diff --git a/rtdata/images/svg/questionmark.svg b/rtdata/images/svg/questionmark.svg new file mode 100644 index 000000000..4c4b59590 --- /dev/null +++ b/rtdata/images/svg/questionmark.svg @@ -0,0 +1,122 @@ + + + + + + + + + + + + image/svg+xml + + + + + Maciej Dworak + + + + + + + + RawTherapee icon. + + + + + + + + + + + + + + ? + + + + diff --git a/rtdata/languages/Catala b/rtdata/languages/Catala index 36666a533..31614c7b3 100644 --- a/rtdata/languages/Catala +++ b/rtdata/languages/Catala @@ -977,6 +977,7 @@ ZOOMPANEL_ZOOMOUT;Allunya\nDrecera: - !GENERAL_AUTO;Automatic !GENERAL_CLOSE;Close !GENERAL_CURRENT;Current +!GENERAL_HELP;Help !GENERAL_OPEN;Open !GENERAL_RESET;Reset !GENERAL_SAVE_AS;Save as... diff --git a/rtdata/languages/Chinese (Simplified) b/rtdata/languages/Chinese (Simplified) index 89a4dd9b4..5be2958e8 100644 --- a/rtdata/languages/Chinese (Simplified) +++ b/rtdata/languages/Chinese (Simplified) @@ -973,6 +973,7 @@ ZOOMPANEL_ZOOMOUT;缩放拉远\n快捷键: - !FILEBROWSER_SHOWUNCOLORHINT;Show images without a color label.\nShortcut: Alt-0 !FILEBROWSER_UNRANK_TOOLTIP;Unrank.\nShortcut: Shift-0 !GENERAL_CURRENT;Current +!GENERAL_HELP;Help !GENERAL_RESET;Reset !GENERAL_SAVE_AS;Save as... !GENERAL_SLIDER;Slider diff --git a/rtdata/languages/Czech b/rtdata/languages/Czech index 0ce34e3ee..25bcf2820 100644 --- a/rtdata/languages/Czech +++ b/rtdata/languages/Czech @@ -2323,6 +2323,7 @@ ZOOMPANEL_ZOOMOUT;Oddálit\nZkratka: - !FILEBROWSER_POPUPREMOVE;Delete permanently !FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version !FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash. +!GENERAL_HELP;Help !HISTORY_MSG_494;Capture Sharpening !HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only !HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch index 9122d5984..592801054 100644 --- a/rtdata/languages/Deutsch +++ b/rtdata/languages/Deutsch @@ -2390,5 +2390,6 @@ ZOOMPANEL_ZOOMOUT;Herauszoomen\nTaste: - ! Untranslated keys follow; remove the ! prefix after an entry is translated. !!!!!!!!!!!!!!!!!!!!!!!!! +!GENERAL_HELP;Help !HISTORY_MSG_PDSHARPEN_CHECKITER;CS - Auto limit iterations !TP_SHARPENING_ITERCHECK;Auto limit iterations diff --git a/rtdata/languages/English (UK) b/rtdata/languages/English (UK) index 1fc07391e..e30425b68 100644 --- a/rtdata/languages/English (UK) +++ b/rtdata/languages/English (UK) @@ -340,6 +340,7 @@ TP_WBALANCE_EQBLUERED_TOOLTIP;Allows to deviate from the normal behaviour of "wh !GENERAL_ENABLE;Enable !GENERAL_ENABLED;Enabled !GENERAL_FILE;File +!GENERAL_HELP;Help !GENERAL_LANDSCAPE;Landscape !GENERAL_NA;n/a !GENERAL_NO;No diff --git a/rtdata/languages/English (US) b/rtdata/languages/English (US) index 63dff83da..a1e0050a8 100644 --- a/rtdata/languages/English (US) +++ b/rtdata/languages/English (US) @@ -226,6 +226,7 @@ !GENERAL_ENABLE;Enable !GENERAL_ENABLED;Enabled !GENERAL_FILE;File +!GENERAL_HELP;Help !GENERAL_LANDSCAPE;Landscape !GENERAL_NA;n/a !GENERAL_NO;No diff --git a/rtdata/languages/Espanol b/rtdata/languages/Espanol index 96bce0cdf..ee8b0d17d 100644 --- a/rtdata/languages/Espanol +++ b/rtdata/languages/Espanol @@ -2321,6 +2321,7 @@ ZOOMPANEL_ZOOMOUT;Reducir Zoom\nTecla de Atajo: - !FILEBROWSER_POPUPREMOVE;Delete permanently !FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version !FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash. +!GENERAL_HELP;Help !HISTORY_MSG_494;Capture Sharpening !HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only !HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 9d1c6a3f7..9ecf43733 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -2266,6 +2266,7 @@ ZOOMPANEL_ZOOMOUT;Zoom Arrière\nRaccourci: - !FILEBROWSER_POPUPREMOVE;Delete permanently !FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version !FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash. +!GENERAL_HELP;Help !HISTORY_MSG_494;Capture Sharpening !HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only !HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative diff --git a/rtdata/languages/Italiano b/rtdata/languages/Italiano index db09b5d3a..0fd256d7c 100644 --- a/rtdata/languages/Italiano +++ b/rtdata/languages/Italiano @@ -1285,6 +1285,7 @@ ZOOMPANEL_ZOOMOUT;Rimpicciolisci.\nScorciatoia: - !GENERAL_APPLY;Apply !GENERAL_ASIMAGE;As Image !GENERAL_CURRENT;Current +!GENERAL_HELP;Help !GENERAL_OPEN;Open !GENERAL_RESET;Reset !GENERAL_SAVE_AS;Save as... diff --git a/rtdata/languages/Japanese b/rtdata/languages/Japanese index 91ef2e931..588a817f2 100644 --- a/rtdata/languages/Japanese +++ b/rtdata/languages/Japanese @@ -8,30 +8,6 @@ #08 2012-12-22 a3novy #09 2013-04-01 a3novy #10 2013-04-19 a3novy -#11 2013-09-10 firefly -#12 2013-10-28 firefly -#13 2014-01-07 firefly -#14 2014-01-15 firefly -#15 2014-02-25 firefly -#16 2014-04-07 firefly -#17 2014-04-08 firefly -#18 2014-05-16 firefly -#19 2014-07-13 firefly -#20 2014-07-24 firefly -#21 2014-09-11 firefly -#22 2014-10-21 firefly -#23 2014-11-07 firefly -#24 2014-11-18 firefly -#25 2015-01-05 firefly -#26 2015-02-17 firefly -#27 2015-02-21 firefly -#28 2015-03-03 firefly -#29 2015-04-20 firefly -#30 2015-05-01 firefly -#31 2015-05-31 firefly -#32 2015-06-13 firefly -#33 2015-07-20 firefly -#34 2015-08-12 firefly ABOUT_TAB_BUILD;バージョン ABOUT_TAB_CREDITS;クレジット @@ -49,7 +25,7 @@ CURVEEDITOR_CURVE;カーブ CURVEEDITOR_CURVES;カーブ CURVEEDITOR_CUSTOM;カスタム CURVEEDITOR_DARKS;ダーク -CURVEEDITOR_EDITPOINT_HINT;ボタンを押すと数値で入出力を編集出来ます\n\n編集したいカーブ上のポイントを右クリックします\n編集を無効にする場合はポイント以外の部分んで右クリックします +CURVEEDITOR_EDITPOINT_HINT;ボタンを押すと数値で入出力を編集出来ます\n\n編集したいカーブ上のポイントを右クリックします\n編集を無効にする場合はポイント以外の部分で右クリックします CURVEEDITOR_HIGHLIGHTS;ハイライト CURVEEDITOR_LIGHTS;ライト CURVEEDITOR_LINEAR;リニア @@ -489,8 +465,8 @@ HISTORY_MSG_205;CAM02 ホット/バッドピクセル HISTORY_MSG_206;CAT02 - 自動で順応 HISTORY_MSG_207;フリンジ低減 - 色相カーブ HISTORY_MSG_208;ブルー/レッド イコライザ -HISTORY_MSG_210;グラデーションフィルター - 角度 -HISTORY_MSG_211;グラデーションフィルター +HISTORY_MSG_210;減光フィルター - 角度 +HISTORY_MSG_211;減光フィルター HISTORY_MSG_212;ビネットフィルター - 強さ HISTORY_MSG_213;ビネットフィルター HISTORY_MSG_214;白黒 @@ -517,10 +493,10 @@ HISTORY_MSG_234;白黒 ‘後の‘カーブのタイプ HISTORY_MSG_235;白黒 チャンネルミキサー 自動 HISTORY_MSG_236;--未使用-- HISTORY_MSG_237;白黒 チャンネルミキサー -HISTORY_MSG_238;グラデーションフィルター フェザー処理 -HISTORY_MSG_239;グラデーションフィルター 強さ -HISTORY_MSG_240;グラデーションフィルター 中央 -HISTORY_MSG_241;ビネットフィルター フェザー処理 +HISTORY_MSG_238;減光フィルター フェザー +HISTORY_MSG_239;減光フィルター 強さ +HISTORY_MSG_240;減光フィルター 中央 +HISTORY_MSG_241;ビネットフィルター フェザー HISTORY_MSG_242;ビネットフィルター 形状 HISTORY_MSG_243;半径 HISTORY_MSG_244;ビネットフィルター 強さ @@ -757,6 +733,7 @@ HISTORY_MSG_490;DRC - 量 HISTORY_MSG_491;ホワイトバランス HISTORY_MSG_492;RGBカーブ HISTORY_MSG_493;L*a*b*調整 +HISTORY_MSG_494;キャプチャーシャープニング HISTORY_MSG_CLAMPOOG;色域外の色を切り取る HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - カラー補正 HISTORY_MSG_COLORTONING_LABREGION_AB;CT - 色の補正 @@ -774,6 +751,7 @@ HISTORY_MSG_COLORTONING_LABREGION_SHOWMASK;CT - マスクの表示 HISTORY_MSG_COLORTONING_LABREGION_SLOPE;CT - スロープ HISTORY_MSG_DEHAZE_DEPTH;霞除去 - 深度 HISTORY_MSG_DEHAZE_ENABLED;霞除去 +HISTORY_MSG_DEHAZE_LUMINANCE;霞除去 - 輝度のみ HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP;霞除去 - 深度マップの表示 HISTORY_MSG_DEHAZE_STRENGTH;霞除去 - 強さ HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;デュアルデモザイク - 自動しきい値 @@ -794,6 +772,13 @@ HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;ローカルコントラスト - 明るい HISTORY_MSG_LOCALCONTRAST_RADIUS;ローカルコントラスト - 半径 HISTORY_MSG_METADATA_MODE;メタデータ コピーモード HISTORY_MSG_MICROCONTRAST_CONTRAST;マイクロコントラスト - コントラストのしきい値 +HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;CS - しきい値の自動設定 +HISTORY_MSG_PDSHARPEN_AUTO_RADIUS;CS - シグマの自動設定 +HISTORY_MSG_PDSHARPEN_CHECKITER;CS - 繰り返しの自動制限 +HISTORY_MSG_PDSHARPEN_CONTRAST;CS - コントラストのしきい値 +HISTORY_MSG_PDSHARPEN_ITERATIONS;CS - 繰り返し +HISTORY_MSG_PDSHARPEN_RADIUS;CS - シグマ +HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;CS - 周辺のシグマを増やす HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - 振れに対するデモザイクの方式 HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;ラインノイズフィルタの方向 HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;PDAFラインフィルタ @@ -960,8 +945,8 @@ MAIN_TOOLTIP_BACKCOLOR2;プレビューの背景色を指定します: 中間のグレー\nショートカット: 9 MAIN_TOOLTIP_BEFOREAFTERLOCK;固定 / 固定解除 - 補正前 の表示設定\n\n固定: 補正前をそのまま表示し変更されません\n複数のツールの累積効果を評価するのに役立ちます\nさらに、比較は履歴上のどこからでも行うことができます\n\n固定解除: 現在使用のツールの効果が 補正後 に表示され、その1段階前が 補正前 に表示されます MAIN_TOOLTIP_HIDEHP;左パネル 表示/非表示 (履歴含む)\nショートカット: l -MAIN_TOOLTIP_INDCLIPPEDH;ハイライト・クリッピング領域の表示\nショートカット: > -MAIN_TOOLTIP_INDCLIPPEDS;シャドウ・クリッピング領域の表示\nショートカット: < +MAIN_TOOLTIP_INDCLIPPEDH;ハイライト・クリッピング領域の表示\nショートカット: < +MAIN_TOOLTIP_INDCLIPPEDS;シャドウ・クリッピング領域の表示\nショートカット: > MAIN_TOOLTIP_PREVIEWB;ブルー チャンネル表示\nショートカット: b MAIN_TOOLTIP_PREVIEWFOCUSMASK;フォーカス・マスク表示\nショートカット: Shift-f\n\n浅い被写界深度、低ノイズ、高ズームの画像の場合は、より正確に\n\nノイズの多い画像に対しては、検出精度を向上させるため10から30%縮小して評価します\n\nフォーカス・マスクをオンにすると表示に時間が掛かります MAIN_TOOLTIP_PREVIEWG;グリーン チャンネル表示\nショートカット: g @@ -1023,7 +1008,7 @@ PARTIALPASTE_FLATFIELDBLURRADIUS;フラットフィールド ぼかし半径 PARTIALPASTE_FLATFIELDBLURTYPE;フラットフィールド ぼかしタイプ PARTIALPASTE_FLATFIELDCLIPCONTROL;フラットフィールド クリップコントロール PARTIALPASTE_FLATFIELDFILE;フラットフィールド ファイル -PARTIALPASTE_GRADIENT;グラデーションフィルター +PARTIALPASTE_GRADIENT;減光フィルター PARTIALPASTE_HSVEQUALIZER;HSV イコライザ PARTIALPASTE_ICMSETTINGS;ICM 設定 PARTIALPASTE_IMPULSEDENOISE;インパルス・ノイズ低減 @@ -1562,6 +1547,7 @@ TP_DEFRINGE_RADIUS;半径 TP_DEFRINGE_THRESHOLD;しきい値 TP_DEHAZE_DEPTH;深度 TP_DEHAZE_LABEL;霞除去 +TP_DEHAZE_LUMINANCE;輝度のみ TP_DEHAZE_SHOW_DEPTH_MAP;深度マップの表示 TP_DEHAZE_STRENGTH;強さ TP_DIRPYRDENOISE_CHROMINANCE_AMZ;自動(多分割方式) @@ -1672,9 +1658,9 @@ TP_EXPOS_BLACKPOINT_LABEL;raw ブラック・ポイント TP_EXPOS_WHITEPOINT_LABEL;raw ホワイト・ポイント TP_FILMNEGATIVE_BLUE;ブルーの比率 TP_FILMNEGATIVE_GREEN;参考指数(コントラスト) -TP_FILMNEGATIVE_GUESS_TOOLTIP;Automatically set the red and blue ratios by picking two patches which had a neutral hue (no color) in the original scene. The patches should differ in brightness. Set the white balance afterwards. +TP_FILMNEGATIVE_GUESS_TOOLTIP;原画像の中で色相がニュートラルな部分2か所をピックすることでレッドとブルーの比率を自動で設定します。明るさが異なる2か所をピックします。その後、ホワイトバランスを設定します。 TP_FILMNEGATIVE_LABEL;ネガフィルム -TP_FILMNEGATIVE_PICK;Pick neutral spots +TP_FILMNEGATIVE_PICK;ニュートラルなポイントをピック TP_FILMNEGATIVE_RED;レッドの比率 TP_FILMSIMULATION_LABEL;フィルムシミュレーション TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapeeはフィルムシミュレーション機能に使う画像をHald CLUTフォルダーの中から探すよう設計されています(プログラムに組み込むにはフォルダーが大き過ぎるため)。\n変更するには、環境設定 > 画像処理 > フィルムシミュレーションと進み\nどのフォルダーが使われているか確認します。機能を利用する場合は、Hald CLUTだけが入っているフォルダーを指定するか、 この機能を使わない場合はそのフォルダーを空にしておきます。\n\n詳しくはRawPediaを参照して下さい。\n\nフィルム画像のスキャンを止めますか? @@ -1698,9 +1684,9 @@ TP_GRADIENT_CENTER_Y;中央 Y軸 TP_GRADIENT_CENTER_Y_TOOLTIP;アンカーポイントの位置 y軸: -100=上端, 0=中央, +100=下端 TP_GRADIENT_DEGREE;角度 TP_GRADIENT_DEGREE_TOOLTIP;回転角度の度数 -TP_GRADIENT_FEATHER;フェザー処理 -TP_GRADIENT_FEATHER_TOOLTIP;対角線に対するグラデーションの幅の割合 -TP_GRADIENT_LABEL;グラデーションフィルター +TP_GRADIENT_FEATHER;フェザー +TP_GRADIENT_FEATHER_TOOLTIP;対角線に対する減光の幅の割合 +TP_GRADIENT_LABEL;減光フィルター TP_GRADIENT_STRENGTH;強さ TP_GRADIENT_STRENGTH_TOOLTIP;終点位置でのフィルターの強さ TP_HLREC_BLEND;ブレンド @@ -1817,13 +1803,14 @@ TP_METADATA_STRIP;メタデータを全て取り除く TP_METADATA_TUNNEL;変更なしでコピー TP_NEUTRAL;リセット TP_NEUTRAL_TIP;露光量補正のスライダー値をニュートラルにリセットします。\n自動露光補正の調整値ついても同様にリセットされます -TP_PCVIGNETTE_FEATHER;フェザー処理 -TP_PCVIGNETTE_FEATHER_TOOLTIP;フェザー処理: 0=四隅だけ、50=中央までの半分、100=中央まで +TP_PCVIGNETTE_FEATHER;フェザー +TP_PCVIGNETTE_FEATHER_TOOLTIP;フェザー: 0=四隅だけ、50=中央までの半分、100=中央まで TP_PCVIGNETTE_LABEL;ビネットフィルター TP_PCVIGNETTE_ROUNDNESS;フィルター形状 TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;形状: 0=長方形、50=楕円形、100=円形 TP_PCVIGNETTE_STRENGTH;強さ TP_PCVIGNETTE_STRENGTH_TOOLTIP;終点位置でのフィルターの強さ(四隅) +TP_PDSHARPENING_LABEL;キャプチャーシャープニング TP_PERSPECTIVE_HORIZONTAL;水平 TP_PERSPECTIVE_LABEL;パースペクティブ TP_PERSPECTIVE_VERTICAL;垂直 @@ -2054,10 +2041,12 @@ TP_SHARPENING_EDRADIUS;半径 TP_SHARPENING_EDTOLERANCE;エッジ許容 TP_SHARPENING_HALOCONTROL;ハロ抑制 TP_SHARPENING_HCAMOUNT;適用量 +TP_SHARPENING_ITERCHECK;繰り返しの自動制限 TP_SHARPENING_LABEL;シャープニング TP_SHARPENING_METHOD;方式 TP_SHARPENING_ONLYEDGES;エッジのみシャープニング TP_SHARPENING_RADIUS;半径 +TP_SHARPENING_RADIUS_BOOST;周辺のシグマを増やす TP_SHARPENING_RLD;RL デコンボリューション TP_SHARPENING_RLD_AMOUNT;適用量 TP_SHARPENING_RLD_DAMPING;減衰 @@ -2311,6 +2300,7 @@ TP_WBALANCE_TUNGSTEN;タングステン TP_WBALANCE_WATER1;水中 1 TP_WBALANCE_WATER2;水中 2 TP_WBALANCE_WATER_HEADER;水中 +The last update by firefly 2019-12-21 ZOOMPANEL_100;(100%) ZOOMPANEL_NEWCROPWINDOW;新規ディテール ウィンドウを開く ZOOMPANEL_ZOOM100;100%にズーム\nショートカット: z @@ -2323,16 +2313,4 @@ ZOOMPANEL_ZOOMOUT;ズームアウト\nショートカット: - ! Untranslated keys follow; remove the ! prefix after an entry is translated. !!!!!!!!!!!!!!!!!!!!!!!!! -!HISTORY_MSG_494;Capture Sharpening -!HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only -!HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;CS - Auto threshold -!HISTORY_MSG_PDSHARPEN_AUTO_RADIUS;CS - Auto radius -!HISTORY_MSG_PDSHARPEN_CHECKITER;CS - Auto limit iterations -!HISTORY_MSG_PDSHARPEN_CONTRAST;CS - Contrast threshold -!HISTORY_MSG_PDSHARPEN_ITERATIONS;CS - Iterations -!HISTORY_MSG_PDSHARPEN_RADIUS;CS - Radius -!HISTORY_MSG_PDSHARPEN_RADIUS_BOOST;CS - Corner radius boost -!TP_DEHAZE_LUMINANCE;Luminance only -!TP_PDSHARPENING_LABEL;Capture Sharpening -!TP_SHARPENING_ITERCHECK;Auto limit iterations -!TP_SHARPENING_RADIUS_BOOST;Corner radius boost +!GENERAL_HELP;Help diff --git a/rtdata/languages/Magyar b/rtdata/languages/Magyar index 43a4ae1e1..4b6f2811b 100644 --- a/rtdata/languages/Magyar +++ b/rtdata/languages/Magyar @@ -908,6 +908,7 @@ ZOOMPANEL_ZOOMOUT;Kicsinyítés - !GENERAL_AUTO;Automatic !GENERAL_CLOSE;Close !GENERAL_CURRENT;Current +!GENERAL_HELP;Help !GENERAL_OPEN;Open !GENERAL_RESET;Reset !GENERAL_SAVE_AS;Save as... diff --git a/rtdata/languages/Nederlands b/rtdata/languages/Nederlands index 07e40256f..c230323f5 100644 --- a/rtdata/languages/Nederlands +++ b/rtdata/languages/Nederlands @@ -1982,6 +1982,7 @@ ZOOMPANEL_ZOOMOUT;Zoom uit\nSneltoets: - !FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version !FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash. !GENERAL_CURRENT;Current +!GENERAL_HELP;Help !GENERAL_RESET;Reset !GENERAL_SAVE_AS;Save as... !GENERAL_SLIDER;Slider diff --git a/rtdata/languages/Polish b/rtdata/languages/Polish index c923c3bad..4e5d950fc 100644 --- a/rtdata/languages/Polish +++ b/rtdata/languages/Polish @@ -1407,6 +1407,7 @@ ZOOMPANEL_ZOOMOUT;Oddal\nSkrót: - !GENERAL_APPLY;Apply !GENERAL_ASIMAGE;As Image !GENERAL_CURRENT;Current +!GENERAL_HELP;Help !GENERAL_OPEN;Open !GENERAL_RESET;Reset !GENERAL_SAVE_AS;Save as... diff --git a/rtdata/languages/Portugues b/rtdata/languages/Portugues index efe3214f8..789d26cd6 100644 --- a/rtdata/languages/Portugues +++ b/rtdata/languages/Portugues @@ -2264,6 +2264,7 @@ ZOOMPANEL_ZOOMOUT;Afastar\nAtalho: - !FILEBROWSER_POPUPREMOVE;Delete permanently !FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version !FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash. +!GENERAL_HELP;Help !HISTORY_MSG_494;Capture Sharpening !HISTORY_MSG_DEHAZE_LUMINANCE;Dehaze - Luminance only !HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative diff --git a/rtdata/languages/Portugues (Brasil) b/rtdata/languages/Portugues (Brasil) index e6adf3bc4..d619356a9 100644 --- a/rtdata/languages/Portugues (Brasil) +++ b/rtdata/languages/Portugues (Brasil) @@ -2269,6 +2269,7 @@ ZOOMPANEL_ZOOMOUT;Menos Zoom\nAtalho: - !!!!!!!!!!!!!!!!!!!!!!!!! !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to open specified path, reload folder and apply "find" keywords. +!GENERAL_HELP;Help !HISTORY_MSG_494;Capture Sharpening !HISTORY_MSG_COLORTONING_LABREGION_OFFSET;CT - region offset !HISTORY_MSG_COLORTONING_LABREGION_POWER;CT - region power diff --git a/rtdata/languages/Russian b/rtdata/languages/Russian index a4e501a77..4246ecbb6 100644 --- a/rtdata/languages/Russian +++ b/rtdata/languages/Russian @@ -1475,6 +1475,7 @@ ZOOMPANEL_ZOOMOUT;Отдалить\nГорячая клавиша: - !FILEBROWSER_SHOWORIGINALHINT;Show only original images.\n\nWhen several images exist with the same filename but different extensions, the one considered original is the one whose extension is nearest the top of the parsed extensions list in Preferences > File Browser > Parsed Extensions. !FILECHOOSER_FILTER_PP;Processing profiles !FILECHOOSER_FILTER_SAME;Same format as current photo +!GENERAL_HELP;Help !GIMP_PLUGIN_INFO;Welcome to the RawTherapee GIMP plugin!\nOnce you are done editing, simply close the main RawTherapee window and the image will be automatically imported in GIMP. !HISTOGRAM_TOOLTIP_MODE;Toggle between linear, log-linear and log-log scaling of the histogram. !HISTORY_MSG_235;B&W - CM - Auto diff --git a/rtdata/languages/Serbian (Cyrilic Characters) b/rtdata/languages/Serbian (Cyrilic Characters) index 9ec7c998b..7fd0ca378 100644 --- a/rtdata/languages/Serbian (Cyrilic Characters) +++ b/rtdata/languages/Serbian (Cyrilic Characters) @@ -1257,6 +1257,7 @@ ZOOMPANEL_ZOOMOUT;Умањује приказ слике - !GENERAL_APPLY;Apply !GENERAL_ASIMAGE;As Image !GENERAL_CURRENT;Current +!GENERAL_HELP;Help !GENERAL_OPEN;Open !GENERAL_RESET;Reset !GENERAL_SAVE_AS;Save as... diff --git a/rtdata/languages/Slovenian b/rtdata/languages/Slovenian index b015cb6f1..0afaa83e9 100644 --- a/rtdata/languages/Slovenian +++ b/rtdata/languages/Slovenian @@ -2306,5 +2306,6 @@ ZOOMPANEL_ZOOMOUT;Zoom Out\nBližnjica: - ! Untranslated keys follow; remove the ! prefix after an entry is translated. !!!!!!!!!!!!!!!!!!!!!!!!! +!GENERAL_HELP;Help !HISTORY_MSG_PDSHARPEN_CHECKITER;CS - Auto limit iterations !TP_SHARPENING_ITERCHECK;Auto limit iterations diff --git a/rtdata/languages/Swedish b/rtdata/languages/Swedish index 7861f2276..6dbea54d8 100644 --- a/rtdata/languages/Swedish +++ b/rtdata/languages/Swedish @@ -1772,6 +1772,7 @@ ZOOMPANEL_ZOOMOUT;Förminska.\nKortkommando: - !FILEBROWSER_RESETDEFAULTPROFILE;Reset to default !FILEBROWSER_SHOWNOTTRASHHINT;Show only images not in trash. !GENERAL_CURRENT;Current +!GENERAL_HELP;Help !GENERAL_RESET;Reset !GENERAL_SAVE_AS;Save as... !GENERAL_SLIDER;Slider diff --git a/rtdata/languages/default b/rtdata/languages/default index 95b8980b3..e6bbe8957 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -225,6 +225,7 @@ GENERAL_DISABLED;Disabled GENERAL_ENABLE;Enable GENERAL_ENABLED;Enabled GENERAL_FILE;File +GENERAL_HELP;Help GENERAL_LANDSCAPE;Landscape GENERAL_NA;n/a GENERAL_NO;No @@ -794,6 +795,7 @@ HISTORY_MSG_SH_COLORSPACE;S/H - Colorspace HISTORY_MSG_SOFTLIGHT_ENABLED;Soft light HISTORY_MSG_SOFTLIGHT_STRENGTH;Soft light - Strength HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - Anchor +HISTORY_MSG_TRANS_Method;Geometry - Method HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1782,6 +1784,8 @@ TP_LABCURVE_RSTPRO_TOOLTIP;Works on the Chromaticity slider and the CC curve. TP_LENSGEOM_AUTOCROP;Auto-Crop TP_LENSGEOM_FILL;Auto-fill TP_LENSGEOM_LABEL;Lens / Geometry +TP_LENSGEOM_LIN;Linear +TP_LENSGEOM_LOG;Logarithmic TP_LENSPROFILE_CORRECTION_AUTOMATCH;Automatically selected TP_LENSPROFILE_CORRECTION_LCPFILE;LCP file TP_LENSPROFILE_CORRECTION_MANUAL;Manually selected diff --git a/rtengine/array2D.h b/rtengine/array2D.h index 208dab1aa..de6381aeb 100644 --- a/rtengine/array2D.h +++ b/rtengine/array2D.h @@ -188,6 +188,16 @@ public: } } + void fill(const T val, bool multiThread = false) + { +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for (int i = 0; i < x * y; ++i) { + data[i] = val; + } + } + void free() { if ((owner) && (data)) { diff --git a/rtengine/cJSON.h b/rtengine/cJSON.h index 786dd2e0e..49fd67b72 100644 --- a/rtengine/cJSON.h +++ b/rtengine/cJSON.h @@ -195,7 +195,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); /* Create a string where valuestring references a string so * it will not be freed by cJSON_Delete */ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); -/* Create an object/arrray that only references it's elements so +/* Create an object/array that only references it's elements so * they will not be freed by cJSON_Delete */ CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index e8f7b1cbf..d136d6a21 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -253,7 +253,7 @@ CameraConst::parseEntry(void *cJSON_, const char *make_model) } if (i % 4 != 0) { - fprintf(stderr, "\"masked_areas\" array length must be divisable by 4\n"); + fprintf(stderr, "\"masked_areas\" array length must be divisible by 4\n"); goto parse_error; } } diff --git a/rtengine/capturesharpening.cc b/rtengine/capturesharpening.cc index d2bb6b351..072935dc2 100644 --- a/rtengine/capturesharpening.cc +++ b/rtengine/capturesharpening.cc @@ -99,31 +99,7 @@ void compute3x3kernel(float sigma, float kernel[3][3]) { } } -inline void initTile(float** dst, const int tileSize) -{ - - // first rows - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < tileSize; ++j) { - dst[i][j] = 1.f; - } - } - - // left and right border - for (int i = 3; i < tileSize - 3; ++i) { - dst[i][0] = dst[i][1] = dst[i][2] = 1.f; - dst[i][tileSize - 3] = dst[i][tileSize - 2] = dst[i][tileSize - 1] = 1.f; - } - - // last rows - for (int i = tileSize - 3 ; i < tileSize; ++i) { - for (int j = 0; j < tileSize; ++j) { - dst[i][j] = 1.f; - } - } -} - -inline void gauss3x3div (float** RESTRICT src, float** RESTRICT dst, float** RESTRICT divBuffer, const int tileSize, const float kernel[3][3]) +void gauss3x3div (float** RESTRICT src, float** RESTRICT dst, float** RESTRICT divBuffer, const int tileSize, const float kernel[3][3]) { const float c11 = kernel[0][0]; @@ -131,6 +107,11 @@ inline void gauss3x3div (float** RESTRICT src, float** RESTRICT dst, float** RES const float c00 = kernel[1][1]; for (int i = 1; i < tileSize - 1; i++) { +#if defined(__clang__) + #pragma clang loop vectorize(assume_safety) +#elif defined(__GNUC__) + #pragma GCC ivdep +#endif for (int j = 1; j < tileSize - 1; j++) { const float val = c11 * (src[i - 1][j - 1] + src[i - 1][j + 1] + src[i + 1][j - 1] + src[i + 1][j + 1]) + c10 * (src[i - 1][j] + src[i][j - 1] + src[i][j + 1] + src[i + 1][j]) + @@ -140,7 +121,7 @@ inline void gauss3x3div (float** RESTRICT src, float** RESTRICT dst, float** RES } } -inline void gauss5x5div (float** RESTRICT src, float** RESTRICT dst, float** RESTRICT divBuffer, const int tileSize, const float kernel[5][5]) +void gauss5x5div (float** RESTRICT src, float** RESTRICT dst, float** RESTRICT divBuffer, const int tileSize, const float kernel[5][5]) { const float c21 = kernel[0][1]; @@ -151,6 +132,11 @@ inline void gauss5x5div (float** RESTRICT src, float** RESTRICT dst, float** RES for (int i = 2; i < tileSize - 2; ++i) { // I tried hand written SSE code but gcc vectorizes better +#if defined(__clang__) + #pragma clang loop vectorize(assume_safety) +#elif defined(__GNUC__) + #pragma GCC ivdep +#endif for (int j = 2; j < tileSize - 2; ++j) { const float val = c21 * ((src[i - 2][j - 1] + src[i - 2][j + 1]) + (src[i - 1][j - 2] + src[i - 1][j + 2]) + (src[i + 1][j - 2] + src[i + 1][j + 2]) + (src[i + 2][j - 1] + src[i + 2][j + 1])) + c20 * (src[i - 2][j] + src[i][j - 2] + src[i][j + 2] + src[i + 2][j]) + @@ -163,7 +149,7 @@ inline void gauss5x5div (float** RESTRICT src, float** RESTRICT dst, float** RES } } -inline void gauss7x7div(float** RESTRICT src, float** RESTRICT dst, float** RESTRICT divBuffer, const int tileSize, const float kernel[7][7]) +void gauss7x7div(float** RESTRICT src, float** RESTRICT dst, float** RESTRICT divBuffer, const int tileSize, const float kernel[7][7]) { const float c31 = kernel[0][2]; @@ -177,6 +163,11 @@ inline void gauss7x7div(float** RESTRICT src, float** RESTRICT dst, float** REST for (int i = 3; i < tileSize - 3; ++i) { // I tried hand written SSE code but gcc vectorizes better +#if defined(__clang__) + #pragma clang loop vectorize(assume_safety) +#elif defined(__GNUC__) + #pragma GCC ivdep +#endif for (int j = 3; j < tileSize - 3; ++j) { const float val = c31 * ((src[i - 3][j - 1] + src[i - 3][j + 1]) + (src[i - 1][j - 3] + src[i - 1][j + 3]) + (src[i + 1][j - 3] + src[i + 1][j + 3]) + (src[i + 3][j - 1] + src[i + 3][j + 1])) + c30 * (src[i - 3][j] + src[i][j - 3] + src[i][j + 3] + src[i + 3][j]) + @@ -192,13 +183,18 @@ inline void gauss7x7div(float** RESTRICT src, float** RESTRICT dst, float** REST } } -inline void gauss3x3mult(float** RESTRICT src, float** RESTRICT dst, const int tileSize, const float kernel[3][3]) +void gauss3x3mult(float** RESTRICT src, float** RESTRICT dst, const int tileSize, const float kernel[3][3]) { const float c11 = kernel[0][0]; const float c10 = kernel[0][1]; const float c00 = kernel[1][1]; for (int i = 1; i < tileSize - 1; i++) { +#if defined(__clang__) + #pragma clang loop vectorize(assume_safety) +#elif defined(__GNUC__) + #pragma GCC ivdep +#endif for (int j = 1; j < tileSize - 1; j++) { const float val = c11 * (src[i - 1][j - 1] + src[i - 1][j + 1] + src[i + 1][j - 1] + src[i + 1][j + 1]) + c10 * (src[i - 1][j] + src[i][j - 1] + src[i][j + 1] + src[i + 1][j]) + @@ -209,7 +205,7 @@ inline void gauss3x3mult(float** RESTRICT src, float** RESTRICT dst, const int t } -inline void gauss5x5mult (float** RESTRICT src, float** RESTRICT dst, const int tileSize, const float kernel[5][5]) +void gauss5x5mult (float** RESTRICT src, float** RESTRICT dst, const int tileSize, const float kernel[5][5]) { const float c21 = kernel[0][1]; @@ -220,6 +216,11 @@ inline void gauss5x5mult (float** RESTRICT src, float** RESTRICT dst, const int for (int i = 2; i < tileSize - 2; ++i) { // I tried hand written SSE code but gcc vectorizes better +#if defined(__clang__) + #pragma clang loop vectorize(assume_safety) +#elif defined(__GNUC__) + #pragma GCC ivdep +#endif for (int j = 2; j < tileSize - 2; ++j) { const float val = c21 * ((src[i - 2][j - 1] + src[i - 2][j + 1]) + (src[i - 1][j - 2] + src[i - 1][j + 2]) + (src[i + 1][j - 2] + src[i + 1][j + 2]) + (src[i + 2][j - 1] + src[i + 2][j + 1])) + c20 * (src[i - 2][j] + src[i][j - 2] + src[i][j + 2] + src[i + 2][j]) + @@ -232,7 +233,7 @@ inline void gauss5x5mult (float** RESTRICT src, float** RESTRICT dst, const int } } -inline void gauss7x7mult(float** RESTRICT src, float** RESTRICT dst, const int tileSize, const float kernel[7][7]) +void gauss7x7mult(float** RESTRICT src, float** RESTRICT dst, const int tileSize, const float kernel[7][7]) { const float c31 = kernel[0][2]; @@ -246,6 +247,11 @@ inline void gauss7x7mult(float** RESTRICT src, float** RESTRICT dst, const int t for (int i = 3; i < tileSize - 3; ++i) { // I tried hand written SSE code but gcc vectorizes better +#if defined(__clang__) + #pragma clang loop vectorize(assume_safety) +#elif defined(__GNUC__) + #pragma GCC ivdep +#endif for (int j = 3; j < tileSize - 3; ++j) { const float val = c31 * ((src[i - 3][j - 1] + src[i - 3][j + 1]) + (src[i - 1][j - 3] + src[i - 1][j + 3]) + (src[i + 1][j - 3] + src[i + 1][j + 3]) + (src[i + 3][j - 1] + src[i + 3][j + 1])) + c30 * (src[i - 3][j] + src[i][j - 3] + src[i][j + 3] + src[i + 3][j]) + @@ -495,28 +501,25 @@ float calcRadiusXtrans(const float * const *rawData, int W, int H, float lowerLi bool checkForStop(float** tmpIThr, float** iterCheck, int fullTileSize, int border) { - bool stopped = false; - for (int ii = border; !stopped && ii < fullTileSize - border; ++ii) { + for (int ii = border; ii < fullTileSize - border; ++ii) { #ifdef __SSE2__ for (int jj = border; jj < fullTileSize - border; jj += 4) { - if (_mm_movemask_ps((vfloat)vmaskf_lt(LVFU(tmpIThr[ii][jj]), LVFU(iterCheck[ii - border][jj - border])))) { - stopped = true; - break; + if (UNLIKELY(_mm_movemask_ps((vfloat)vmaskf_lt(LVFU(tmpIThr[ii][jj]), LVFU(iterCheck[ii - border][jj - border]))))) { + return true; } } #else for (int jj = border; jj < fullTileSize - border; ++jj) { if (tmpIThr[ii][jj] < iterCheck[ii - border][jj - border]) { - stopped = true; - break; + return true; } } #endif } - return stopped; + return false; } -void CaptureDeconvSharpening (float ** clipmask, float** luminance, float** oldLuminance, const float * const * blend, int W, int H, double sigma, double sigmaCornerOffset, int iterations, bool checkIterStop, rtengine::ProgressListener* plistener, double startVal, double endVal) +void CaptureDeconvSharpening (float** luminance, const float* const * oldLuminance, const float * const * blend, int W, int H, double sigma, double sigmaCornerOffset, int iterations, bool checkIterStop, rtengine::ProgressListener* plistener, double startVal, double endVal) { BENCHFUN const bool is5x5 = (sigma <= 0.84 && sigmaCornerOffset == 0.0); @@ -541,6 +544,7 @@ BENCHFUN double progress = startVal; const double progressStep = (endVal - startVal) * rtengine::SQR(tileSize) / (W * H); + constexpr float minBlend = 0.01f; #ifdef _OPENMP @@ -550,9 +554,9 @@ BENCHFUN int progresscounter = 0; array2D tmpIThr(fullTileSize, fullTileSize); array2D tmpThr(fullTileSize, fullTileSize); + tmpThr.fill(1.f); array2D lumThr(fullTileSize, fullTileSize); array2D iterCheck(tileSize, tileSize); - initTile(tmpThr, fullTileSize); #ifdef _OPENMP #pragma omp for schedule(dynamic,16) collapse(2) #endif @@ -567,14 +571,14 @@ BENCHFUN if (checkIterStop) { for (int k = 0, ii = endOfCol ? H - fullTileSize + border : i; k < tileSize; ++k, ++ii) { for (int l = 0, jj = endOfRow ? W - fullTileSize + border : j; l < tileSize; ++l, ++jj) { - iterCheck[k][l] = oldLuminance[ii][jj] * clipmask[ii][jj] * 0.5f; - maxVal = std::max(maxVal, clipmask[ii][jj]); + iterCheck[k][l] = oldLuminance[ii][jj] * blend[ii][jj] * 0.5f; + maxVal = std::max(maxVal, blend[ii][jj]); } } } else { for (int k = 0, ii = endOfCol ? H - fullTileSize + border : i; k < tileSize; ++k, ++ii) { for (int l = 0, jj = endOfRow ? W - fullTileSize + border : j; l < tileSize; ++l, ++jj) { - maxVal = std::max(maxVal, clipmask[ii][jj]); + maxVal = std::max(maxVal, blend[ii][jj]); } } } @@ -593,14 +597,14 @@ BENCHFUN if (checkIterStop) { for (int ii = 0; ii < tileSize; ++ii) { for (int jj = 0; jj < tileSize; ++jj) { - iterCheck[ii][jj] = oldLuminance[i + ii][j + jj] * clipmask[i + ii][j + jj] * 0.5f; - maxVal = std::max(maxVal, clipmask[i + ii][j + jj]); + iterCheck[ii][jj] = oldLuminance[i + ii][j + jj] * blend[i + ii][j + jj] * 0.5f; + maxVal = std::max(maxVal, blend[i + ii][j + jj]); } } } else { for (int ii = 0; ii < tileSize; ++ii) { for (int jj = 0; jj < tileSize; ++jj) { - maxVal = std::max(maxVal, clipmask[i + ii][j + jj]); + maxVal = std::max(maxVal, blend[i + ii][j + jj]); } } } @@ -615,23 +619,22 @@ BENCHFUN } } } - bool stopped = false; if (is3x3) { - for (int k = 0; k < iterations && !stopped; ++k) { + for (int k = 0; k < iterations; ++k) { // apply 3x3 gaussian blur and divide luminance by result of gaussian blur gauss3x3div(tmpIThr, tmpThr, lumThr, fullTileSize, kernel3); gauss3x3mult(tmpThr, tmpIThr, fullTileSize, kernel3); - if (checkIterStop) { - stopped = checkForStop(tmpIThr, iterCheck, fullTileSize, border); + if (checkIterStop && k < iterations - 1 && checkForStop(tmpIThr, iterCheck, fullTileSize, border)) { + break; } } } else if (is5x5) { - for (int k = 0; k < iterations && !stopped; ++k) { + for (int k = 0; k < iterations; ++k) { // apply 5x5 gaussian blur and divide luminance by result of gaussian blur gauss5x5div(tmpIThr, tmpThr, lumThr, fullTileSize, kernel5); gauss5x5mult(tmpThr, tmpIThr, fullTileSize, kernel5); - if (checkIterStop) { - stopped = checkForStop(tmpIThr, iterCheck, fullTileSize, border); + if (checkIterStop && k < iterations - 1 && checkForStop(tmpIThr, iterCheck, fullTileSize, border)) { + break; } } } else { @@ -642,34 +645,34 @@ BENCHFUN if (sigmaTile > 0.84) { // have to use 7x7 kernel float lkernel7[7][7]; compute7x7kernel(static_cast(sigma) + distanceFactor * distance, lkernel7); - for (int k = 0; k < iterations && !stopped; ++k) { + for (int k = 0; k < iterations; ++k) { // apply 7x7 gaussian blur and divide luminance by result of gaussian blur gauss7x7div(tmpIThr, tmpThr, lumThr, fullTileSize, lkernel7); gauss7x7mult(tmpThr, tmpIThr, fullTileSize, lkernel7); - if (checkIterStop) { - stopped = checkForStop(tmpIThr, iterCheck, fullTileSize, border); + if (checkIterStop && k < iterations - 1 && checkForStop(tmpIThr, iterCheck, fullTileSize, border)) { + break; } } } else { // can use 5x5 kernel - float lkernel7[5][5]; - compute5x5kernel(static_cast(sigma) + distanceFactor * distance, lkernel7); - for (int k = 0; k < iterations && !stopped; ++k) { + float lkernel5[5][5]; + compute5x5kernel(static_cast(sigma) + distanceFactor * distance, lkernel5); + for (int k = 0; k < iterations; ++k) { // apply 7x7 gaussian blur and divide luminance by result of gaussian blur - gauss5x5div(tmpIThr, tmpThr, lumThr, fullTileSize, lkernel7); - gauss5x5mult(tmpThr, tmpIThr, fullTileSize, lkernel7); - if (checkIterStop) { - stopped = checkForStop(tmpIThr, iterCheck, fullTileSize, border); + gauss5x5div(tmpIThr, tmpThr, lumThr, fullTileSize, lkernel5); + gauss5x5mult(tmpThr, tmpIThr, fullTileSize, lkernel5); + if (checkIterStop && k < iterations - 1 && checkForStop(tmpIThr, iterCheck, fullTileSize, border)) { + break; } } } } } else { - for (int k = 0; k < iterations && !stopped; ++k) { + for (int k = 0; k < iterations; ++k) { // apply 7x7 gaussian blur and divide luminance by result of gaussian blur gauss7x7div(tmpIThr, tmpThr, lumThr, fullTileSize, kernel7); gauss7x7mult(tmpThr, tmpIThr, fullTileSize, kernel7); - if (checkIterStop) { - stopped = checkForStop(tmpIThr, iterCheck, fullTileSize, border); + if (checkIterStop && k < iterations - 1 && checkForStop(tmpIThr, iterCheck, fullTileSize, border)) { + break; } } } @@ -678,23 +681,23 @@ BENCHFUN // special handling for small tiles at end of row or column for (int k = border, ii = endOfCol ? H - fullTileSize : i - border; k < fullTileSize - border; ++k) { for (int l = border, jj = endOfRow ? W - fullTileSize : j - border; l < fullTileSize - border; ++l) { - luminance[ii + k][jj + l] = rtengine::intp(blend[ii + k][jj + l], std::max(tmpIThr[k][l], 0.0f), luminance[ii + k][jj + l]); + luminance[ii + k][jj + l] = rtengine::intp(blend[ii + k][jj + l], tmpIThr[k][l], luminance[ii + k][jj + l]); } } } else { for (int ii = border; ii < fullTileSize - border; ++ii) { for (int jj = border; jj < fullTileSize - border; ++jj) { - luminance[i + ii - border][j + jj - border] = rtengine::intp(blend[i + ii - border][j + jj - border], std::max(tmpIThr[ii][jj], 0.0f), luminance[i + ii - border][j + jj - border]); + luminance[i + ii - border][j + jj - border] = rtengine::intp(blend[i + ii - border][j + jj - border], tmpIThr[ii][jj], luminance[i + ii - border][j + jj - border]); } } } if (plistener) { - if (++progresscounter % 16 == 0) { + if (++progresscounter % 32 == 0) { #ifdef _OPENMP #pragma omp critical(csprogress) #endif { - progress += 16.0 * progressStep; + progress += 32.0 * progressStep; progress = rtengine::min(progress, endVal); plistener->setProgress(progress); } @@ -721,6 +724,7 @@ void RawImageSource::captureSharpening(const procparams::CaptureSharpeningParams plistener->setProgress(0.0); } BENCHFUN + constexpr float xyz_rgb[3][3] = { // XYZ from RGB { 0.412453, 0.357580, 0.180423 }, { 0.212671, 0.715160, 0.072169 }, @@ -799,8 +803,7 @@ BENCHFUN plistener->setProgress(0.1); } - array2D& blend = red; // red will be overridden anyway => we can use its buffer to store the blend mask - buildBlendMask(L, blend, W, H, contrast, 1.f, sharpeningParams.autoContrast, clipMask); + buildBlendMask(L, clipMask, W, H, contrast, sharpeningParams.autoContrast, clipMask); if (plistener) { plistener->setProgress(0.2); } @@ -810,7 +813,7 @@ BENCHFUN #endif for (int i = 0; i < H; ++i) { for (int j = 0; j < W; ++j) { - red[i][j] = green[i][j] = blue[i][j] = blend[i][j] * 16384.f; + red[i][j] = green[i][j] = blue[i][j] = clipMask[i][j] * 16384.f; } } if (plistener) { @@ -847,18 +850,18 @@ BENCHFUN if (plistener) { plistener->setProgress(0.1); } + // calculate contrast based blend factors to reduce sharpening in regions with low contrast - array2D& blend = clipMask; // we can share blend and clipMask buffer here - buildBlendMask(L, blend, W, H, contrast, 1.f, sharpeningParams.autoContrast, clipMask); + buildBlendMask(L, clipMask, W, H, contrast, sharpeningParams.autoContrast, clipMask); if (plistener) { plistener->setProgress(0.2); } conrastThreshold = contrast * 100.f; - - CaptureDeconvSharpening(clipMask, YNew, YOld, blend, W, H, radius, sharpeningParams.deconvradiusOffset, sharpeningParams.deconviter, sharpeningParams.deconvitercheck, plistener, 0.2, 0.9); + CaptureDeconvSharpening(YNew, YOld, clipMask, W, H, radius, sharpeningParams.deconvradiusOffset, sharpeningParams.deconviter, sharpeningParams.deconvitercheck, plistener, 0.2, 0.9); if (plistener) { plistener->setProgress(0.9); } + #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 16) #endif @@ -866,7 +869,7 @@ BENCHFUN int j = 0; #ifdef __SSE2__ for (; j < W - 3; j += 4) { - const vfloat factor = vmaxf(LVFU(YNew[i][j]), ZEROV) / vmaxf(LVFU(YOld[i][j]), F2V(0.00001f)); + const vfloat factor = LVFU(YNew[i][j]) / vmaxf(LVFU(YOld[i][j]), F2V(0.00001f)); STVFU(red[i][j], LVFU(redVals[i][j]) * factor); STVFU(green[i][j], LVFU(greenVals[i][j]) * factor); STVFU(blue[i][j], LVFU(blueVals[i][j]) * factor); @@ -874,7 +877,7 @@ BENCHFUN #endif for (; j < W; ++j) { - const float factor = std::max(YNew[i][j], 0.f) / std::max(YOld[i][j], 0.00001f); + const float factor = YNew[i][j] / std::max(YOld[i][j], 0.00001f); red[i][j] = redVals[i][j] * factor; green[i][j] = greenVals[i][j] * factor; blue[i][j] = blueVals[i][j] * factor; diff --git a/rtengine/color.h b/rtengine/color.h index d9c344c27..211615de1 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -1372,7 +1372,7 @@ public: * @param HH hue before [-PI ; +PI] * @param Chprov1 chroma after [0 ; 180 (can be superior)] * @param CC chroma before [0 ; 180] - * @param corectionHuechroma hue correction depending on chromaticity (saturation), in radians [0 ; 0.45] (return value) + * @param correctionHueChroma hue correction depending on chromaticity (saturation), in radians [0 ; 0.45] (return value) * @param correctlum hue correction depending on luminance (brightness, contrast,...), in radians [0 ; 0.45] (return value) * @param munsDbgInfo (Debug target only) object to collect information */ diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index d5348286c..812f122b3 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -4433,6 +4433,10 @@ void CLASS foveon_interpolate() void CLASS crop_masked_pixels() { + if (data_error) { + return; + } + int row, col; unsigned r, c, m, mblack[8], zero, val; diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index a6889b954..890003ee0 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -173,8 +173,6 @@ void Crop::update(int todo) int widIm = parent->fw;//full image int heiIm = parent->fh; - bool needstransform = parent->ipf.needsTransform(); - if (todo & (M_INIT | M_LINDENOISE | M_HDR)) { MyMutex::MyLock lock(parent->minit); // Also used in improccoord @@ -766,8 +764,9 @@ void Crop::update(int todo) } } + const bool needstransform = parent->ipf.needsTransform(skips(parent->fw, skip), skips(parent->fh, skip), parent->imgsrc->getRotateDegree(), parent->imgsrc->getMetaData()); // transform - if (needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled)) { + if (needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled)) { if (!transCrop) { transCrop = new Imagefloat(cropw, croph); } @@ -784,10 +783,7 @@ void Crop::update(int todo) baseCrop = transCrop; } } else { - if (transCrop) { - delete transCrop; - } - + delete transCrop; transCrop = nullptr; } @@ -1167,41 +1163,42 @@ bool Crop::setCropSizes(int rcx, int rcy, int rcw, int rch, int skip, bool inter parent->ipf.transCoord(parent->fw, parent->fh, bx1, by1, bw, bh, orx, ory, orw, orh); - if (check_need_larger_crop_for_lcp_distortion(parent->fw, parent->fh, orx, ory, orw, orh, *parent->params)) { - // TODO - this is an estimate of the max distortion relative to the image size. ATM it is hardcoded to be 15%, which seems enough. If not, need to revise - int dW = int (double (parent->fw) * 0.15 / (2 * skip)); - int dH = int (double (parent->fh) * 0.15 / (2 * skip)); - int x1 = orx - dW; - int x2 = orx + orw + dW; - int y1 = ory - dH; - int y2 = ory + orh + dH; + if (parent->ipf.needsTransform(skips(parent->fw, skip), skips(parent->fh, skip), parent->imgsrc->getRotateDegree(), parent->imgsrc->getMetaData())) { + if (check_need_larger_crop_for_lcp_distortion(parent->fw, parent->fh, orx, ory, orw, orh, *parent->params)) { + // TODO - this is an estimate of the max distortion relative to the image size. ATM it is hardcoded to be 15%, which seems enough. If not, need to revise + int dW = int (double (parent->fw) * 0.15 / (2 * skip)); + int dH = int (double (parent->fh) * 0.15 / (2 * skip)); + int x1 = orx - dW; + int x2 = orx + orw + dW; + int y1 = ory - dH; + int y2 = ory + orh + dH; - if (x1 < 0) { - x2 += -x1; - x1 = 0; + if (x1 < 0) { + x2 += -x1; + x1 = 0; + } + + if (x2 > parent->fw) { + x1 -= x2 - parent->fw; + x2 = parent->fw; + } + + if (y1 < 0) { + y2 += -y1; + y1 = 0; + } + + if (y2 > parent->fh) { + y1 -= y2 - parent->fh; + y2 = parent->fh; + } + + orx = max(x1, 0); + ory = max(y1, 0); + orw = min(x2 - x1, parent->fw - orx); + orh = min(y2 - y1, parent->fh - ory); } - - if (x2 > parent->fw) { - x1 -= x2 - parent->fw; - x2 = parent->fw; - } - - if (y1 < 0) { - y2 += -y1; - y1 = 0; - } - - if (y2 > parent->fh) { - y1 -= y2 - parent->fh; - y2 = parent->fh; - } - - orx = max(x1, 0); - ory = max(y1, 0); - orw = min(x2 - x1, parent->fw - orx); - orh = min(y2 - y1, parent->fh - ory); } - leftBorder = skips(rqx1 - bx1, skip); upperBorder = skips(rqy1 - by1, skip); diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 69d1a189a..93508808c 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -105,7 +105,7 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams JaggedArray blend(winw, winh); float contrastf = contrast / 100.f; - buildBlendMask(L, blend, winw, winh, contrastf, 1.f, autoContrast); + buildBlendMask(L, blend, winw, winh, contrastf, autoContrast); contrast = contrastf * 100.f; array2D& redTmp = L; // L is not needed anymore => reuse it diff --git a/rtengine/guidedfilter.cc b/rtengine/guidedfilter.cc index 6b2adb773..ad3beec51 100644 --- a/rtengine/guidedfilter.cc +++ b/rtengine/guidedfilter.cc @@ -106,7 +106,18 @@ void guidedFilter(const array2D &guide, const array2D &src, array2 const auto f_subsample = [multithread](array2D &d, const array2D &s) -> void { - rescaleBilinear(s, d, multithread); + if (d.width() == s.width() && d.height() == s.height()) { +#ifdef _OPENMP + #pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < s.height(); ++y) { + for (int x = 0; x < s.width(); ++x) { + d[y][x] = s[y][x]; + } + } + } else { + rescaleBilinear(s, d, multithread); + } }; const auto f_mean = diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index a4ca0ea0b..e915a11b0 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -545,7 +545,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) oprevi = orig_prev; // Remove transformation if unneeded - bool needstransform = ipf.needsTransform(); + bool needstransform = ipf.needsTransform(fw, fh, imgsrc->getRotateDegree(), imgsrc->getMetaData()); if ((needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled && !params->colorappearance.enabled))) { assert(oprevi); @@ -1349,7 +1349,7 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw); ImProcFunctions ipf(&ppar, true); - if (ipf.needsTransform()) { + if (ipf.needsTransform(fW, fH, imgsrc->getRotateDegree(), imgsrc->getMetaData())) { Imagefloat* trImg = new Imagefloat(fW, fH); ipf.transform(im, trImg, 0, 0, 0, 0, fW, fH, fW, fH, imgsrc->getMetaData(), imgsrc->getRotateDegree(), true); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index cb0834570..d5c69773e 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -5131,11 +5131,11 @@ void ImProcFunctions::EPDToneMapCIE (CieImage *ncie, float a_w, float c_, int Wi if (!params->epd.enabled) { return; } - +/* if (params->wavelet.enabled && params->wavelet.tmrs != 0) { return; } - +*/ float stren = params->epd.strength; float edgest = params->epd.edgeStopping; float sca = params->epd.scale; @@ -5245,11 +5245,11 @@ void ImProcFunctions::EPDToneMap (LabImage *lab, unsigned int Iterates, int skip if (!params->epd.enabled) { return; } - +/* if (params->wavelet.enabled && params->wavelet.tmrs != 0) { return; } - +*/ float stren = params->epd.strength; float edgest = params->epd.edgeStopping; float sca = params->epd.scale; @@ -5590,7 +5590,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double whiteclipg = CurveFactory::igamma2 ((float) (whiteclipg / 65535.0)) * 65535.0; //need to inverse gamma transform to get correct exposure compensation parameter - //corection with gamma + //correction with gamma black = (int) ((65535 * black) / whiteclipg); //expcomp = log(65535.0 / (whiteclipg)) / log(2.0); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 661f399ef..8f4ae7771 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -84,8 +84,8 @@ class ImProcFunctions void calcVignettingParams(int oW, int oH, const procparams::VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul); void transformLuminanceOnly(Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH, int fW, int fH); - void transformGeneral(bool highQuality, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap); - void transformLCPCAOnly(Imagefloat *original, Imagefloat *transformed, int cx, int cy, const LensCorrection *pLCPMap); + void transformGeneral(bool highQuality, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap, bool useOriginalBuffer); + void transformLCPCAOnly(Imagefloat *original, Imagefloat *transformed, int cx, int cy, const LensCorrection *pLCPMap, bool useOriginalBuffer); bool needsCA() const; bool needsDistortion() const; @@ -119,7 +119,7 @@ public: } void setScale(double iscale); - bool needsTransform() const; + bool needsTransform(int oW, int oH, int rawRotationDeg, const FramesMetaData *metadata) const; bool needsPCVignetting() const; void firstAnalysis(const Imagefloat* const working, const procparams::ProcParams ¶ms, LUTu & vhist16); @@ -156,7 +156,7 @@ public: // void colorCurve (LabImage* lold, LabImage* lnew); void sharpening(LabImage* lab, const procparams::SharpeningParams &sharpenParam, bool showMask = false); void sharpeningcam(CieImage* ncie, float** buffer, bool showMask = false); - void transform(Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const FramesMetaData *metadata, int rawRotationDeg, bool fullImage); + void transform(Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const FramesMetaData *metadata, int rawRotationDeg, bool fullImage, bool useOriginalBuffer = false); float resizeScale(const procparams::ProcParams* params, int fw, int fh, int &imw, int &imh); void lab2monitorRgb(LabImage* lab, Image8* image); void resize(Imagefloat* src, Imagefloat* dst, float dScale); diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 1d3f2f494..e366184b0 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -38,14 +38,8 @@ namespace { inline void copyAndClampLine(const float *src, unsigned char *dst, const int W) { - for (int j = 0, iy = 0; j < W; ++j) { - float r = src[iy] * MAXVALF; - float g = src[iy+1] * MAXVALF; - float b = src[iy+2] * MAXVALF; - dst[iy] = uint16ToUint8Rounded(CLIP(r)); - dst[iy+1] = uint16ToUint8Rounded(CLIP(g)); - dst[iy+2] = uint16ToUint8Rounded(CLIP(b)); - iy += 3; + for (int j = 0; j < W * 3; ++j) { + dst[j] = uint16ToUint8Rounded(CLIP(src[j] * MAXVALF)); } } @@ -90,8 +84,8 @@ void ImProcFunctions::lab2monitorRgb(LabImage* lab, Image8* image) { if (monitorTransform) { - int W = lab->W; - int H = lab->H; + const int W = lab->W; + const int H = lab->H; unsigned char * data = image->data; // cmsDoTransform is relatively expensive @@ -100,18 +94,19 @@ void ImProcFunctions::lab2monitorRgb(LabImage* lab, Image8* image) #endif { AlignedBuffer pBuf(3 * lab->W); - AlignedBuffer mBuf(3 * lab->W); + AlignedBuffer mBuf; AlignedBuffer gwBuf1; AlignedBuffer gwBuf2; if (gamutWarning) { gwBuf1.resize(3 * lab->W); gwBuf2.resize(3 * lab->W); + mBuf.resize(3 * lab->W); } float *buffer = pBuf.data; - float *outbuffer = mBuf.data; + float *outbuffer = gamutWarning ? mBuf.data : pBuf.data; // make in place transformations when gamutWarning is not needed #ifdef _OPENMP #pragma omp for schedule(dynamic,16) @@ -132,7 +127,7 @@ void ImProcFunctions::lab2monitorRgb(LabImage* lab, Image8* image) buffer[iy++] = rb[j] / 327.68f; } - cmsDoTransform (monitorTransform, buffer, outbuffer, W); + cmsDoTransform(monitorTransform, buffer, outbuffer, W); copyAndClampLine(outbuffer, data + ix, W); if (gamutWarning) { diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index a35476d3a..7198b76c5 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -256,7 +256,7 @@ void ImProcFunctions::sharpening (LabImage* lab, const procparams::SharpeningPar // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); float contrast = sharpenParam.contrast / 100.f; - buildBlendMask(lab->L, blend, W, H, contrast, 1.f); + buildBlendMask(lab->L, blend, W, H, contrast); if(showMask) { #ifdef _OPENMP diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc index 600dca033..0c900c998 100644 --- a/rtengine/iptransform.cc +++ b/rtengine/iptransform.cc @@ -87,6 +87,29 @@ float normn (float a, float b, int n) } } +void logEncode(rtengine::Imagefloat *src, rtengine::Imagefloat *dest, bool multiThread) { + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 16) if(multiThread) +#endif + + for (int y = 0; y < src->getHeight(); ++y) { + int x = 0; +#ifdef __SSE2__ + for (; x < src->getWidth() - 3; x += 4) { + STVFU(dest->r(y, x), xlogf1(LVFU(src->r(y, x)))); + STVFU(dest->g(y, x), xlogf1(LVFU(src->g(y, x)))); + STVFU(dest->b(y, x), xlogf1(LVFU(src->b(y, x)))); + } +#endif + for (; x < src->getWidth(); ++x) { + dest->r(y, x) = xlogf1(src->r(y, x)); + dest->g(y, x) = xlogf1(src->g(y, x)); + dest->b(y, x) = xlogf1(src->b(y, x)); + } + } +} + #ifdef __SSE2__ inline void interpolateTransformCubic(rtengine::Imagefloat* src, int xs, int ys, float Dx, float Dy, float &r, float &g, float &b, float mul) { @@ -112,6 +135,33 @@ inline void interpolateTransformCubic(rtengine::Imagefloat* src, int xs, int ys, g = vhadd(weight * gv); b = vhadd(weight * bv); } + +inline void interpolateTransformCubicLog(rtengine::Imagefloat* src, int xs, int ys, float Dx, float Dy, float &r, float &g, float &b, float mul) +{ + constexpr float A = -0.85f; + + // Vertical + const float t1Vert = A * (Dy - Dy * Dy); + const float t2Vert = (3.f - 2.f * Dy) * Dy * Dy; + const vfloat w3Vert = F2V(t1Vert * Dy); + const vfloat w2Vert = F2V(t1Vert * Dy - t1Vert + t2Vert); + const vfloat w1Vert = F2V(1.f - (t1Vert * Dy) - t2Vert); + const vfloat w0Vert = F2V(t1Vert - (t1Vert * Dy)); + + const vfloat rv = (w0Vert * LVFU(src->r(ys, xs)) + w1Vert * LVFU(src->r(ys + 1, xs))) + (w2Vert * LVFU(src->r(ys + 2, xs)) + w3Vert * LVFU(src->r(ys + 3, xs))); + const vfloat gv = (w0Vert * LVFU(src->g(ys, xs)) + w1Vert * LVFU(src->g(ys + 1, xs))) + (w2Vert * LVFU(src->g(ys + 2, xs)) + w3Vert * LVFU(src->g(ys + 3, xs))); + const vfloat bv = (w0Vert * LVFU(src->b(ys, xs)) + w1Vert * LVFU(src->b(ys + 1, xs))) + (w2Vert * LVFU(src->b(ys + 2, xs)) + w3Vert * LVFU(src->b(ys + 3, xs))); + + // Horizontal + const float t1Hor = A * (Dx - Dx * Dx); + const float t2Hor = (3.f - 2.f * Dx) * Dx * Dx; + const vfloat weight = _mm_set_ps(t1Hor * Dx, t1Hor * Dx - t1Hor + t2Hor, 1.f - (t1Hor * Dx) - t2Hor, t1Hor - (t1Hor * Dx)); + const vfloat tempv = _mm_setr_ps(vhadd(weight * rv), vhadd(weight * gv), vhadd(weight * bv), 0.f); + const vfloat resultv = xexpf(tempv); + r = mul * resultv[0]; + g = mul * resultv[1]; + b = mul * resultv[2]; +} #else inline void interpolateTransformCubic(rtengine::Imagefloat* src, int xs, int ys, float Dx, float Dy, float &r, float &g, float &b, float mul) { @@ -144,6 +194,38 @@ inline void interpolateTransformCubic(rtengine::Imagefloat* src, int xs, int ys, g = mul * (gv[0] * w0Hor + gv[1] * w1Hor + gv[2] * w2Hor + gv[3] * w3Hor); b = mul * (bv[0] * w0Hor + bv[1] * w1Hor + bv[2] * w2Hor + bv[3] * w3Hor); } + +inline void interpolateTransformCubicLog(rtengine::Imagefloat* src, int xs, int ys, float Dx, float Dy, float &r, float &g, float &b, float mul) +{ + constexpr float A = -0.85f; + + // Vertical + const float t1Vert = A * (Dy - Dy * Dy); + const float t2Vert = (3.f - 2.f * Dy) * Dy * Dy; + const float w3Vert = t1Vert * Dy; + const float w2Vert = t1Vert * Dy - t1Vert + t2Vert; + const float w1Vert = 1.f - (t1Vert * Dy) - t2Vert; + const float w0Vert = t1Vert - (t1Vert * Dy); + + float rv[4], gv[4], bv[4]; + for (int i = 0; i < 4; ++i) { + rv[i] = w0Vert * src->r(ys, xs + i) + w1Vert * src->r(ys + 1, xs + i) + w2Vert * src->r(ys + 2, xs + i) + w3Vert * src->r(ys + 3, xs + i); + gv[i] = w0Vert * src->g(ys, xs + i) + w1Vert * src->g(ys + 1, xs + i) + w2Vert * src->g(ys + 2, xs + i) + w3Vert * src->g(ys + 3, xs + i); + bv[i] = w0Vert * src->b(ys, xs + i) + w1Vert * src->b(ys + 1, xs + i) + w2Vert * src->b(ys + 2, xs + i) + w3Vert * src->b(ys + 3, xs + i); + } + + // Horizontal + const float t1Hor = A * (Dx - Dx * Dx); + const float t2Hor = (3.f - 2.f * Dx) * Dx * Dx; + const float w3Hor = t1Hor * Dx; + const float w2Hor = t1Hor * Dx - t1Hor + t2Hor; + const float w1Hor = 1.f - (t1Hor * Dx) - t2Hor; + const float w0Hor = t1Hor - (t1Hor * Dx); + + r = mul * xexpf(rv[0] * w0Hor + rv[1] * w1Hor + rv[2] * w2Hor + rv[3] * w3Hor); + g = mul * xexpf(gv[0] * w0Hor + gv[1] * w1Hor + gv[2] * w2Hor + gv[3] * w3Hor); + b = mul * xexpf(bv[0] * w0Hor + bv[1] * w1Hor + bv[2] * w2Hor + bv[3] * w3Hor); +} #endif #ifdef __SSE2__ inline void interpolateTransformChannelsCubic(const float* const* src, int xs, int ys, float Dx, float Dy, float& dest, float mul) @@ -166,6 +248,27 @@ inline void interpolateTransformChannelsCubic(const float* const* src, int xs, i const vfloat weight = _mm_set_ps(t1Hor * Dx, t1Hor * Dx - t1Hor + t2Hor, 1.f - (t1Hor * Dx) - t2Hor, t1Hor - (t1Hor * Dx)); dest = mul * vhadd(weight * cv); } + +inline void interpolateTransformChannelsCubicLog(const float* const* src, int xs, int ys, float Dx, float Dy, float& dest, float mul) +{ + constexpr float A = -0.85f; + + // Vertical + const float t1Vert = A * (Dy - Dy * Dy); + const float t2Vert = (3.f - 2.f * Dy) * Dy * Dy; + const vfloat w3Vert = F2V(t1Vert * Dy); + const vfloat w2Vert = F2V(t1Vert * Dy - t1Vert + t2Vert); + const vfloat w1Vert = F2V(1.f - (t1Vert * Dy) - t2Vert); + const vfloat w0Vert = F2V(t1Vert - (t1Vert * Dy)); + + const vfloat cv = (w0Vert * LVFU(src[ys][xs]) + w1Vert * LVFU(src[ys + 1][xs])) + (w2Vert * LVFU(src[ys + 2][xs]) + w3Vert * LVFU(src[ys + 3][xs])); + + // Horizontal + const float t1Hor = A * (Dx - Dx * Dx); + const float t2Hor = (3.f - 2.f * Dx) * Dx * Dx; + const vfloat weight = _mm_set_ps(t1Hor * Dx, t1Hor * Dx - t1Hor + t2Hor, 1.f - (t1Hor * Dx) - t2Hor, t1Hor - (t1Hor * Dx)); + dest = mul * xexpf(vhadd(weight * cv)); +} #else inline void interpolateTransformChannelsCubic(const float* const* src, int xs, int ys, float Dx, float Dy, float& dest, float mul) { @@ -194,6 +297,34 @@ inline void interpolateTransformChannelsCubic(const float* const* src, int xs, i dest = mul * (cv[0] * w0Hor + cv[1] * w1Hor + cv[2] * w2Hor + cv[3] * w3Hor); } + +inline void interpolateTransformChannelsCubicLog(const float* const* src, int xs, int ys, float Dx, float Dy, float& dest, float mul) +{ + constexpr float A = -0.85f; + + // Vertical + const float t1Vert = A * (Dy - Dy * Dy); + const float t2Vert = (3.f - 2.f * Dy) * Dy * Dy; + const float w3Vert = t1Vert * Dy; + const float w2Vert = t1Vert * Dy - t1Vert + t2Vert; + const float w1Vert = 1.f - (t1Vert * Dy) - t2Vert; + const float w0Vert = t1Vert - (t1Vert * Dy); + + float cv[4]; + for (int i = 0; i < 4; ++i) { + cv[i] = w0Vert * src[ys][xs + i] + w1Vert * src[ys + 1][xs + i] + w2Vert * src[ys + 2][xs + i] + w3Vert * src[ys + 3][xs + i]; + } + + // Horizontal + const float t1Hor = A * (Dx - Dx * Dx); + const float t2Hor = (3.f - 2.f * Dx) * Dx * Dx; + const float w3Hor = t1Hor * Dx; + const float w2Hor = t1Hor * Dx - t1Hor + t2Hor; + const float w1Hor = 1.f - (t1Hor * Dx) - t2Hor; + const float w0Hor = t1Hor - (t1Hor * Dx); + + dest = mul * xexpf(cv[0] * w0Hor + cv[1] * w1Hor + cv[2] * w2Hor + cv[3] * w3Hor); +} #endif } @@ -522,7 +653,7 @@ bool ImProcFunctions::transCoord (int W, int H, int x, int y, int w, int h, int& void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const FramesMetaData *metadata, - int rawRotationDeg, bool fullImage) + int rawRotationDeg, bool fullImage, bool useOriginalBuffer) { double focalLen = metadata->getFocalLen(); double focalLen35mm = metadata->getFocalLen35mm(); @@ -570,10 +701,10 @@ void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, dest = tmpimg.get(); } } - transformGeneral(highQuality, original, dest, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap.get()); + transformGeneral(highQuality, original, dest, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap.get(), useOriginalBuffer); if (highQuality && dest != transformed) { - transformLCPCAOnly(dest, transformed, cx, cy, pLCPMap.get()); + transformLCPCAOnly(dest, transformed, cx, cy, pLCPMap.get(), useOriginalBuffer); } } } @@ -962,8 +1093,9 @@ void ImProcFunctions::transformLuminanceOnly (Imagefloat* original, Imagefloat* } -void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap) +void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap, bool useOriginalBuffer) { + // set up stuff, depending on the mode we are enum PerspType { NONE, SIMPLE, CAMERA_BASED }; const bool enableLCPDist = pLCPMap && params->lensProf.useDist; @@ -994,11 +1126,6 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I calcPCVignetteParams(fW, fH, oW, oH, params->pcvignette, params->crop, pcv); } - const std::array chOrig = { - original->r.ptrs, - original->g.ptrs, - original->b.ptrs - }; const std::array chTrans = { transformed->r.ptrs, transformed->g.ptrs, @@ -1023,12 +1150,6 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I const double cost = cos(params->rotate.degree * rtengine::RT_PI / 180.0); const double sint = sin(params->rotate.degree * rtengine::RT_PI / 180.0); - const double ascale = params->commonTrans.autofill ? getTransformAutoFill(oW, oH, pLCPMap) : 1.0; - - const bool darkening = (params->vignetting.amount <= 0.0); - const double centerFactorx = cx - w2; - const double centerFactory = cy - h2; - // auxiliary variables for perspective correction // Simple. const double vpdeg = params->perspective.vertical / 100.0 * 45.0; @@ -1064,6 +1185,30 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I p_projection_rotate, p_projection_shift_horiz, p_projection_shift_vert, p_projection_scale); + const double ascale = params->commonTrans.autofill ? getTransformAutoFill(oW, oH, pLCPMap) : 1.0; + + const bool darkening = (params->vignetting.amount <= 0.0); + const bool useLog = params->commonTrans.method == "log" && highQuality; + const double centerFactorx = cx - w2; + const double centerFactory = cy - h2; + + std::unique_ptr tempLog; + if (useLog) { + if (!useOriginalBuffer) { + tempLog.reset(new Imagefloat(original->getWidth(), original->getHeight())); + logEncode(original, tempLog.get(), multiThread); + original = tempLog.get(); + } else { + logEncode(original, original, multiThread); + } + } + + const std::array chOrig = { + original->r.ptrs, + original->g.ptrs, + original->b.ptrs + }; + // main cycle #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 16) if(multiThread) @@ -1161,14 +1306,22 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I if (yc > 0 && yc < original->getHeight() - 2 && xc > 0 && xc < original->getWidth() - 2) { // all interpolation pixels inside image - if (enableCA) { - interpolateTransformChannelsCubic(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], vignmul); - } else if (!highQuality) { + if (!highQuality) { transformed->r(y, x) = vignmul * (original->r(yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->r(yc, xc + 1) * Dx * (1.0 - Dy) + original->r(yc + 1, xc) * (1.0 - Dx) * Dy + original->r(yc + 1, xc + 1) * Dx * Dy); transformed->g(y, x) = vignmul * (original->g(yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->g(yc, xc + 1) * Dx * (1.0 - Dy) + original->g(yc + 1, xc) * (1.0 - Dx) * Dy + original->g(yc + 1, xc + 1) * Dx * Dy); transformed->b(y, x) = vignmul * (original->b(yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->b(yc, xc + 1) * Dx * (1.0 - Dy) + original->b(yc + 1, xc) * (1.0 - Dx) * Dy + original->b(yc + 1, xc + 1) * Dx * Dy); + } else if (!useLog) { + if (enableCA) { + interpolateTransformChannelsCubic(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], vignmul); + } else { + interpolateTransformCubic(original, xc - 1, yc - 1, Dx, Dy, transformed->r(y, x), transformed->g(y, x), transformed->b(y, x), vignmul); + } } else { - interpolateTransformCubic(original, xc - 1, yc - 1, Dx, Dy, transformed->r(y, x), transformed->g(y, x), transformed->b(y, x), vignmul); + if (enableCA) { + interpolateTransformChannelsCubicLog(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], vignmul); + } else { + interpolateTransformCubicLog(original, xc - 1, yc - 1, Dx, Dy, transformed->r(y, x), transformed->g(y, x), transformed->b(y, x), vignmul); + } } } else { // edge pixels @@ -1177,12 +1330,22 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I const int x1 = LIM(xc, 0, original->getWidth() - 1); const int x2 = LIM(xc + 1, 0, original->getWidth() - 1); - if (enableCA) { - chTrans[c][y][x] = vignmul * (chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy); + if (useLog) { + if (enableCA) { + chTrans[c][y][x] = vignmul * xexpf(chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy); + } else { + transformed->r(y, x) = vignmul * xexpf(original->r(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->r(y1, x2) * Dx * (1.0 - Dy) + original->r(y2, x1) * (1.0 - Dx) * Dy + original->r(y2, x2) * Dx * Dy); + transformed->g(y, x) = vignmul * xexpf(original->g(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->g(y1, x2) * Dx * (1.0 - Dy) + original->g(y2, x1) * (1.0 - Dx) * Dy + original->g(y2, x2) * Dx * Dy); + transformed->b(y, x) = vignmul * xexpf(original->b(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->b(y1, x2) * Dx * (1.0 - Dy) + original->b(y2, x1) * (1.0 - Dx) * Dy + original->b(y2, x2) * Dx * Dy); + } } else { - transformed->r(y, x) = vignmul * (original->r(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->r(y1, x2) * Dx * (1.0 - Dy) + original->r(y2, x1) * (1.0 - Dx) * Dy + original->r(y2, x2) * Dx * Dy); - transformed->g(y, x) = vignmul * (original->g(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->g(y1, x2) * Dx * (1.0 - Dy) + original->g(y2, x1) * (1.0 - Dx) * Dy + original->g(y2, x2) * Dx * Dy); - transformed->b(y, x) = vignmul * (original->b(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->b(y1, x2) * Dx * (1.0 - Dy) + original->b(y2, x1) * (1.0 - Dx) * Dy + original->b(y2, x2) * Dx * Dy); + if (enableCA) { + chTrans[c][y][x] = vignmul * (chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy); + } else { + transformed->r(y, x) = vignmul * (original->r(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->r(y1, x2) * Dx * (1.0 - Dy) + original->r(y2, x1) * (1.0 - Dx) * Dy + original->r(y2, x2) * Dx * Dy); + transformed->g(y, x) = vignmul * (original->g(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->g(y1, x2) * Dx * (1.0 - Dy) + original->g(y2, x1) * (1.0 - Dx) * Dy + original->g(y2, x2) * Dx * Dy); + transformed->b(y, x) = vignmul * (original->b(y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->b(y1, x2) * Dx * (1.0 - Dy) + original->b(y2, x1) * (1.0 - Dx) * Dy + original->b(y2, x2) * Dx * Dy); + } } } } else { @@ -1201,19 +1364,24 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I } -void ImProcFunctions::transformLCPCAOnly(Imagefloat *original, Imagefloat *transformed, int cx, int cy, const LensCorrection *pLCPMap) +void ImProcFunctions::transformLCPCAOnly(Imagefloat *original, Imagefloat *transformed, int cx, int cy, const LensCorrection *pLCPMap, bool useOriginalBuffer) { assert(pLCPMap && params->lensProf.useCA && pLCPMap->isCACorrectionAvailable()); + const bool useLog = params->commonTrans.method == "log"; - float** chOrig[3]; - chOrig[0] = original->r.ptrs; - chOrig[1] = original->g.ptrs; - chOrig[2] = original->b.ptrs; + float** chTrans[3] = {transformed->r.ptrs, transformed->g.ptrs, transformed->b.ptrs}; - float** chTrans[3]; - chTrans[0] = transformed->r.ptrs; - chTrans[1] = transformed->g.ptrs; - chTrans[2] = transformed->b.ptrs; + std::unique_ptr tempLog; + if (useLog) { + if (!useOriginalBuffer) { + tempLog.reset(new Imagefloat(original->getWidth(), original->getHeight())); + logEncode(original, tempLog.get(), multiThread); + original = tempLog.get(); + } else { + logEncode(original, original, multiThread); + } + } + float** chOrig[3] = {original->r.ptrs, original->g.ptrs, original->b.ptrs}; #ifdef _OPENMP #pragma omp parallel for if (multiThread) @@ -1239,15 +1407,22 @@ void ImProcFunctions::transformLCPCAOnly(Imagefloat *original, Imagefloat *trans // multiplier for vignetting correction if (yc > 0 && yc < original->getHeight() - 2 && xc > 0 && xc < original->getWidth() - 2) { // all interpolation pixels inside image - interpolateTransformChannelsCubic (chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], 1.0); + if (!useLog) { + interpolateTransformChannelsCubic(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], 1.0); + } else { + interpolateTransformChannelsCubicLog(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], 1.0); + } } else { // edge pixels int y1 = LIM (yc, 0, original->getHeight() - 1); int y2 = LIM (yc + 1, 0, original->getHeight() - 1); int x1 = LIM (xc, 0, original->getWidth() - 1); int x2 = LIM (xc + 1, 0, original->getWidth() - 1); - - chTrans[c][y][x] = (chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy); + if (!useLog) { + chTrans[c][y][x] = (chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy); + } else { + chTrans[c][y][x] = xexpf(chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy); + } } } else { // not valid (source pixel x,y not inside source image, etc.) @@ -1341,9 +1516,14 @@ bool ImProcFunctions::needsLensfun() const return params->lensProf.useLensfun(); } -bool ImProcFunctions::needsTransform () const +bool ImProcFunctions::needsTransform (int oW, int oH, int rawRotationDeg, const FramesMetaData *metadata) const { - return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsPCVignetting () || needsVignetting () || needsLCP() || needsLensfun(); + bool needsLf = needsLensfun(); + if (needsLf) { + std::unique_ptr pLCPMap = LFDatabase::getInstance()->findModifier(params->lensProf, metadata, oW, oH, params->coarse, rawRotationDeg); + needsLf = pLCPMap.get(); + } + return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsPCVignetting () || needsVignetting () || needsLCP() || needsLf; } diff --git a/rtengine/perspectivecorrection.cc b/rtengine/perspectivecorrection.cc index 5f2ce3aa5..5fa7b32f3 100644 --- a/rtengine/perspectivecorrection.cc +++ b/rtengine/perspectivecorrection.cc @@ -271,7 +271,7 @@ PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *sr neutral.distortion = pparams->distortion; neutral.lensProf = pparams->lensProf; ImProcFunctions ipf(&neutral, true); - if (ipf.needsTransform()) { + if (ipf.needsTransform(w, h, src->getRotateDegree(), src->getMetaData())) { Imagefloat *tmp = new Imagefloat(w, h); ipf.transform(img.get(), tmp, 0, 0, 0, 0, w, h, w, h, src->getMetaData(), src->getRotateDegree(), false); diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 8934bf977..686577d98 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -1732,13 +1732,14 @@ bool CoarseTransformParams::operator !=(const CoarseTransformParams& other) cons } CommonTransformParams::CommonTransformParams() : + method("log"), autofill(true) { } bool CommonTransformParams::operator ==(const CommonTransformParams& other) const { - return autofill == other.autofill; + return method == other.method && autofill == other.autofill; } bool CommonTransformParams::operator !=(const CommonTransformParams& other) const @@ -3350,6 +3351,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->coarse.vflip, "Coarse Transformation", "VerticalFlip", coarse.vflip, keyFile); // Common properties for transformations + saveToKeyfile(!pedited || pedited->commonTrans.method, "Common Properties for Transformations", "Method", commonTrans.method, keyFile); saveToKeyfile(!pedited || pedited->commonTrans.autofill, "Common Properties for Transformations", "AutoFill", commonTrans.autofill, keyFile); // Rotation @@ -4403,6 +4405,11 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } if (keyFile.has_group("Common Properties for Transformations")) { + if (keyFile.has_key("Common Properties for Transformations", "Method")) { + assignFromKeyfile(keyFile, "Common Properties for Transformations", "Method", pedited, commonTrans.method, pedited->commonTrans.method); + } else { + commonTrans.method = "lin"; + } assignFromKeyfile(keyFile, "Common Properties for Transformations", "AutoFill", pedited, commonTrans.autofill, pedited->commonTrans.autofill); } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 06d397a54..ffebe89b9 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -837,6 +837,7 @@ struct CoarseTransformParams { * Common transformation parameters */ struct CommonTransformParams { + Glib::ustring method; bool autofill; CommonTransformParams(); diff --git a/rtengine/rawflatfield.cc b/rtengine/rawflatfield.cc index 05b3be408..cbc5e6bd6 100644 --- a/rtengine/rawflatfield.cc +++ b/rtengine/rawflatfield.cc @@ -263,10 +263,9 @@ void cfaboxblur(const float* const * riFlatFile, float* cfablur, int boxH, int b namespace rtengine { -void RawImageSource::processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, const unsigned short black[4]) +void RawImageSource::processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, const float black[4]) { // BENCHFUN - const float fblack[4] = {static_cast(black[0]), static_cast(black[1]), static_cast(black[2]), static_cast(black[3])}; std::unique_ptr cfablur(new float[H * W]); const int BS = raw.ff_BlurRadius + (raw.ff_BlurRadius & 1); @@ -292,7 +291,7 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra const int col = 2 * (W >> 2) + n; const int c = ri->get_colors() != 1 ? FC(row, col) : 0; const int c4 = ri->get_colors() != 1 ? ((c == 1 && !(row & 1)) ? 3 : c) : 0; - refcolor[m][n] = std::max(0.0f, cfablur[row * W + col] - fblack[c4]); + refcolor[m][n] = std::max(0.0f, cfablur[row * W + col] - black[c4]); } float limitFactor = 1.f; @@ -315,16 +314,16 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra clippedBefore = true; break; } - const float tempval = (rawVal - fblack[c4]) * (refcolor[m][n] / std::max(1e-5f, cfablur[(row + m) * W + col + n] - fblack[c4])); + const float tempval = (rawVal - black[c4]) * (refcolor[m][n] / std::max(1e-5f, cfablur[(row + m) * W + col + n] - black[c4])); maxval = std::max(maxval, tempval); } } // now we have the max value for the channel // if it clips, calculate factor to avoid clipping - if (maxval + fblack[c4] >= ri->get_white(c4)) { + if (maxval + black[c4] >= ri->get_white(c4)) { if (!clippedBefore) { - limitFactor = std::min(limitFactor, ri->get_white(c4) / (maxval + fblack[c4])); + limitFactor = std::min(limitFactor, ri->get_white(c4) / (maxval + black[c4])); } else { limitFactor = 1.f; } @@ -361,8 +360,8 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra const vfloat refcolorv[2] = {_mm_set_ps(refcolor[0][1], refcolor[0][0], refcolor[0][1], refcolor[0][0]), _mm_set_ps(refcolor[1][1], refcolor[1][0], refcolor[1][1], refcolor[1][0]) }; - const vfloat blackv[2] = {_mm_set_ps(fblack[c4[0][1]], fblack[c4[0][0]], fblack[c4[0][1]], fblack[c4[0][0]]), - _mm_set_ps(fblack[c4[1][1]], fblack[c4[1][0]], fblack[c4[1][1]], fblack[c4[1][0]]) + const vfloat blackv[2] = {_mm_set_ps(black[c4[0][1]], black[c4[0][0]], black[c4[0][1]], black[c4[0][0]]), + _mm_set_ps(black[c4[1][1]], black[c4[1][0]], black[c4[1][1]], black[c4[1][0]]) }; const vfloat onev = F2V(1.f); @@ -389,9 +388,9 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra #endif for (; col < W; ++col) { - const float blur = cfablur[row * W + col] - fblack[c4[row & 1][col & 1]]; + const float blur = cfablur[row * W + col] - black[c4[row & 1][col & 1]]; const float vignettecorr = blur <= minValue ? 1.f : refcolor[row & 1][col & 1] / blur; - rawData[row][col] = (rawData[row][col] - fblack[c4[row & 1][col & 1]]) * vignettecorr + fblack[c4[row & 1][col & 1]]; + rawData[row][col] = (rawData[row][col] - black[c4[row & 1][col & 1]]) * vignettecorr + black[c4[row & 1][col & 1]]; } } } else if (ri->getSensorType() == ST_FUJI_XTRANS) { @@ -404,7 +403,7 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra const int row = 2 * (H >> 2) + m; const int col = 2 * (W >> 2) + n; const int c = riFlatFile->XTRANSFC(row, col); - refcolor[c] += std::max(0.0f, cfablur[row * W + col] - fblack[c]); + refcolor[c] += std::max(0.0f, cfablur[row * W + col] - black[c]); cCount[c] ++; } @@ -430,14 +429,14 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra clippedBefore = true; break; } - const float tempval = (rawVal - fblack[0]) * (refcolor[ri->XTRANSFC(row, col)] / std::max(1e-5f, cfablur[(row) * W + col] - fblack[0])); + const float tempval = (rawVal - black[0]) * (refcolor[ri->XTRANSFC(row, col)] / std::max(1e-5f, cfablur[(row) * W + col] - black[0])); maxval = std::max(maxval, tempval); } } // there's only one white level for xtrans - if (!clippedBefore && maxval + fblack[0] > ri->get_white(0)) { - limitFactor = ri->get_white(0) / (maxval + fblack[0]); + if (!clippedBefore && maxval + black[0] > ri->get_white(0)) { + limitFactor = ri->get_white(0) / (maxval + black[0]); flatFieldAutoClipValue = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui } } else { @@ -458,9 +457,9 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra for (int row = 0; row < H; ++row) { for (int col = 0; col < W; ++col) { const int c = ri->XTRANSFC(row, col); - const float blur = cfablur[(row) * W + col] - fblack[c]; + const float blur = cfablur[(row) * W + col] - black[c]; const float vignettecorr = blur <= minValue ? 1.f : refcolor[c] / blur; - rawData[row][col] = (rawData[row][col] - fblack[c]) * vignettecorr + fblack[c]; + rawData[row][col] = (rawData[row][col] - black[c]) * vignettecorr + black[c]; } } } @@ -488,8 +487,8 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra } #ifdef __SSE2__ - const vfloat blackv[2] = {_mm_set_ps(fblack[c4[0][1]], fblack[c4[0][0]], fblack[c4[0][1]], fblack[c4[0][0]]), - _mm_set_ps(fblack[c4[1][1]], fblack[c4[1][0]], fblack[c4[1][1]], fblack[c4[1][0]]) + const vfloat blackv[2] = {_mm_set_ps(black[c4[0][1]], black[c4[0][0]], black[c4[0][1]], black[c4[0][0]]), + _mm_set_ps(black[c4[1][1]], black[c4[1][0]], black[c4[1][1]], black[c4[1][0]]) }; const vfloat epsv = F2V(1e-5f); @@ -513,9 +512,9 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra #endif for (; col < W; ++col) { - const float linecorr = SQR(std::max(1e-5f, cfablur[row * W + col] - fblack[c4[row & 1][col & 1]])) / - (std::max(1e-5f, cfablur1[row * W + col] - fblack[c4[row & 1][col & 1]]) * std::max(1e-5f, cfablur2[row * W + col] - fblack[c4[row & 1][col & 1]])); - rawData[row][col] = (rawData[row][col] - fblack[c4[row & 1][col & 1]]) * linecorr + fblack[c4[row & 1][col & 1]]; + const float linecorr = SQR(std::max(1e-5f, cfablur[row * W + col] - black[c4[row & 1][col & 1]])) / + (std::max(1e-5f, cfablur1[row * W + col] - black[c4[row & 1][col & 1]]) * std::max(1e-5f, cfablur2[row * W + col] - black[c4[row & 1][col & 1]])); + rawData[row][col] = (rawData[row][col] - black[c4[row & 1][col & 1]]) * linecorr + black[c4[row & 1][col & 1]]; } } } else if (ri->getSensorType() == ST_FUJI_XTRANS) { @@ -526,9 +525,9 @@ void RawImageSource::processFlatField(const procparams::RAWParams &raw, const Ra for (int row = 0; row < H; ++row) { for (int col = 0; col < W; ++col) { const int c = ri->XTRANSFC(row, col); - const float hlinecorr = std::max(1e-5f, cfablur[(row) * W + col] - fblack[c]) / std::max(1e-5f, cfablur1[(row) * W + col] - fblack[c]); - const float vlinecorr = std::max(1e-5f, cfablur[(row) * W + col] - fblack[c]) / std::max(1e-5f, cfablur2[(row) * W + col] - fblack[c]); - rawData[row][col] = (rawData[row][col] - fblack[c]) * hlinecorr * vlinecorr + fblack[c]; + const float hlinecorr = std::max(1e-5f, cfablur[(row) * W + col] - black[c]) / std::max(1e-5f, cfablur1[(row) * W + col] - black[c]); + const float vlinecorr = std::max(1e-5f, cfablur[(row) * W + col] - black[c]) / std::max(1e-5f, cfablur2[(row) * W + col] - black[c]); + rawData[row][col] = (rawData[row][col] - black[c]) * hlinecorr * vlinecorr + black[c]; } } } diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index d00812d88..18fc18f58 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -42,7 +42,7 @@ #include "../rtgui/options.h" //#define BENCHMARK -//#include "StopWatch.h" +#include "StopWatch.h" #ifdef _OPENMP #include @@ -2397,11 +2397,10 @@ void RawImageSource::HLRecovery_Global(const ToneCurveParams &hrp) */ void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, RawImage *riDark, RawImage *riFlatFile, array2D &rawData ) { - // TODO: Change type of black[] to float to avoid conversions - unsigned short black[4] = { - (unsigned short)ri->get_cblack(0), (unsigned short)ri->get_cblack(1), - (unsigned short)ri->get_cblack(2), (unsigned short)ri->get_cblack(3) - }; + const float black[4] = { + static_cast(ri->get_cblack(0)), static_cast(ri->get_cblack(1)), + static_cast(ri->get_cblack(2)), static_cast(ri->get_cblack(3)) + }; if (ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS) { if (!rawData) { @@ -2409,11 +2408,22 @@ void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, Raw } if (riDark && W == riDark->get_width() && H == riDark->get_height()) { // This works also for xtrans-sensors, because black[0] to black[4] are equal for these + StopWatch Stop1("darkframe subtraction"); +#ifdef _OPENMP + #pragma omp parallel for +#endif for (int row = 0; row < H; row++) { - for (int col = 0; col < W; col++) { - int c = FC(row, col); - int c4 = ( c == 1 && !(row & 1) ) ? 3 : c; - rawData[row][col] = max(src->data[row][col] + black[c4] - riDark->data[row][col], 0.0f); + const int c0 = FC(row, 0); + const float black0 = black[(c0 == 1 && !(row & 1) ) ? 3 : c0]; + const int c1 = FC(row, 1); + const float black1 = black[(c1 == 1 && !(row & 1) ) ? 3 : c1]; + int col; + for (col = 0; col < W - 1; col += 2) { + rawData[row][col] = max(src->data[row][col] + black0 - riDark->data[row][col], 0.0f); + rawData[row][col + 1] = max(src->data[row][col + 1] + black1 - riDark->data[row][col + 1], 0.0f); + } + if (col < W) { + rawData[row][col] = max(src->data[row][col] + black0 - riDark->data[row][col], 0.0f); } } } else { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 28cf30010..bd460c61b 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -136,7 +136,7 @@ public: return rgbSourceModified; // tracks whether cached rgb output of demosaic has been modified } - void processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, const unsigned short black[4]); + void processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, const float black[4]); void copyOriginalPixels(const procparams::RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile, array2D &rawData ); void scaleColors (int winx, int winy, int winw, int winh, const procparams::RAWParams &raw, array2D &rawData); // raw for cblack diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index 79a7c3679..a5b48af95 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -299,7 +299,7 @@ void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& maxOut = rtengine::LIM(maxOut, minVal, maxVal); } -void buildBlendMask(const float* const * luminance, float **blend, int W, int H, float &contrastThreshold, float amount, bool autoContrast, float ** clipMask) { +void buildBlendMask(const float* const * luminance, float **blend, int W, int H, float &contrastThreshold, bool autoContrast, float ** clipMask) { if (autoContrast) { constexpr float minLuminance = 2000.f; @@ -403,7 +403,7 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H, if(contrastThreshold == 0.f) { for(int j = 0; j < H; ++j) { for(int i = 0; i < W; ++i) { - blend[j][i] = amount; + blend[j][i] = 1.f; } } } else { @@ -415,7 +415,6 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H, #ifdef __SSE2__ const vfloat contrastThresholdv = F2V(contrastThreshold); const vfloat scalev = F2V(scale); - const vfloat amountv = F2V(amount); #endif #ifdef _OPENMP #pragma omp for schedule(dynamic,16) @@ -429,14 +428,14 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H, vfloat contrastv = vsqrtf(SQRV(LVFU(luminance[j][i+1]) - LVFU(luminance[j][i-1])) + SQRV(LVFU(luminance[j+1][i]) - LVFU(luminance[j-1][i])) + SQRV(LVFU(luminance[j][i+2]) - LVFU(luminance[j][i-2])) + SQRV(LVFU(luminance[j+2][i]) - LVFU(luminance[j-2][i]))) * scalev; - STVFU(blend[j][i], LVFU(clipMask[j][i]) * amountv * calcBlendFactor(contrastv, contrastThresholdv)); + STVFU(blend[j][i], LVFU(clipMask[j][i]) * calcBlendFactor(contrastv, contrastThresholdv)); } } else { for(; i < W - 5; i += 4) { vfloat contrastv = vsqrtf(SQRV(LVFU(luminance[j][i+1]) - LVFU(luminance[j][i-1])) + SQRV(LVFU(luminance[j+1][i]) - LVFU(luminance[j-1][i])) + SQRV(LVFU(luminance[j][i+2]) - LVFU(luminance[j][i-2])) + SQRV(LVFU(luminance[j+2][i]) - LVFU(luminance[j-2][i]))) * scalev; - STVFU(blend[j][i], amountv * calcBlendFactor(contrastv, contrastThresholdv)); + STVFU(blend[j][i], calcBlendFactor(contrastv, contrastThresholdv)); } } #endif @@ -445,7 +444,7 @@ void buildBlendMask(const float* const * luminance, float **blend, int W, int H, float contrast = sqrtf(rtengine::SQR(luminance[j][i+1] - luminance[j][i-1]) + rtengine::SQR(luminance[j+1][i] - luminance[j-1][i]) + rtengine::SQR(luminance[j][i+2] - luminance[j][i-2]) + rtengine::SQR(luminance[j+2][i] - luminance[j-2][i])) * scale; - blend[j][i] = (clipMask ? clipMask[j][i] : 1.f) * amount * calcBlendFactor(contrast, contrastThreshold); + blend[j][i] = (clipMask ? clipMask[j][i] : 1.f) * calcBlendFactor(contrast, contrastThreshold); } } diff --git a/rtengine/rt_algo.h b/rtengine/rt_algo.h index 5485346c7..81147fd75 100644 --- a/rtengine/rt_algo.h +++ b/rtengine/rt_algo.h @@ -24,5 +24,5 @@ namespace rtengine { void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& minOut, float maxPrct, float& maxOut, bool multiThread = true); -void buildBlendMask(const float* const * luminance, float **blend, int W, int H, float &contrastThreshold, float amount = 1.f, bool autoContrast = false, float ** clipmask = nullptr); +void buildBlendMask(const float* const * luminance, float **blend, int W, int H, float &contrastThreshold, bool autoContrast = false, float ** clipmask = nullptr); } diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 0cdcbf6ed..9da601e2a 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -1247,12 +1247,12 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.ToneMapFattal02(baseImg); // perform transform - if (ipf.needsTransform()) { + int origFW; + int origFH; + double tscale = 0.0; + getDimensions (origFW, origFH, tscale); + if (ipf.needsTransform(origFW * tscale + 0.5, origFH * tscale + 0.5, 0, metadata)) { Imagefloat* trImg = new Imagefloat (fw, fh); - int origFW; - int origFH; - double tscale = 0.0; - getDimensions (origFW, origFH, tscale); ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, origFW * tscale + 0.5, origFH * tscale + 0.5, metadata, 0, true); // Raw rotate degree not detectable here delete baseImg; baseImg = trImg; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index c35fc7431..1c1e46a65 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -872,7 +872,7 @@ private: ipf.ToneMapFattal02(baseImg); // perform transform (excepted resizing) - if (ipf.needsTransform()) { + if (ipf.needsTransform(fw, fh, imgsrc->getRotateDegree(), imgsrc->getMetaData())) { Imagefloat* trImg = nullptr; if (ipf.needsLuminanceOnly()) { trImg = baseImg; @@ -880,7 +880,7 @@ private: trImg = new Imagefloat (fw, fh); } ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, fw, fh, - imgsrc->getMetaData(), imgsrc->getRotateDegree(), true); + imgsrc->getMetaData(), imgsrc->getRotateDegree(), true, true); if(trImg != baseImg) { delete baseImg; baseImg = trImg; diff --git a/rtengine/sleef.h b/rtengine/sleef.h index 30c059010..b7655258b 100644 --- a/rtengine/sleef.h +++ b/rtengine/sleef.h @@ -532,7 +532,7 @@ __inline double xlog(double d) { x = x * t + 0.693147180559945286226764 * e; - if (xisinf(d)) x = rtengine::RT_INFINITY; + if (xispinf(d)) x = rtengine::RT_INFINITY; if (d < 0) x = rtengine::RT_NAN; if (d == 0) x = -rtengine::RT_INFINITY; @@ -864,7 +864,7 @@ __inline double xlog10(double a) { double2 d = mul_dd(logk(a), dd(0.43429448190325176116, 6.6494347733425473126e-17)); double x = d.x + d.y; - if (xisinf(a)) x = rtengine::RT_INFINITY; + if (xispinf(a)) x = rtengine::RT_INFINITY; if (a < 0) x = rtengine::RT_NAN; if (a == 0) x = -rtengine::RT_INFINITY; @@ -875,7 +875,7 @@ __inline double xlog1p(double a) { double2 d = logk2(add2_ss(a, 1)); double x = d.x + d.y; - if (xisinf(a)) x = rtengine::RT_INFINITY; + if (xispinf(a)) x = rtengine::RT_INFINITY; if (a < -1) x = rtengine::RT_NAN; if (a == -1) x = -rtengine::RT_INFINITY; @@ -894,6 +894,15 @@ __inline double xlog1p(double a) { #define R_LN2f 1.442695040888963407359924681001892137426645954152985934135449406931f +#ifdef __SSE2__ +__inline int xrintf(float x) { + return _mm_cvt_ss2si(_mm_set_ss(x)); +} +#else +__inline int xrintf(float x) { + return x + (x < 0 ? -0.5f : 0.5f); +} +#endif __inline int32_t floatToRawIntBits(float d) { union { float f; @@ -980,7 +989,7 @@ __inline float xsinf(float d) { int q; float u, s; - q = rint(d * rtengine::RT_1_PI_F); + q = xrintf(d * rtengine::RT_1_PI_F); d = mlaf(q, -PI4_Af*4, d); d = mlaf(q, -PI4_Bf*4, d); @@ -1009,7 +1018,7 @@ __inline float xcosf(float d) { int q; float u, s; - q = 1 + 2*rint(d * rtengine::RT_1_PI_F - 0.5f); + q = 1 + 2*xrintf(d * rtengine::RT_1_PI_F - 0.5f); d = mlaf(q, -PI4_Af*2, d); d = mlaf(q, -PI4_Bf*2, d); @@ -1041,7 +1050,7 @@ __inline float2 xsincosf(float d) { float u, s, t; float2 r; - q = rint(d * rtengine::RT_2_PI_F); + q = xrintf(d * rtengine::RT_2_PI_F); s = d; @@ -1083,7 +1092,7 @@ __inline float xtanf(float d) { int q; float u, s, x; - q = rint(d * (float)(2 * rtengine::RT_1_PI)); + q = xrintf(d * (float)(2 * rtengine::RT_1_PI)); x = d; @@ -1199,17 +1208,41 @@ __inline float xlogf(float d) { x = x * t + 0.693147180559945286226764f * e; - if (xisinff(d)) x = rtengine::RT_INFINITY_F; + if (xispinff(d)) x = rtengine::RT_INFINITY_F; if (d < 0) x = rtengine::RT_NAN_F; if (d == 0) x = -rtengine::RT_INFINITY_F; return x; } +__inline float xlogf1(float d) { // does xlogf(vmaxf(d, 1.f)) but faster + float x, x2, t, m; + int e; + + e = ilogbp1f(d * 0.7071f); + m = ldexpkf(d, -e); + + x = (m-1.0f) / (m+1.0f); + x2 = x * x; + + t = 0.2371599674224853515625f; + t = mlaf(t, x2, 0.285279005765914916992188f); + t = mlaf(t, x2, 0.400005519390106201171875f); + t = mlaf(t, x2, 0.666666567325592041015625f); + t = mlaf(t, x2, 2.0f); + + x = x * t + 0.693147180559945286226764f * e; + + if (xispinff(d)) x = rtengine::RT_INFINITY_F; + if (d <= 1.f) x = 0; + + return x; +} + __inline float xexpf(float d) { if(d<=-104.0f) return 0.0f; - int q = rint(d * R_LN2f); + int q = xrintf(d * R_LN2f); float s, u; s = mlaf(q, -L2Uf, d); diff --git a/rtengine/sleefsseavx.c b/rtengine/sleefsseavx.c index 1982c7c4c..0af516f9b 100644 --- a/rtengine/sleefsseavx.c +++ b/rtengine/sleefsseavx.c @@ -1253,6 +1253,30 @@ static INLINE vfloat xlogf(vfloat d) { return x; } +static INLINE vfloat xlogf1(vfloat d) { // does xlogf(vmaxf(d, 1.f)) but faster + vfloat x, x2, t, m; + vint2 e; + + e = vilogbp1f(vmulf(d, vcast_vf_f(0.7071f))); + m = vldexpf(d, vsubi2(vcast_vi2_i(0), e)); + + x = vdivf(vaddf(vcast_vf_f(-1.0f), m), vaddf(vcast_vf_f(1.0f), m)); + x2 = vmulf(x, x); + + t = vcast_vf_f(0.2371599674224853515625f); + t = vmlaf(t, x2, vcast_vf_f(0.285279005765914916992188f)); + t = vmlaf(t, x2, vcast_vf_f(0.400005519390106201171875f)); + t = vmlaf(t, x2, vcast_vf_f(0.666666567325592041015625f)); + t = vmlaf(t, x2, vcast_vf_f(2.0f)); + + x = vaddf(vmulf(x, t), vmulf(vcast_vf_f(0.693147180559945286226764f), vcast_vf_vi2(e))); + + x = vself(vmaskf_ispinf(d), vcast_vf_f(INFINITYf), x); + x = vselfnotzero(vmaskf_le(d, vcast_vf_f(1.f)), x); + + return x; +} + static INLINE vfloat xlogf0(vfloat d) { vfloat x, x2, t, m; vint2 e; diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index b00032191..0a9b81112 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -1492,9 +1492,9 @@ void CropWindow::expose (Cairo::RefPtr cr) const float kernel_size2 = SQR(2.f * blur_radius2 + 1.f); // count of pixels in the small blur kernel const float rkernel_size2 = 1.0f / kernel_size2; // reciprocal of kernel_size to avoid divisions - // aloocate buffer for precalculated Luminance + // allocate buffer for precalculated Luminance float* tmpL = (float*)malloc(bHeight * bWidth * sizeof(float) ); - // aloocate buffers for sums and sums of squares of small kernel + // allocate buffers for sums and sums of squares of small kernel float* tmpLsum = (float*)malloc((bHeight) * (bWidth) * sizeof(float) ); float* tmpLsumSq = (float*)malloc((bHeight) * (bWidth) * sizeof(float) ); float* tmpstdDev2 = (float*)malloc((bHeight) * (bWidth) * sizeof(float) ); @@ -1631,7 +1631,7 @@ void CropWindow::expose (Cairo::RefPtr cr) && stdDev_L2 > stdDev_L //this is the key to select fine detail within lower contrast on larger scale && stdDev_L > focus_threshby10 //options.highlightThreshold ) { - // transpareny depends on sdtDev_L2 and maxstdDev_L2 + // transparency depends on sdtDev_L2 and maxstdDev_L2 float transparency = 1.f - std::min(stdDev_L2 / maxstdDev_L2, 1.0f) ; // first row of circle guint8* currtmp = &curr[0] + (-3 * pixRowStride); diff --git a/rtgui/editwidgets.h b/rtgui/editwidgets.h index 55b4ca3cc..0fa7a91bf 100644 --- a/rtgui/editwidgets.h +++ b/rtgui/editwidgets.h @@ -55,7 +55,7 @@ class RTSurface; * - drag1 * - button1Released * - * Actually, only curves does use this class, and everything is handled for curve implementor (as much as possible). + * Actually, only curves does use this class, and everything is handled for curve implementer (as much as possible). * See the curve's class documentation to see how to implement the curve's pipette feature. * * ### Event handling diff --git a/rtgui/epd.cc b/rtgui/epd.cc index 307790ff7..b13effba3 100644 --- a/rtgui/epd.cc +++ b/rtgui/epd.cc @@ -69,17 +69,18 @@ void EdgePreservingDecompositionUI::read(const ProcParams *pp, const ParamsEdite setEnabled(pp->epd.enabled); strength->set_sensitive (true); - - if(pp->wavelet.enabled) { - if(pp->wavelet.tmrs == 0) { + gamma->set_sensitive (true); +/* + if(pp->wavelet.enabled) { + if(pp->wavelet.tmrs == 0 || pp->wavelet.TMmethod == "cont") { strength->set_sensitive (true); gamma->set_sensitive (true); - } else { + } else if(pp->wavelet.tmrs != 0 && pp->wavelet.TMmethod == "tm") { strength->set_sensitive (false); gamma->set_sensitive (false); } } - +*/ strength->setValue(pp->epd.strength); gamma->setValue(pp->epd.gamma); edgeStopping->setValue(pp->epd.edgeStopping); @@ -98,17 +99,18 @@ void EdgePreservingDecompositionUI::write(ProcParams *pp, ParamsEdited *pedited) pp->epd.reweightingIterates = reweightingIterates->getValue(); pp->epd.enabled = getEnabled(); strength->set_sensitive (true); - - if(pp->wavelet.enabled) { - if(pp->wavelet.tmrs == 0) { + gamma->set_sensitive (true); +/* + if(pp->wavelet.enabled) { + if(pp->wavelet.tmrs == 0 || pp->wavelet.TMmethod == "cont") { strength->set_sensitive (true); gamma->set_sensitive (true); - } else { + } else if(pp->wavelet.tmrs != 0 && pp->wavelet.TMmethod == "tm") { strength->set_sensitive (false); gamma->set_sensitive (false); } } - +*/ if(pedited) { pedited->epd.strength = strength->getEditedState(); pedited->epd.gamma = gamma->getEditedState(); diff --git a/rtgui/filterpanel.cc b/rtgui/filterpanel.cc index 301a7b188..2c4fc52d2 100644 --- a/rtgui/filterpanel.cc +++ b/rtgui/filterpanel.cc @@ -14,7 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . + * along with RawTherapee. If not, see . */ #include "filterpanel.h" #include "multilangmgr.h" @@ -107,8 +107,8 @@ FilterPanel::FilterPanel () : listener (nullptr) scamera->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); scamera->set_size_request(-1, 80); scamera->add(*camera); - cvb->pack_start (*scamera, Gtk::PACK_SHRINK, 0); - pack_start (*cvb, Gtk::PACK_SHRINK, 4); + cvb->pack_start (*scamera, Gtk::PACK_EXPAND_WIDGET, 0); + pack_start (*cvb, Gtk::PACK_EXPAND_WIDGET, 4); enaLens = Gtk::manage(new Gtk::CheckButton(M("EXIFFILTER_LENS") + ":")); Gtk::VBox* lvb = Gtk::manage(new Gtk::VBox ()); @@ -119,8 +119,8 @@ FilterPanel::FilterPanel () : listener (nullptr) slens->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); slens->set_size_request(-1, 80); slens->add(*lens); - lvb->pack_start (*slens, Gtk::PACK_SHRINK, 0); - pack_start (*lvb, Gtk::PACK_SHRINK, 4); + lvb->pack_start (*slens, Gtk::PACK_EXPAND_WIDGET, 0); + pack_start (*lvb, Gtk::PACK_EXPAND_WIDGET, 4); enaFiletype = Gtk::manage(new Gtk::CheckButton(M("EXIFFILTER_FILETYPE") + ":")); Gtk::VBox* ftvb = Gtk::manage(new Gtk::VBox ()); @@ -131,8 +131,8 @@ FilterPanel::FilterPanel () : listener (nullptr) sfiletype->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); sfiletype->set_size_request(-1, 80); sfiletype->add(*filetype); - ftvb->pack_start (*sfiletype, Gtk::PACK_SHRINK, 0); - pack_start (*ftvb, Gtk::PACK_SHRINK, 4); + ftvb->pack_start (*sfiletype, Gtk::PACK_EXPAND_WIDGET, 0); + pack_start (*ftvb, Gtk::PACK_EXPAND_WIDGET, 4); // add panel ending Gtk::VBox* vboxpe = Gtk::manage (new Gtk::VBox ()); diff --git a/rtgui/lensgeom.cc b/rtgui/lensgeom.cc index 76e0635eb..762726107 100644 --- a/rtgui/lensgeom.cc +++ b/rtgui/lensgeom.cc @@ -17,6 +17,8 @@ * along with RawTherapee. If not, see . */ #include "lensgeom.h" + +#include "eventmapper.h" #include "guiutils.h" #include "rtimage.h" @@ -28,6 +30,18 @@ using namespace rtengine::procparams; LensGeometry::LensGeometry () : FoldableToolPanel(this, "lensgeom", M("TP_LENSGEOM_LABEL")), rlistener(nullptr), lastFill(false) { + auto m = ProcEventMapper::getInstance(); + EvTransMethod = m->newEvent(TRANSFORM, "HISTORY_MSG_TRANS_METHOD"); + + Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); + hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") + ": ")), Gtk::PACK_SHRINK, 4); + method = Gtk::manage (new MyComboBoxText ()); + method->append(M("TP_LENSGEOM_LOG")); + method->append(M("TP_LENSGEOM_LIN")); + method->set_active(0); + hb1->pack_end (*method, Gtk::PACK_EXPAND_WIDGET, 4); + pack_start( *hb1, Gtk::PACK_SHRINK, 4); + fill = Gtk::manage (new Gtk::CheckButton (M("TP_LENSGEOM_FILL"))); pack_start (*fill); @@ -39,8 +53,9 @@ LensGeometry::LensGeometry () : FoldableToolPanel(this, "lensgeom", M("TP_LENSGE packBox = Gtk::manage (new ToolParamBlock ()); pack_start (*packBox); - autoCrop->signal_pressed().connect( sigc::mem_fun(*this, &LensGeometry::autoCropPressed) ); - fillConn = fill->signal_toggled().connect( sigc::mem_fun(*this, &LensGeometry::fillPressed) ); + method->connect(method->signal_changed().connect(sigc::mem_fun(*this, &LensGeometry::methodChanged))); + autoCrop->signal_pressed().connect(sigc::mem_fun(*this, &LensGeometry::autoCropPressed)); + fillConn = fill->signal_toggled().connect(sigc::mem_fun(*this, &LensGeometry::fillPressed)); fill->set_active (true); show_all (); @@ -55,8 +70,14 @@ void LensGeometry::read (const ProcParams* pp, const ParamsEdited* pedited) { disableListener (); + method->block (true); + method->set_active(pp->commonTrans.method == "log" ? 0 : 1); if (pedited) { + if(!pedited->commonTrans.method) { + method->set_active_text(M("GENERAL_UNCHANGED")); + } + fill->set_inconsistent (!pedited->commonTrans.autofill); } @@ -67,15 +88,20 @@ void LensGeometry::read (const ProcParams* pp, const ParamsEdited* pedited) lastFill = pp->commonTrans.autofill; + method->block (false); enableListener (); } void LensGeometry::write (ProcParams* pp, ParamsEdited* pedited) { - + int currentRow = method->get_active_row_number(); + if( currentRow >= 0 && method->get_active_text() != M("GENERAL_UNCHANGED")) { + pp->commonTrans.method = currentRow == 0 ? "log" : "lin"; + } pp->commonTrans.autofill = fill->get_active (); if (pedited) { + pedited->commonTrans.method = method->get_active_text() != M("GENERAL_UNCHANGED"); pedited->commonTrans.autofill = !fill->get_inconsistent(); } } @@ -115,6 +141,14 @@ void LensGeometry::fillPressed () } } +void LensGeometry::methodChanged () +{ + + if (listener && method->get_active_row_number() >= 0) { + listener->panelChanged(EvTransMethod, method->get_active_text()); + } +} + void LensGeometry::setBatchMode (bool batchMode) { diff --git a/rtgui/lensgeom.h b/rtgui/lensgeom.h index 18b31a619..73c28b006 100644 --- a/rtgui/lensgeom.h +++ b/rtgui/lensgeom.h @@ -29,6 +29,7 @@ class LensGeometry final : { protected: + MyComboBoxText* method; Gtk::Button* autoCrop; LensGeomListener* rlistener; Gtk::CheckButton* fill; @@ -36,6 +37,7 @@ protected: sigc::connection fillConn; ToolParamBlock* packBox; + rtengine::ProcEvent EvTransMethod; public: LensGeometry (); @@ -50,6 +52,7 @@ public: void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; void setBatchMode (bool batchMode) override; + void methodChanged(); void fillPressed (); void autoCropPressed (); void setLensGeomListener (LensGeomListener* l) diff --git a/rtgui/lensprofile.cc b/rtgui/lensprofile.cc index be21512d5..1a8391f66 100644 --- a/rtgui/lensprofile.cc +++ b/rtgui/lensprofile.cc @@ -586,6 +586,9 @@ void LensProfilePanel::onCorrModeChanged(const Gtk::RadioButton* rbChanged) LensProfilePanel::LFDbHelper::LFDbHelper() { + lensfunCameraModel = Gtk::TreeStore::create(lensfunModelCam); + lensfunLensModel = Gtk::TreeStore::create(lensfunModelLens); + #ifdef _OPENMP #pragma omp parallel sections if (!settings->verbose) #endif @@ -594,14 +597,12 @@ LensProfilePanel::LFDbHelper::LFDbHelper() #pragma omp section #endif { - lensfunCameraModel = Gtk::TreeStore::create(lensfunModelCam); fillLensfunCameras(); } #ifdef _OPENMP #pragma omp section #endif { - lensfunLensModel = Gtk::TreeStore::create(lensfunModelLens); fillLensfunLenses(); } } diff --git a/rtgui/options.cc b/rtgui/options.cc index f5b6b5b60..dcb16e1ea 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -225,7 +225,7 @@ Glib::ustring Options::getPreferredProfilePath() * *@param profName path + filename of the procparam to look for. A filename without path can be provided for backward compatibility. * In this case, this parameter will be updated with the new format. - *@return Send back the absolute path of the given filename or "Neutral" if "Neutral" has been set to profName. Implementor will have + *@return Send back the absolute path of the given filename or "Neutral" if "Neutral" has been set to profName. Implementer will have * to test for this particular value. If the absolute path is invalid (e.g. the file doesn't exist), it will return an empty string. */ Glib::ustring Options::findProfilePath(Glib::ustring &profName) diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index b78033796..39cbf082b 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -321,6 +321,7 @@ void ParamsEdited::set(bool v) coarse.rotate = v; coarse.hflip = v; coarse.vflip = v; + commonTrans.method = v; commonTrans.autofill = v; rotate.degree = v; distortion.amount = v; @@ -918,6 +919,7 @@ void ParamsEdited::initFrom(const std::vector& coarse.rotate = coarse.rotate && p.coarse.rotate == other.coarse.rotate; coarse.hflip = coarse.hflip && p.coarse.hflip == other.coarse.hflip; coarse.vflip = coarse.vflip && p.coarse.vflip == other.coarse.vflip; + commonTrans.method = commonTrans.method && p.commonTrans.method == other.commonTrans.method; commonTrans.autofill = commonTrans.autofill && p.commonTrans.autofill == other.commonTrans.autofill; rotate.degree = rotate.degree && p.rotate.degree == other.rotate.degree; distortion.amount = distortion.amount && p.distortion.amount == other.distortion.amount; @@ -2293,6 +2295,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.coarse.vflip = mods.coarse.vflip; } + if (commonTrans.method) { + toEdit.commonTrans.method = mods.commonTrans.method; + } + if (commonTrans.autofill) { toEdit.commonTrans.autofill = mods.commonTrans.autofill; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index b7ae96de1..2a920a4f3 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -365,6 +365,7 @@ struct CoarseTransformParamsEdited { }; struct CommonTransformParamsEdited { + bool method; bool autofill; }; diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index 5ab3ab85d..514685a16 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -383,8 +383,13 @@ RTWindow::RTWindow () iccProfileCreator->set_tooltip_markup (M ("MAIN_BUTTON_ICCPROFCREATOR")); iccProfileCreator->signal_clicked().connect ( sigc::mem_fun (*this, &RTWindow::showICCProfileCreator) ); - //Gtk::LinkButton* rtWeb = Gtk::manage (new Gtk::LinkButton ("http://rawtherapee.com")); // unused... but fail to be linked anyway !? - //Gtk::Button* preferences = Gtk::manage (new Gtk::Button (M("MAIN_BUTTON_PREFERENCES")+"...")); + Gtk::Button* helpBtn = Gtk::manage (new Gtk::Button ()); + setExpandAlignProperties (helpBtn, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + helpBtn->set_relief(Gtk::RELIEF_NONE); + helpBtn->set_image (*Gtk::manage (new RTImage ("questionmark.png"))); + helpBtn->set_tooltip_markup (M ("GENERAL_HELP")); + helpBtn->signal_clicked().connect (sigc::mem_fun (*this, &RTWindow::showRawPedia)); + Gtk::Button* preferences = Gtk::manage (new Gtk::Button ()); setExpandAlignProperties (preferences, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); preferences->set_relief(Gtk::RELIEF_NONE); @@ -392,7 +397,6 @@ RTWindow::RTWindow () preferences->set_tooltip_markup (M ("MAIN_BUTTON_PREFERENCES")); preferences->signal_clicked().connect ( sigc::mem_fun (*this, &RTWindow::showPreferences) ); - //btn_fullscreen = Gtk::manage( new Gtk::Button(M("MAIN_BUTTON_FULLSCREEN"))); btn_fullscreen = Gtk::manage ( new Gtk::Button()); setExpandAlignProperties (btn_fullscreen, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); btn_fullscreen->set_relief(Gtk::RELIEF_NONE); @@ -414,6 +418,7 @@ RTWindow::RTWindow () actionGrid->set_orientation (Gtk::ORIENTATION_VERTICAL); actionGrid->attach_next_to (prProgBar, Gtk::POS_BOTTOM, 1, 1); actionGrid->attach_next_to (*iccProfileCreator, Gtk::POS_BOTTOM, 1, 1); + actionGrid->attach_next_to (*helpBtn, Gtk::POS_BOTTOM, 1, 1); actionGrid->attach_next_to (*preferences, Gtk::POS_BOTTOM, 1, 1); actionGrid->attach_next_to (*btn_fullscreen, Gtk::POS_BOTTOM, 1, 1); mainNB->set_action_widget (actionGrid, Gtk::PACK_END); @@ -422,6 +427,7 @@ RTWindow::RTWindow () actionGrid->set_orientation (Gtk::ORIENTATION_HORIZONTAL); actionGrid->attach_next_to (prProgBar, Gtk::POS_RIGHT, 1, 1); actionGrid->attach_next_to (*iccProfileCreator, Gtk::POS_RIGHT, 1, 1); + actionGrid->attach_next_to (*helpBtn, Gtk::POS_RIGHT, 1, 1); actionGrid->attach_next_to (*preferences, Gtk::POS_RIGHT, 1, 1); actionGrid->attach_next_to (*btn_fullscreen, Gtk::POS_RIGHT, 1, 1); mainNB->set_action_widget (actionGrid, Gtk::PACK_END); @@ -913,6 +919,12 @@ void RTWindow::writeToolExpandedStatus (std::vector &tpOpen) } +void RTWindow::showRawPedia() +{ + GError* gerror = nullptr; + gtk_show_uri(nullptr, "https://rawpedia.rawtherapee.com/", GDK_CURRENT_TIME, &gerror); +} + void RTWindow::showICCProfileCreator () { ICCProfileCreator *iccpc = new ICCProfileCreator (this); diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index 100ddf636..4791ac6c1 100644 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -90,6 +90,7 @@ public: bool on_window_state_event (GdkEventWindowState* event) override; void on_mainNB_switch_page (Gtk::Widget* widget, guint page_num); + void showRawPedia(); void showICCProfileCreator (); void showPreferences (); void on_realize () override;