diff --git a/rtdata/languages/default b/rtdata/languages/default
index 8ff9f25c4..82ede29d7 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -1420,6 +1420,7 @@ HISTORY_MSG_FILMNEGATIVE_VALUES;Film negative values
HISTORY_MSG_GAMUTMUNSEL;Gamut-Munsell
HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
HISTORY_MSG_HLBL;Color propagation - blur
+HISTORY_MSG_HLTH;Inpaint opposed - gain threshold
HISTORY_MSG_ICL_LABGRIDCIEXY;Cie xy
HISTORY_MSG_ICM_AINTENT;Abstract profile intent
HISTORY_MSG_ICM_BLUX;Primaries Blue X
@@ -1986,6 +1987,7 @@ PREFERENCES_STARTUPIMDIR;Image Directory at Startup
PREFERENCES_TAB_BROWSER;File Browser
PREFERENCES_TAB_COLORMGR;Color Management
PREFERENCES_TAB_DYNAMICPROFILE;Dynamic Profile Rules
+PREFERENCES_TAB_FAVORITES;Favorites
PREFERENCES_TAB_GENERAL;General
PREFERENCES_TAB_IMPROC;Image Processing
PREFERENCES_TAB_PERFORMANCE;Performance
@@ -1994,6 +1996,12 @@ PREFERENCES_THUMBNAIL_INSPECTOR_JPEG;Embedded JPEG preview
PREFERENCES_THUMBNAIL_INSPECTOR_MODE;Image to show
PREFERENCES_THUMBNAIL_INSPECTOR_RAW;Neutral raw rendering
PREFERENCES_THUMBNAIL_INSPECTOR_RAW_IF_NO_JPEG_FULLSIZE;Embedded JPEG if fullsize, neutral raw otherwise
+PREFERENCES_TOOLPANEL_AVAILABLETOOLS;Available Tools
+PREFERENCES_TOOLPANEL_CLONE_FAVORITES;Keep favorite tools in original locations
+PREFERENCES_TOOLPANEL_CLONE_FAVORITES_TOOLTIP;If set, favorite tools will appear in both the favorites tab and their original tabs.\n\nNote: Enabling this option may result in a slight delay when switching tabs.
+PREFERENCES_TOOLPANEL_FAVORITE;Favorite
+PREFERENCES_TOOLPANEL_FAVORITESPANEL;Favorites Panel
+PREFERENCES_TOOLPANEL_TOOL;Tool
PREFERENCES_TP_LABEL;Tool panel:
PREFERENCES_TP_VSCROLLBAR;Hide vertical scrollbar
PREFERENCES_USEBUNDLEDPROFILES;Use bundled profiles
@@ -2522,8 +2530,10 @@ TP_GRADIENT_STRENGTH_TOOLTIP;Filter strength in stops.
TP_HLREC_BLEND;Blend
TP_HLREC_CIELAB;CIELab Blending
TP_HLREC_COLOR;Color Propagation
+TP_HLREC_COLOROPP;Inpaint Opposed
TP_HLREC_ENA_TOOLTIP;Could be activated by Auto Levels.
TP_HLREC_HLBLUR;Blur
+TP_HLREC_HLTH;Gain threshold
TP_HLREC_LABEL;Highlight reconstruction
TP_HLREC_LUMINANCE;Luminance Recovery
TP_HLREC_METHOD;Method:
diff --git a/rtdata/profiles/Auto-Matched Curve - ISO High.pp3 b/rtdata/profiles/Auto-Matched Curve - ISO High.pp3
index 99f0af8fe..16c9a71f5 100644
--- a/rtdata/profiles/Auto-Matched Curve - ISO High.pp3
+++ b/rtdata/profiles/Auto-Matched Curve - ISO High.pp3
@@ -4,7 +4,7 @@ HistogramMatching=true
[HLRecovery]
Enabled=true
-Method=Blend
+Method=Coloropp
[Directional Pyramid Denoising]
Enabled=true
diff --git a/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3 b/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3
index c94077b21..e6c7fb96c 100644
--- a/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3
+++ b/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3
@@ -4,7 +4,7 @@ HistogramMatching=true
[HLRecovery]
Enabled=true
-Method=Blend
+Method=Coloropp
[LensProfile]
LcMode=lfauto
diff --git a/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3 b/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3
index f9196bb30..ffb5587b9 100644
--- a/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3
+++ b/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3
@@ -4,7 +4,7 @@ HistogramMatching=true
[HLRecovery]
Enabled=true
-Method=Blend
+Method=Coloropp
[Directional Pyramid Denoising]
Enabled=true
diff --git a/rtdata/profiles/Film Negative - Black and White.pp3 b/rtdata/profiles/Film Negative - Black and White.pp3
index ad2a38e1e..3bebe7e3c 100644
--- a/rtdata/profiles/Film Negative - Black and White.pp3
+++ b/rtdata/profiles/Film Negative - Black and White.pp3
@@ -11,7 +11,7 @@ Curve2=1;0;0;0.0397505754145333;0.020171771436200074;0.54669745433149319;0.69419
[HLRecovery]
Enabled=false
-Method=Blend
+Method=Coloropp
[Black & White]
Enabled=true
diff --git a/rtdata/profiles/Film Negative.pp3 b/rtdata/profiles/Film Negative.pp3
index 0ecac1d33..e76c61866 100644
--- a/rtdata/profiles/Film Negative.pp3
+++ b/rtdata/profiles/Film Negative.pp3
@@ -11,7 +11,7 @@ Curve2=1;0;0;0.0397505754145333;0.020171771436200074;0.54669745433149319;0.69419
[HLRecovery]
Enabled=false
-Method=Blend
+Method=Coloropp
[Crop]
FixedRatio=false
diff --git a/rtdata/profiles/Pop/Pop 1.pp3 b/rtdata/profiles/Pop/Pop 1.pp3
index 2152a268b..cbdf4ab5b 100644
--- a/rtdata/profiles/Pop/Pop 1.pp3
+++ b/rtdata/profiles/Pop/Pop 1.pp3
@@ -19,7 +19,7 @@ Curve2=0;
[HLRecovery]
Enabled=true
-Method=Blend
+Method=Coloropp
[Luminance Curve]
Enabled=true
diff --git a/rtdata/profiles/Pop/Pop 2 Lab.pp3 b/rtdata/profiles/Pop/Pop 2 Lab.pp3
index 796aeb5ba..f4c01fd1b 100644
--- a/rtdata/profiles/Pop/Pop 2 Lab.pp3
+++ b/rtdata/profiles/Pop/Pop 2 Lab.pp3
@@ -19,7 +19,7 @@ Curve2=0;
[HLRecovery]
Enabled=true
-Method=Blend
+Method=Coloropp
[Luminance Curve]
Enabled=true
diff --git a/rtdata/profiles/Pop/Pop 3 Skin.pp3 b/rtdata/profiles/Pop/Pop 3 Skin.pp3
index 650b2e189..ebce37b58 100644
--- a/rtdata/profiles/Pop/Pop 3 Skin.pp3
+++ b/rtdata/profiles/Pop/Pop 3 Skin.pp3
@@ -19,7 +19,7 @@ Curve2=0;
[HLRecovery]
Enabled=true
-Method=Blend
+Method=Coloropp
[Luminance Curve]
Enabled=true
diff --git a/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3 b/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3
index 9faa32a0a..1e3527ceb 100644
--- a/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3
+++ b/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3
@@ -19,7 +19,7 @@ Curve2=0;
[HLRecovery]
Enabled=true
-Method=Blend
+Method=Coloropp
[Black & White]
Enabled=true
diff --git a/rtdata/profiles/Standard Film Curve - ISO High.pp3 b/rtdata/profiles/Standard Film Curve - ISO High.pp3
index 4dd3a9b1d..42bbed6d3 100644
--- a/rtdata/profiles/Standard Film Curve - ISO High.pp3
+++ b/rtdata/profiles/Standard Film Curve - ISO High.pp3
@@ -6,7 +6,7 @@ Curve=1;0;0;0.11;0.089999999999999997;0.32000000000000001;0.42999999999999999;0.
[HLRecovery]
Enabled=true
-Method=Blend
+Method=Coloropp
[Directional Pyramid Denoising]
Enabled=true
diff --git a/rtdata/profiles/Standard Film Curve - ISO Low.pp3 b/rtdata/profiles/Standard Film Curve - ISO Low.pp3
index 45fcca730..342b1c8d3 100644
--- a/rtdata/profiles/Standard Film Curve - ISO Low.pp3
+++ b/rtdata/profiles/Standard Film Curve - ISO Low.pp3
@@ -6,7 +6,7 @@ Curve=1;0;0;0.11;0.089999999999999997;0.32000000000000001;0.42999999999999999;0.
[HLRecovery]
Enabled=true
-Method=Blend
+Method=Coloropp
[LensProfile]
LcMode=lfauto
diff --git a/rtdata/profiles/Standard Film Curve - ISO Medium.pp3 b/rtdata/profiles/Standard Film Curve - ISO Medium.pp3
index 4aff630f5..f3b292094 100644
--- a/rtdata/profiles/Standard Film Curve - ISO Medium.pp3
+++ b/rtdata/profiles/Standard Film Curve - ISO Medium.pp3
@@ -6,7 +6,7 @@ Curve=1;0;0;0.11;0.089999999999999997;0.32000000000000001;0.42999999999999999;0.
[HLRecovery]
Enabled=true
-Method=Blend
+Method=Coloropp
[Directional Pyramid Denoising]
Enabled=true
diff --git a/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css b/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css
index dd7be3bfd..07a0bd65d 100644
--- a/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css
+++ b/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css
@@ -760,6 +760,23 @@ button.radio#histButton:hover {
margin-right: 0.25em;
}
+/* ExpanderContents is just a logical container. Don't add additional spacing. */
+#ExpanderBox > .ExpanderContents > * {
+ margin: 0;
+ min-height: 0;
+ padding: 0;
+}
+
+/* For sub-tools containers that go below another widget, add some margin
+ * between them if the container has children. */
+#MyExpander .SubToolsContainer:not(:first-child) > :first-child {
+ margin-top: 0.1666666666666666em;
+}
+
+#MyExpander .SubToolsContainer {
+ min-height: 0;
+}
+
/* Tool background */
#ExpanderBox > box, #ExpanderBox > grid {
background-color: #363636;
@@ -808,9 +825,11 @@ button.radio#histButton:hover {
}
#LocallabToolPanel > box > checkbutton, #LocallabToolPanel > box > box, #LocallabToolPanel > grid > checkbutton, #LocallabToolPanel > box > grid, #LocallabToolPanel > grid > grid, #LocallabToolPanel frame > box > grid, #LocallabToolPanel frame > grid > grid, #LocallabToolPanel frame > grid > box,
-#ExpanderBox > box > checkbutton, #ExpanderBox > box > box, #ExpanderBox > grid > checkbutton, #ExpanderBox > box > grid, #ExpanderBox > grid > grid, #ExpanderBox frame > box > grid, #ExpanderBox frame > grid > grid, #ExpanderBox frame > grid > box,
-#ExpanderBox2 > box > checkbutton, #ExpanderBox2 > box > box, #ExpanderBox2 > grid > checkbutton, #ExpanderBox2 > box > grid, #ExpanderBox2 > grid > grid, #ExpanderBox2 frame > box > grid, #ExpanderBox2 frame > grid > grid, #ExpanderBox2 frame > grid > box,
-#ExpanderBox3 > box > checkbutton, #ExpanderBox3 > box > box, #ExpanderBox3 > grid > checkbutton, #ExpanderBox3 > box > grid, #ExpanderBox3 > grid > grid, #ExpanderBox3 frame > box > grid, #ExpanderBox3 frame > grid > grid, #ExpanderBox3 frame > grid > box {
+#ExpanderBox > .ExpanderContents > box:not(.SubToolsContainer) > checkbutton, #ExpanderBox > .ExpanderContents > box:not(.SubToolsContainer) > box, #ExpanderBox > .ExpanderContents > grid > checkbutton, #ExpanderBox > .ExpanderContents > box:not(.SubToolsContainer) > grid, #ExpanderBox > .ExpanderContents > grid > grid, #ExpanderBox frame > box > grid, #ExpanderBox frame > grid > grid, #ExpanderBox frame > grid > box,
+#ExpanderBox2 > .ExpanderContents > box:not(.SubToolsContainer) > checkbutton, #ExpanderBox2 > .ExpanderContents > box:not(.SubToolsContainer) > box, #ExpanderBox2 > .ExpanderContents > grid > checkbutton, #ExpanderBox2 > .ExpanderContents > box:not(.SubToolsContainer) > grid, #ExpanderBox2 > .ExpanderContents > grid > grid, #ExpanderBox2 frame > box > grid, #ExpanderBox2 frame > grid > grid, #ExpanderBox2 frame > grid > box,
+#ExpanderBox2 > box:not(.ExpanderContents) > checkbutton, #ExpanderBox2 > box:not(.ExpanderContents) > box, #ExpanderBox2 > grid > checkbutton, #ExpanderBox2 > box:not(.ExpanderContents) > grid, #ExpanderBox2 > grid > grid, #ExpanderBox2 frame > box > grid, #ExpanderBox2 frame > grid > grid, #ExpanderBox2 frame > grid > box,
+#ExpanderBox3 > .ExpanderContents > box:not(.SubToolsContainer) > checkbutton, #ExpanderBox3 > .ExpanderContents > box:not(.SubToolsContainer) > box, #ExpanderBox3 > .ExpanderContents > grid > checkbutton, #ExpanderBox3 > .ExpanderContents > box:not(.SubToolsContainer) > grid, #ExpanderBox3 > .ExpanderContents > grid > grid, #ExpanderBox3 frame > box > grid, #ExpanderBox3 frame > grid > grid, #ExpanderBox3 frame > grid > box,
+#ExpanderBox3 > box:not(.ExpanderContents) > checkbutton, #ExpanderBox3 > box:not(.ExpanderContents) > box, #ExpanderBox3 > grid > checkbutton, #ExpanderBox3 > box:not(.ExpanderContents) > grid, #ExpanderBox3 > grid > grid, #ExpanderBox3 frame > box > grid, #ExpanderBox3 frame > grid > grid, #ExpanderBox3 frame > grid > box {
margin-top: 0.1666666666666666em;
}
@@ -1099,6 +1118,10 @@ dialog frame > label:not(.dummy) {
min-width: 25em;
}
+#ToolPanelNotebook .PanelEnding {
+ margin-top: 4px;
+}
+
#ToolPanelNotebook header {
background-color: #383838;
border-color: #262626;
@@ -1395,4 +1418,4 @@ progressbar progress {
.grid-spacing > * {
margin: 0.1666666666666666em;
-}
\ No newline at end of file
+}
diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css
index 57c6db148..2e314510a 100644
--- a/rtdata/themes/RawTherapee-GTK3-20_.css
+++ b/rtdata/themes/RawTherapee-GTK3-20_.css
@@ -758,7 +758,7 @@ button.radio#histButton:hover {
#MyExpander:first-child {
border-top: none;
}
-#MyExpander:nth-last-child(2),
+#MyExpander:nth-last-child(1),
#MyExpander #MyExpander:nth-last-child(1) {
border-bottom: 0.0833333333333333em solid rgba(0,0,0,0.3);
}
@@ -766,6 +766,29 @@ button.radio#histButton:hover {
border-bottom: none;
}
+/* ExpanderContents is just a logical container. Don't add additional spacing. */
+#ExpanderBox > .ExpanderContents > * {
+ margin: 0;
+ min-height: 0;
+ padding: 0;
+}
+
+/* For sub-tools containers that go below another widget, add some margin
+ * between them if the container has children. */
+#MyExpander .SubToolsContainer:not(:first-child) > :first-child {
+ margin-top: 0.3333333333333333em;
+}
+
+#MyExpander .SubToolsContainer {
+ min-height: 0;
+}
+
+.SubToolsContainer > #MyExpander,
+.ToolParamBlock > #MyExpander,
+.ExpanderContents,
+#MyExpander .ToolParamBlock {
+ margin: 0;
+}
/* Tool background */
#ExpanderBox > box,
@@ -1046,6 +1069,10 @@ dialog frame > label:not(.dummy) {
padding: 0;
}
+#ToolPanelNotebook .PanelEnding {
+ margin-top: 4px;
+}
+
#ToolPanelNotebook header tabs {
padding: 0.0833333333333333em;
background-color: #2A2A2A;
diff --git a/rtdata/themes/TooWaBlue-GTK3-20_.css b/rtdata/themes/TooWaBlue-GTK3-20_.css
index d2a63dd2e..ba25e70b7 100644
--- a/rtdata/themes/TooWaBlue-GTK3-20_.css
+++ b/rtdata/themes/TooWaBlue-GTK3-20_.css
@@ -963,6 +963,9 @@ window.csd:not(.fullscreen) #MainNotebook > header.top {
#ToolPanelNotebook {
background-color: @bg-dark-grey;
}
+#ToolPanelNotebook .PanelEnding {
+ margin-top: 4px;
+}
#ToolPanelNotebook > header {
border-bottom: 0.083333333333333333em solid @view-grid-border;
margin-left: 0.083333333333333333em;
diff --git a/rtengine/camconst.json b/rtengine/camconst.json
index 7a143e850..07f08d9a6 100644
--- a/rtengine/camconst.json
+++ b/rtengine/camconst.json
@@ -1973,6 +1973,11 @@ Camera constants:
"dcraw_matrix" : [13705, -6004, -1401, -5464, 13568, 2062, -940, 1706, 7618] // DNG
},
+ { // Quality C
+ "make_model" : "NIKON Z 9",
+ "dcraw_matrix" : [13389, -6049, -1441, -4544, 12757, 1969, 229, 498, 7390] //DNG
+ },
+
{ // Quality C, only color matrix and PDAF lines info
"make_model" : "Nikon Z 6",
"dcraw_matrix" : [8210, -2534, -683, -5355, 13338, 2212, -1143, 1928, 6464], // DNG v13.2
diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc
index e3bd9c988..4c70ad951 100644
--- a/rtengine/clutstore.cc
+++ b/rtengine/clutstore.cc
@@ -57,7 +57,7 @@ bool loadFile(
rtengine::procparams::ColorManagementParams icm;
icm.workingProfile = working_color_space;
- img_src.getImage(curr_wb, TR_NONE, img_float.get(), pp, rtengine::procparams::ToneCurveParams(), rtengine::procparams::RAWParams());
+ img_src.getImage(curr_wb, TR_NONE, img_float.get(), pp, rtengine::procparams::ToneCurveParams(), rtengine::procparams::RAWParams(), 0);
if (!working_color_space.empty()) {
img_src.convertColorSpace(img_float.get(), icm, curr_wb);
diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc
index a4dd8a4d1..4ba47b25a 100644
--- a/rtengine/colortemp.cc
+++ b/rtengine/colortemp.cc
@@ -33,7 +33,7 @@
namespace rtengine
{
-static double cie_colour_match_jd2[97][3] = {//350nm to 830nm 5 nm J.Desmis 2° Standard Observer.
+static const color_match_type cie_colour_match_jd2 = {//350nm to 830nm 5 nm J.Desmis 2° Standard Observer.
{0.0000000, 0.000000, 0.000000}, {0.0000000, 0.000000, 0.000000}, {0.0001299, 0.0003917, 0.0006061},
{0.0002321, 0.000006965, 0.001086}, {0.0004149, 0.00001239, 0.001946}, {0.0007416, 0.00002202, 0.003846},
{0.001368, 0.000039, 0.006450001}, {0.002236, 0.000064, 0.01054999}, {0.004243, 0.000120, 0.02005001},
@@ -70,7 +70,7 @@ static double cie_colour_match_jd2[97][3] = {//350nm to 830nm 5 nm J.Desmis 2
};
-static const double cie_colour_match_jd[97][3] = {//350nm to 830nm 5 nm J.Desmis 10° Standard Observer.
+static const color_match_type cie_colour_match_jd = {//350nm to 830nm 5 nm J.Desmis 10° Standard Observer.
{0.000000000000, 0.000000000000, 0.000000000000},
{0.000000000000, 0.000000000000, 0.000000000000},
{0.000000122200, 0.000000013398, 0.000000535027},
@@ -2963,15 +2963,16 @@ void ColorTemp::temp2mulxyz (double temp, const std::string &method, double &Xxy
// We first test for specially handled methods
const auto iterator = spectMap.find(method);
+ const auto &color_match = (settings->observer10 == true) ? cie_colour_match_jd : cie_colour_match_jd2;
if (iterator != spectMap.end()) {
- spectrum_to_xyz_preset(iterator->second, x, y, z);
+ spectrum_to_xyz_preset(iterator->second, x, y, z, color_match);
} else {
// otherwise we use the Temp+Green generic solution
if (temp <= INITIALBLACKBODY) {
// if temperature is between 2000K and 4000K we use blackbody, because there will be no Daylight reference below 4000K...
// of course, the previous version of RT used the "magical" but wrong formula of U.Fuchs (Ufraw).
- spectrum_to_xyz_blackbody(temp, x, y, z);
+ spectrum_to_xyz_blackbody(temp, x, y, z, color_match);
} else {
// from 4000K up to 25000K: using the D illuminant (daylight) which is standard
double x_D, y_D;
@@ -2990,7 +2991,7 @@ void ColorTemp::temp2mulxyz (double temp, const std::string &method, double &Xxy
double interm = 0.0241 + 0.2562 * x_D - 0.734 * y_D;
double m1 = (-1.3515 - 1.7703 * x_D + 5.9114 * y_D) / interm;
double m2 = (0.03 - 31.4424 * x_D + 30.0717 * y_D) / interm;
- spectrum_to_xyz_daylight(m1, m2, x, y, z);
+ spectrum_to_xyz_daylight(m1, m2, x, y, z, color_match);
}
}
@@ -3169,17 +3170,19 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
float CRI_RT = 0.0, CRI[50];
float CRI_RTs = 0.0, CRIs[8];
+ const auto &color_match = (settings->observer10 == true) ? cie_colour_match_jd : cie_colour_match_jd2;
+
for(int i = 0; i < N_c; i++) {
- spectrum_to_color_xyz_preset(spec_color[i], spect_illum[illum + 3], XchkLamp[i], YchkLamp[i], ZchkLamp[i]);
+ spectrum_to_color_xyz_preset(spec_color[i], spect_illum[illum + 3], XchkLamp[i], YchkLamp[i], ZchkLamp[i], color_match);
}
//calculate XYZ for each color : for Blackbody and Daylight at tempw
if(tempw <= INITIALBLACKBODY) {
for(int i = 0; i < N_c; i++) {
- spectrum_to_color_xyz_blackbody(spec_color[i], tempw, Xchk[i], Ychk[i], Zchk[i]);
+ spectrum_to_color_xyz_blackbody(spec_color[i], tempw, Xchk[i], Ychk[i], Zchk[i], color_match);
}
- spectrum_to_xyz_blackbody(tempw, x, y, z);//for white point
+ spectrum_to_xyz_blackbody(tempw, x, y, z, color_match);//for white point
} else { // after 6600K (arbitrary) I use daylight...because ...but there is no lamp...
double m11, m22, x_DD, y_DD, interm2;
@@ -3197,10 +3200,10 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2;
for(int i = 0; i < N_c; i++) {
- spectrum_to_color_xyz_daylight(spec_color[i], m11, m22, Xchk[i], Ychk[i], Zchk[i]);
+ spectrum_to_color_xyz_daylight(spec_color[i], m11, m22, Xchk[i], Ychk[i], Zchk[i], color_match);
}
- spectrum_to_xyz_daylight(m11, m22, x, y, z);
+ spectrum_to_xyz_daylight(m11, m22, x, y, z, color_match);
}
if (settings->verbose) {
@@ -3394,16 +3397,16 @@ I have increase precision used by J.Walker and pass to 350nm to 830nm
And also add 10° standard observer
*/
-void ColorTemp::spectrum_to_xyz_daylight(double _m1, double _m2, double &x, double &y, double &z)
+void ColorTemp::spectrum_to_xyz_daylight(double _m1, double _m2, double &x, double &y, double &z, const color_match_type &color_match)
{
int i;
double lambda, X = 0, Y = 0, Z = 0, XYZ;
for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) {
double Me = daylight_spect(lambda, _m1, _m2);
- X += Me * cie_colour_match_jd2[i][0];
- Y += Me * cie_colour_match_jd2[i][1];
- Z += Me * cie_colour_match_jd2[i][2];
+ X += Me * color_match[i][0];
+ Y += Me * color_match[i][1];
+ Z += Me * color_match[i][2];
}
XYZ = (X + Y + Z);
@@ -3412,16 +3415,16 @@ void ColorTemp::spectrum_to_xyz_daylight(double _m1, double _m2, double &x, doub
z = Z / XYZ;
}
-void ColorTemp::spectrum_to_xyz_blackbody(double _temp, double &x, double &y, double &z)
+void ColorTemp::spectrum_to_xyz_blackbody(double _temp, double &x, double &y, double &z, const color_match_type &color_match)
{
int i;
double lambda, X = 0, Y = 0, Z = 0, XYZ;
for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) {
double Me = blackbody_spect(lambda, _temp);
- X += Me * cie_colour_match_jd2[i][0];
- Y += Me * cie_colour_match_jd2[i][1];
- Z += Me * cie_colour_match_jd2[i][2];
+ X += Me * color_match[i][0];
+ Y += Me * color_match[i][1];
+ Z += Me * color_match[i][2];
}
XYZ = (X + Y + Z);
@@ -3430,7 +3433,7 @@ void ColorTemp::spectrum_to_xyz_blackbody(double _temp, double &x, double &y, do
z = Z / XYZ;
}
-void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, double &y, double &z)
+void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, double &y, double &z, const color_match_type &color_match)
{
int i;
double lambda, X = 0, Y = 0, Z = 0, XYZ;
@@ -3454,9 +3457,9 @@ void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, dou
*/
for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) {
double Me = get_spectral_color(lambda, spec_intens);
- X += Me * cie_colour_match_jd2[i][0];
- Y += Me * cie_colour_match_jd2[i][1];
- Z += Me * cie_colour_match_jd2[i][2];
+ X += Me * color_match[i][0];
+ Y += Me * color_match[i][1];
+ Z += Me * color_match[i][2];
}
XYZ = (X + Y + Z);
@@ -3466,7 +3469,7 @@ void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, dou
}
//calculate XYZ from spectrum data (color) and illuminant : J.Desmis December 2011
-void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz)
+void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz, const color_match_type &color_match)
{
int i;
double lambda, X = 0, Y = 0, Z = 0, Yo = 0;
@@ -3478,9 +3481,9 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou
Me = get_spectral_color(lambda, spec_color);
Mc = get_spectral_color(lambda, spec_intens);
- X += Mc * cie_colour_match_jd2[i][0] * Me;
- Y += Mc * cie_colour_match_jd2[i][1] * Me;
- Z += Mc * cie_colour_match_jd2[i][2] * Me;
+ X += Mc * color_match[i][0] * Me;
+ Y += Mc * color_match[i][1] * Me;
+ Z += Mc * color_match[i][2] * Me;
}
for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) {
@@ -3488,7 +3491,7 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou
double Ms;
Ms = get_spectral_color(lambda, spec_intens);
- Yo += cie_colour_match_jd2[i][1] * Ms;
+ Yo += color_match[i][1] * Ms;
}
xx = X / Yo;
@@ -3497,7 +3500,7 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou
}
//calculate XYZ from spectrum data (color) and illuminant : J.Desmis december 2011
-void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz)
+void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz, const color_match_type &color_match)
{
int i;
double lambda, X = 0, Y = 0, Z = 0;
@@ -3505,9 +3508,9 @@ void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double
for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) {
const double Me = spec_color[i];
const double Mc = daylight_spect(lambda, _m1, _m2);
- X += Mc * cie_colour_match_jd2[i][0] * Me;
- Y += Mc * cie_colour_match_jd2[i][1] * Me;
- Z += Mc * cie_colour_match_jd2[i][2] * Me;
+ X += Mc * color_match[i][0] * Me;
+ Y += Mc * color_match[i][1] * Me;
+ Z += Mc * color_match[i][2] * Me;
}
xx = X / Y;
@@ -3516,7 +3519,7 @@ void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double
}
//calculate XYZ from spectrum data (color) and illuminant : J.Desmis december 2011
-void ColorTemp::spectrum_to_color_xyz_blackbody(const double* spec_color, double _temp, double &xx, double &yy, double &zz)
+void ColorTemp::spectrum_to_color_xyz_blackbody(const double* spec_color, double _temp, double &xx, double &yy, double &zz, const color_match_type &color_match)
{
int i;
double lambda, X = 0, Y = 0, Z = 0;
@@ -3524,9 +3527,9 @@ void ColorTemp::spectrum_to_color_xyz_blackbody(const double* spec_color, double
for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) {
const double Me = spec_color[i];
const double Mc = blackbody_spect(lambda, _temp);
- X += Mc * cie_colour_match_jd2[i][0] * Me;
- Y += Mc * cie_colour_match_jd2[i][1] * Me;
- Z += Mc * cie_colour_match_jd2[i][2] * Me;
+ X += Mc * color_match[i][0] * Me;
+ Y += Mc * color_match[i][1] * Me;
+ Z += Mc * color_match[i][2] * Me;
}
xx = X / Y;
@@ -3762,27 +3765,21 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float
}
if (settings->verbose) {
- if (settings->itcwb_stdobserver10 == false) {
+ if (settings->itcwb_stdobserver10 == false) {//I will try to change settings by main
printf("Use standard observer 2°\n");
} else {
printf("Use standard observer 10°\n");
}
}
- if (settings->itcwb_stdobserver10 == true) {
- for (int i = 0; i < 97; i++) {
- cie_colour_match_jd2[i][0] = cie_colour_match_jd[i][0];
- cie_colour_match_jd2[i][1] = cie_colour_match_jd[i][1];;
- cie_colour_match_jd2[i][2] = cie_colour_match_jd[i][2];
- }
- }
+ const color_match_type &color_match = (settings->itcwb_stdobserver10 == true) ? cie_colour_match_jd : cie_colour_match_jd2;
if (separated) {
const double tempw = Txyz[repref].Tem;
if (tempw <= INITIALBLACKBODY) {
for (int i = 0; i < N_c; i++) {
- spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, TX[i], TY[i], TZ[i]);
+ spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, TX[i], TY[i], TZ[i], color_match);
}
} else {
double m11, m22, x_DD, y_DD, interm2;
@@ -3801,7 +3798,7 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float
m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2;
for (int i = 0; i < N_c; i++) {
- spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, TX[i], TY[i], TZ[i]);
+ spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, TX[i], TY[i], TZ[i], color_match);
}
}
} else {
@@ -3810,7 +3807,7 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float
if (tempw <= INITIALBLACKBODY) {
for (int i = 0; i < N_c; i++) {
- spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref);
+ spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref, color_match);
}
} else {
double x_DD;
@@ -3829,7 +3826,7 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float
const double m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2;
for (int i = 0; i < N_c; i++) {
- spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref);
+ spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref, color_match);
}
}
diff --git a/rtengine/colortemp.h b/rtengine/colortemp.h
index 89c324490..78091f51d 100644
--- a/rtengine/colortemp.h
+++ b/rtengine/colortemp.h
@@ -26,6 +26,8 @@
namespace rtengine
{
+using color_match_type = double [97][3];
+
constexpr double MINTEMP = 1500.0;
constexpr double MAXTEMP = 60000.0;
constexpr double MINGREEN = 0.02;
@@ -375,13 +377,13 @@ public:
static const double JDC468_greym13_325_spect[97];
static const double JDC468_greyf26_156_spect[97];
*/
- static void spectrum_to_xyz_daylight (double _m1, double _m2, double &x, double &y, double &z);
- static void spectrum_to_xyz_blackbody (double _temp, double &x, double &y, double &z);
- static void spectrum_to_xyz_preset (const double* spec_intens, double &x, double &y, double &z);
+ static void spectrum_to_xyz_daylight (double _m1, double _m2, double &x, double &y, double &z, const color_match_type &color_match);
+ static void spectrum_to_xyz_blackbody (double _temp, double &x, double &y, double &z, const color_match_type &color_match);
+ static void spectrum_to_xyz_preset (const double* spec_intens, double &x, double &y, double &z, const color_match_type &color_match);
- static void spectrum_to_color_xyz_daylight (const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz);
- static void spectrum_to_color_xyz_blackbody (const double* spec_color, double _temp, double &xx, double &yy, double &zz);
- static void spectrum_to_color_xyz_preset (const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz);
+ static void spectrum_to_color_xyz_daylight (const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz, const color_match_type &color_match);
+ static void spectrum_to_color_xyz_blackbody (const double* spec_color, double _temp, double &xx, double &yy, double &zz, const color_match_type &color_match);
+ static void spectrum_to_color_xyz_preset (const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz, const color_match_type &color_match);
};
}
diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc
index f4ac49fc4..8ddaa5f75 100644
--- a/rtengine/dcrop.cc
+++ b/rtengine/dcrop.cc
@@ -228,18 +228,18 @@ void Crop::update(int todo)
if (settings->leveldnautsimpl == 1) {
if (params.dirpyrDenoise.Cmethod == "MAN" || params.dirpyrDenoise.Cmethod == "PON") {
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
- parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
+ parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0);
}
} else {
if (params.dirpyrDenoise.C2method == "MANU") {
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
- parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
+ parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0);
}
}
if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "PRE") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "PREV")) {
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
- parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
+ parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0);
if ((!isDetailWindow) && parent->adnListener && skip == 1 && params.dirpyrDenoise.enabled) {
float lowdenoise = 1.f;
@@ -451,7 +451,7 @@ void Crop::update(int todo)
for (int wcr = 0; wcr <= 2; wcr++) {
for (int hcr = 0; hcr <= 2; hcr++) {
PreviewProps ppP(coordW[wcr], coordH[hcr], crW, crH, 1);
- parent->imgsrc->getImage(parent->currWB, tr, origCropPart, ppP, params.toneCurve, params.raw);
+ parent->imgsrc->getImage(parent->currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0);
// we only need image reduced to 1/4 here
for (int ii = 0; ii < crH; ii += 2) {
@@ -613,7 +613,7 @@ void Crop::update(int todo)
// if (params.dirpyrDenoise.Cmethod=="AUT" || params.dirpyrDenoise.Cmethod=="PON") {//reinit origCrop after Auto
if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { //reinit origCrop after Auto
PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip);
- parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw);
+ parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0);
}
if ((todo & M_SPOT) && params.spot.enabled && !params.spot.entries.empty()) {
@@ -749,7 +749,7 @@ void Crop::update(int todo)
fattalCrop.reset(f);
PreviewProps pp(0, 0, parent->fw, parent->fh, skip);
int tr = getCoarseBitMask(params.coarse);
- parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw);
+ parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw, 0);
parent->imgsrc->convertColorSpace(f, params.icm, parent->currWB);
if (params.dirpyrDenoise.enabled || params.filmNegative.enabled || params.spot.enabled) {
diff --git a/rtengine/filmnegativeproc.cc b/rtengine/filmnegativeproc.cc
index ae1813db9..c33dc4a9a 100644
--- a/rtengine/filmnegativeproc.cc
+++ b/rtengine/filmnegativeproc.cc
@@ -84,7 +84,7 @@ void getSpotAvgMax(ImageSource *imgsrc, ColorTemp currWB, const std::unique_ptr<
}
rtengine::Imagefloat spotImg(spotSize, spotSize);
- imgsrc->getImage(currWB, tr, &spotImg, pp, params->toneCurve, params->raw);
+ imgsrc->getImage(currWB, tr, &spotImg, pp, params->toneCurve, params->raw, 0);
auto avgMax = [spotSize, &spotImg](RGB & avg, RGB & max) -> void {
avg = {};
diff --git a/rtengine/hilite_recon.cc b/rtengine/hilite_recon.cc
index 86fdd6800..653ce80a2 100644
--- a/rtengine/hilite_recon.cc
+++ b/rtengine/hilite_recon.cc
@@ -32,14 +32,15 @@
#include "opthelper.h"
#include "rawimagesource.h"
#include "rt_math.h"
-//#define BENCHMARK
-//#include "StopWatch.h"
+#define BENCHMARK
+#include "StopWatch.h"
#include "guidedfilter.h"
#include "settings.h"
#include "gauss.h"
#include "rescale.h"
#include "iccstore.h"
#include "color.h"
+#include "linalgebra.h"
namespace
{
@@ -301,7 +302,7 @@ using namespace procparams;
void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue, int blur)
{
- // BENCHFUN
+ //BENCHFUN
double progress = 0.0;
if (plistener) {
@@ -1226,5 +1227,371 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
}// end of HLReconstruction
+
+//-----------------------------------------------------------------------------
+// "inpaint opposed" algorithm taken from darktable
+//
+// (Very effective, very simple, very neat)
+//
+// Kudos to the original authors (@jenshannoschwalm from dt, in collaboration
+// with @garagecoder and @Iain from gmic).
+//
+// Copyright and description of the original code follows
+//
+/*
+ Copyright (C) 2022 darktable developers.
+
+ darktable is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ darktable is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with darktable. If not, see .
+*/
+
+/* The refavg values are calculated in raw-RGB-cube3 space
+ We calculate all color channels in the 3x3 photosite area, this can be understaood as a "superpixel",
+ the "asking" location is in the centre.
+ As this works for bayer and xtrans sensors we don't have a fixed ratio but calculate the average
+ for every color channel first.
+ refavg for one of red, green or blue is defined as means of both other color channels (opposing).
+
+ The basic idea / observation for the _process_opposed algorithm is, the refavg is a good estimate
+ for any clipped color channel in the vast majority of images, working mostly fine both for small specular
+ highlighted spots and large areas.
+
+ The correction via some sort of global chrominance further helps to correct color casts.
+ The chrominace data are taken from the areas morphologically very close to clipped data.
+ Failures of the algorithm (color casts) are in most cases related to
+ a) very large differences between optimal white balance coefficients vs what we have as D65 in the darktable pipeline
+ b) complicated lightings so the gradients are not well related
+ c) a wrong whitepoint setting in the rawprepare module.
+ d) the maths might not be best
+*/
+//-----------------------------------------------------------------------------
+
+namespace {
+
+constexpr int HL_BORDER = 8;
+constexpr float HL_POWERF = 3.0f;
+
+// void border_fill_zero(int *d, int width, int height)
+// {
+// for (int i = 0; i < HL_BORDER * width; i++) {
+// d[i] = 0;
+// }
+// for (int i = (height - HL_BORDER - 1) * width; i < width*height; i++) {
+// d[i] = 0;
+// }
+// for (int row = HL_BORDER; row < height - HL_BORDER; row++) {
+// int *p1 = d + row*width;
+// int *p2 = d + (row+1)*width - HL_BORDER;
+// for(int i = 0; i < HL_BORDER; i++) {
+// p1[i] = p2[i] = 0;
+// }
+// }
+// }
+
+
+int test_dilate(const int *img, int i, int w1)
+{
+ int retval = 0;
+ retval = img[i-w1-1] | img[i-w1] | img[i-w1+1] |
+ img[i-1] | img[i] | img[i+1] |
+ img[i+w1-1] | img[i+w1] | img[i+w1+1];
+ if (retval) {
+ return retval;
+ }
+
+ const size_t w2 = 2*w1;
+ retval = img[i-w2-1] | img[i-w2] | img[i-w2+1] |
+ img[i-w1-2] | img[i-w1+2] |
+ img[i-2] | img[i+2] |
+ img[i+w1-2] | img[i+w1+2] |
+ img[i+w2-1] | img[i+w2] | img[i+w2+1];
+ if (retval) {
+ return retval;
+ }
+
+ const size_t w3 = 3*w1;
+ retval = img[i-w3-2] | img[i-w3-1] | img[i-w3] | img[i-w3+1] | img[i-w3+2] |
+ img[i-w2-3] | img[i-w2-2] | img[i-w2+2] | img[i-w2+3] |
+ img[i-w1-3] | img[i-w1+3] |
+ img[i-3] | img[i+3] |
+ img[i+w1-3] | img[i+w1+3] |
+ img[i+w2-3] | img[i+w2-2] | img[i+w2+2] | img[i+w2+3] |
+ img[i+w3-2] | img[i+w3-1] | img[i+w3] | img[i+w3+1] | img[i+w3+2];
+ return retval;
+}
+
+
+void dilating(const int *img, int *o, int w1, int height)
+{
+#ifdef _OPENMP
+# pragma omp parallel for
+#endif
+ for (int row = HL_BORDER; row < height - HL_BORDER; row++) {
+ for (int col = HL_BORDER, i = row*w1 + col; col < w1 - HL_BORDER; col++, i++) {
+ o[i] = test_dilate(img, i, w1);
+ }
+ }
+}
+
+} // namespace
+
+void RawImageSource::highlight_recovery_opposed(float scale_mul[3], const ColorTemp &wb, float gainth)
+{
+ //BENCHFUN
+
+ if (settings->verbose) {
+ std::cout << "Applying Highlight Recovery: Inpaint opposed" << std::endl;
+ }
+
+ if (plistener) {
+ plistener->setProgressStr("PROGRESSBAR_HLREC");
+ plistener->setProgress(0);
+ }
+
+ double rr, gg, bb;
+ wb.getMultipliers(rr, gg, bb);
+ wbMul2Camera(rr, gg, bb);
+
+ float gain = 1.2f * gainth;
+
+ float clipval = 0.987f / gain;
+ const float scalecoeffs[3] = {
+ scale_mul[0] * float(rr) / 65535.f,
+ scale_mul[1] * float(gg) / 65535.f,
+ scale_mul[2] * float(bb) / 65535.f,
+ };
+ const float clips[3] = {
+ clipval * float(rr),
+ clipval * float(gg),
+ clipval * float(bb)
+ };
+ const float clipdark[3] = {
+ 0.03f * clips[0],
+ 0.125f * clips[1],
+ 0.03f * clips[2]
+ };
+
+ bool anyclipped = false;
+ float **chan[3] = { red, green, blue };
+
+ const float clipscale[3] = {
+ clips[0] / scalecoeffs[0],
+ clips[1] / scalecoeffs[1],
+ clips[2] / scalecoeffs[2]
+ };
+
+ int x1 = W, y1 = H, x2 = 0, y2 = 0;
+ for (int y = 0; y < H; ++y) {
+ for (int x = 0; x < W; ++x) {
+ for (int c = 0; c < 3; ++c) {
+ if (chan[c][y][x] >= clipscale[c]) {
+ anyclipped = true;
+ x1 = std::min(x, x1);
+ x2 = std::max(x, x2);
+ y1 = std::min(y, y1);
+ y2 = std::max(y, y2);
+ }
+ }
+ }
+ }
+
+ if (!anyclipped) {
+ if (plistener) {
+ plistener->setProgress(1.0);
+ }
+ return;
+ }
+
+ x1 = std::max(x1-1, 0);
+ x2 = std::min(x2+1, W-1);
+ y1 = std::max(y1-1, 0);
+ y2 = std::min(y2+1, H-1);
+
+ const int cW = x2 - x1 + 1;
+ const int cH = y2 - y1 + 1;
+
+#ifdef _OPENMP
+# pragma omp parallel for
+#endif
+ for (int y = 0; y < cH; ++y) {
+ const int yy = y + y1;
+ for (int x = 0; x < cW; ++x) {
+ const int xx = x + x1;
+ for (int c = 0; c < 3; ++c) {
+ chan[c][yy][xx] *= scalecoeffs[c];
+ }
+ }
+ }
+
+ if (plistener) {
+ plistener->setProgress(0.1);
+ }
+
+ multi_array2D tmp(cW, cH);
+
+ const int pwidth = cW + 2 * HL_BORDER;
+ const int pheight = cH + 2 * HL_BORDER;
+ const int p_size = pwidth * pheight;
+ AlignedBuffer mask_vec(4 * p_size);
+ int *mask_buffer = mask_vec.data;
+
+ const auto mask_val =
+ [&](int c, int y, int x) -> int &
+ {
+ return mask_buffer[c * p_size + (HL_BORDER + y) * pwidth + x + HL_BORDER];
+ };
+
+ const auto set_refavg =
+ [&](int y, int x) -> bool
+ {
+ const int yy = y + y1;
+ const int xx = x + x1;
+ bool found = false;
+ for (int c = 0; c < 3 && !found; ++c) {
+ if (chan[c][yy][xx] >= clips[c]) {
+ found = true;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+
+ float mean[3] = { 0.0f, 0.0f, 0.0f };
+ for (int dy = -1; dy < 2; dy++) {
+ for (int dx = -1; dx < 2; dx++) {
+ for (int c = 0; c < 3; ++c) {
+ mean[c] += std::max(0.0f, chan[c][yy+dy][xx+dx]);
+ }
+ }
+ }
+ for (int c = 0; c < 3; ++c) {
+ mean[c] = pow_F(mean[c] / 9.0f, 1.0f / HL_POWERF);
+ }
+
+ const float croot_refavg[3] = {
+ 0.5f * (mean[1] + mean[2]),
+ 0.5f * (mean[0] + mean[2]),
+ 0.5f * (mean[0] + mean[1])
+ };
+
+ for (int c = 0; c < 3; ++c) {
+ if (chan[c][yy][xx] >= clips[c]) {
+ tmp[c][y][x] = pow_F(croot_refavg[c], HL_POWERF);
+ mask_val(c, y, x) = 1;
+ }
+ }
+ return true;
+ };
+
+#ifdef _OPENMP
+# pragma omp parallel for
+#endif
+ for (int y = 0; y < cH; ++y) {
+ const int yy = y + y1;
+ for (int x = 0; x < cW; ++x) {
+ const int xx = x + x1;
+ for (int c = 0; c < 3; ++c) {
+ tmp[c][y][x] = std::max(0.f, chan[c][yy][xx]);
+ }
+
+ if ((x > 0) && (x < cW - 1) && (y > 0) && (y < cH - 1)) {
+ set_refavg(y, x);
+ }
+ }
+ }
+
+ if (plistener) {
+ plistener->setProgress(0.3);
+ }
+
+ for (size_t i = 0; i < 3; i++) {
+ int *mask = mask_buffer + i * p_size;
+ int *tmp = mask_buffer + 3 * p_size;
+ //border_fill_zero(mask, pwidth, pheight);
+ dilating(mask, tmp, pwidth, pheight);
+ memcpy(mask, tmp, p_size * sizeof(int));
+ }
+
+ float cr_sum[3] = { 0.f, 0.f, 0.f };
+ int cr_cnt[3] = { 0, 0, 0 };
+
+#ifdef _OPENMP
+# pragma omp parallel for reduction(+ : cr_sum, cr_cnt)
+#endif
+ for (int y = 1; y < cH-1; ++y) {
+ const int yy = y + y1;
+ for (int x = 1; x < cW-1; ++x) {
+ const int xx = x + x1;
+ for (int c = 0; c < 3; ++c) {
+ const float inval = std::max(0.0f, chan[c][yy][xx]);
+ if (mask_val(c, y, x) && (inval > clipdark[c]) && (inval < clips[c])) {
+ cr_sum[c] += inval - tmp[c][y][x];
+ ++cr_cnt[c];
+ }
+ }
+ }
+ }
+
+ if (plistener) {
+ plistener->setProgress(0.6);
+ }
+
+ float chrominance[3] = {
+ cr_sum[0] / std::max(1.f, float(cr_cnt[0])),
+ cr_sum[1] / std::max(1.f, float(cr_cnt[1])),
+ cr_sum[2] / std::max(1.f, float(cr_cnt[2]))
+ };
+
+#ifdef _OPENMP
+# pragma omp parallel for
+#endif
+ for (int y = 0; y < cH; ++y) {
+ const int yy = y + y1;
+ for (int x = 0; x < cW; ++x) {
+ const int xx = x + x1;
+ for (int c = 0; c < 3; ++c) {
+ const float inval = std::max(0.0f, chan[c][yy][xx]);
+ if (inval >= clips[c]) {
+ chan[c][yy][xx] = std::max(inval, tmp[c][y][x] + chrominance[c]);
+ }
+ }
+ }
+ }
+
+ if (plistener) {
+ plistener->setProgress(0.9);
+ }
+
+#ifdef _OPENMP
+# pragma omp parallel for
+#endif
+ for (int y = 0; y < cH; ++y) {
+ const int yy = y + y1;
+ for (int x = 0; x < cW; ++x) {
+ const int xx = x + x1;
+ for (int c = 0; c < 3; ++c) {
+ chan[c][yy][xx] /= scalecoeffs[c];
+ }
+ }
+ }
+
+ if (plistener) {
+ plistener->setProgress(1.0);
+ }
+}
+
+
+
+
}
diff --git a/rtengine/iimage.h b/rtengine/iimage.h
index 2c75a0d59..a544b454a 100644
--- a/rtengine/iimage.h
+++ b/rtengine/iimage.h
@@ -111,7 +111,7 @@ public:
{
rm = gm = bm = 1.0;
}
- virtual void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw)
+ virtual void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp)
{
rm = gm = bm = 1.0;
}
diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h
index 926987ec0..aec2d31e8 100644
--- a/rtengine/imagesource.h
+++ b/rtengine/imagesource.h
@@ -109,7 +109,7 @@ public:
virtual void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const = 0;
// use right after demosaicing image, add coarse transformation and put the result in the provided Imagefloat*
- virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hlp, const procparams::RAWParams &raw) = 0;
+ virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hlp, const procparams::RAWParams &raw, int opposed) = 0;
virtual eSensorType getSensorType () const = 0;
virtual bool isMono () const = 0;
// true is ready to provide the AutoWB, i.e. when the image has been demosaiced for RawImageSource
@@ -117,10 +117,10 @@ public:
virtual void convertColorSpace (Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) = 0; // DIRTY HACK: this method is derived in rawimagesource and strimagesource, but (...,RAWParams raw) will be used ONLY for raw images
virtual void getAutoWBMultipliers (double &rm, double &gm, double &bm) = 0;
- virtual void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double & greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) = 0;
+ virtual void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double & greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) = 0;
virtual ColorTemp getWB () const = 0;
virtual ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) = 0;
- virtual void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) = 0;
+ virtual void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) = 0;
virtual void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) = 0;
virtual double getDefGain () const
@@ -195,6 +195,9 @@ public:
}
virtual void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) = 0;
virtual void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) = 0;
+ virtual void wbMul2Camera(double &rm, double &gm, double &bm) = 0;
+ virtual void wbCamera2Mul(double &rm, double &gm, double &bm) = 0;
+
};
}
diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc
index 1c3142c65..bf973e5f8 100644
--- a/rtengine/improccoordinator.cc
+++ b/rtengine/improccoordinator.cc
@@ -1,6 +1,6 @@
/*
* This file is part of RawTherapee.
- *
+ *
* Copyright (c) 2004-2010 Gabor Horvath
*
* RawTherapee is free software: you can redistribute it and/or modify
@@ -410,11 +410,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
if (imageTypeListener) {
imageTypeListener->imageTypeChanged(imgsrc->isRAW(), imgsrc->getSensorType() == ST_BAYER, imgsrc->getSensorType() == ST_FUJI_XTRANS, imgsrc->isMono(), imgsrc->isGainMapSupported());
}
-
+ bool iscolor = (params->toneCurve.method == "Color");// || params->toneCurve.method == "Coloropp");
if ((todo & M_RAW)
|| (!highDetailRawComputed && highDetailNeeded)
- || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified())
- || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) {
+ // || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified())
+ // || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) {
+ || (params->toneCurve.hrenabled && !iscolor && imgsrc->isRGBSourceModified())
+ || (!params->toneCurve.hrenabled && iscolor && imgsrc->isRGBSourceModified())) {
if (settings->verbose) {
if (imgsrc->getSensorType() == ST_BAYER) {
@@ -467,8 +469,10 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
if ((todo & M_RAW)
|| (!highDetailRawComputed && highDetailNeeded)
- || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified())
- || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) {
+ // || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified())
+ // || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) {
+ || (params->toneCurve.hrenabled && !iscolor && imgsrc->isRGBSourceModified())
+ || (!params->toneCurve.hrenabled && iscolor && imgsrc->isRGBSourceModified())) {
if (highDetailNeeded) {
highDetailRawComputed = true;
} else {
@@ -511,8 +515,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
}
if (todo & (M_INIT | M_LINDENOISE | M_HDR)) {
MyMutex::MyLock initLock(minit); // Also used in crop window
-
- imgsrc->HLRecovery_Global(params->toneCurve); // this handles Color HLRecovery
+ // imgsrc->HLRecovery_Global(params->toneCurve); // this handles Color HLRecovery
if (settings->verbose) {
@@ -539,7 +542,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
printf("tempref=%f greref=%f\n", tempref, greenref);
}
- imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw);
+ imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw, params->toneCurve);
if (params->wb.method == "autitcgreen") {
params->wb.temperature = tempitc;
@@ -618,8 +621,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
PreviewProps pp(0, 0, fw, fh, scale);
// Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications
ipf.setScale(scale);
-
- imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw);
+ int inpaintopposed = 1;//force getimage to use inpaint-opposed if enable, only once
+ imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw, inpaintopposed);
if ((todo & M_SPOT) && params->spot.enabled && !params->spot.entries.empty()) {
spotsDone = true;
@@ -2453,7 +2456,7 @@ bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, dou
double greenitc = 1.;
float studgood = 1000.f;
double tempref, greenref;
- imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw);
+ imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw, params->toneCurve);
if (rm != -1) {
autoWB.update(rm, gm, bm, equal, tempBias);
@@ -2640,7 +2643,7 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a
currWB = ColorTemp(); // = no white balance
}
- imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw);
+ imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw, 0);
ImProcFunctions ipf(&ppar, true);
if (ipf.needsTransform(fW, fH, imgsrc->getRotateDegree(), imgsrc->getMetaData())) {
diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc
index 30c48adc1..ba6b7cc2e 100644
--- a/rtengine/iplocallab.cc
+++ b/rtengine/iplocallab.cc
@@ -2128,7 +2128,7 @@ void ImProcFunctions::getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg,
Imagefloat img(int(fw / SCALE + 0.5), int(fh / SCALE + 0.5));
const ProcParams neutral;
- imgsrc->getImage(imgsrc->getWB(), TR_NONE, &img, pp, params->toneCurve, neutral.raw);
+ imgsrc->getImage(imgsrc->getWB(), TR_NONE, &img, pp, params->toneCurve, neutral.raw, 0);
imgsrc->convertColorSpace(&img, params->icm, imgsrc->getWB());
float minVal = RT_INFINITY;
float maxVal = -RT_INFINITY;
diff --git a/rtengine/linalgebra.h b/rtengine/linalgebra.h
new file mode 100644
index 000000000..32e44e147
--- /dev/null
+++ b/rtengine/linalgebra.h
@@ -0,0 +1,275 @@
+/* -*- C++ -*-
+ * This file is part of ART
+ *
+ * Copyright (c) 2022 Alberto Griggio
+ *
+ * RawTherapee is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RawTherapee is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * 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 .
+ */
+
+#pragma once
+#include
+
+namespace rtengine {
+
+template
+class Vec3 {
+public:
+ Vec3() { data_[0] = data_[1] = data_[2] = T(); }
+ Vec3(T a, T b, T c) { data_[0] = a; data_[1] = b; data_[2] = c; }
+
+ template
+ Vec3(T2 const a[3]) { data_[0] = a[0]; data_[1] = a[1]; data_[2] = a[2]; }
+
+ Vec3 &operator=(const Vec3 &a) = default;
+
+ template
+ Vec3 &operator=(T2 const a[3])
+ {
+ data_[0] = a[0]; data_[1] = a[1]; data_[2] = a[2];
+ return *this;
+ }
+
+ T operator[](int i) const { return data_[i]; }
+ T &operator[](int i) { return data_[i]; }
+ operator const T *() const { return data_; }
+ operator T *() { return data_; }
+
+private:
+ T data_[3];
+};
+
+typedef Vec3 Vec3f;
+
+
+template
+class Mat33 {
+public:
+ Mat33()
+ {
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ data_[i][j] = T();
+ }
+ }
+ }
+
+ Mat33(T a00, T a01, T a02,
+ T a10, T a11, T a12,
+ T a20, T a21, T a22)
+ {
+ data_[0][0] = a00; data_[0][1] = a01; data_[0][2] = a02;
+ data_[1][0] = a10; data_[1][1] = a11; data_[1][2] = a12;
+ data_[2][0] = a20; data_[2][1] = a21; data_[2][2] = a22;
+ }
+
+ template
+ Mat33(const T2 m[3][3])
+ {
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ data_[i][j] = m[i][j];
+ }
+ }
+ }
+
+ Mat33 &operator=(const Mat33 &m) = default;
+
+ template
+ Mat33 &operator=(const T2 m[3][3])
+ {
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ data_[i][j] = m[i][j];
+ }
+ }
+ return *this;
+ }
+
+ T const *operator[](int i) const { return data_[i]; }
+ T *operator[](int i) { return data_[i]; }
+ typedef const T(*Data)[3];
+ operator Data() const { return data_; }
+
+private:
+ T data_[3][3];
+};
+
+
+typedef Mat33 Mat33f;
+
+
+template
+Mat33 identity()
+{
+ return Mat33(1, 0, 0, 0, 1, 0, 0, 0, 1);
+}
+
+
+template
+Mat33 diagonal(T a, T b, T c)
+{
+ return Mat33(a, 0, 0, 0, b, 0, 0, 0, c);
+}
+
+
+template
+Mat33 transpose(T const m[3][3])
+{
+ return Mat33(m[0][0], m[1][0], m[2][0],
+ m[0][1], m[1][1], m[2][1],
+ m[0][2], m[1][2], m[2][2]);
+}
+
+template
+Mat33 transpose(const Mat33 &m)
+{
+ return transpose(static_cast::Data>(m));
+}
+
+
+template
+bool inverse(T const m[3][3], Mat33 &out)
+{
+ const T res00 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
+ const T res10 = m[2][0] * m[1][2] - m[1][0] * m[2][2];
+ const T res20 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
+
+ const T det = m[0][0] * res00 + m[0][1] * res10 + m[0][2] * res20;
+
+ if (std::abs(det) >= 1.0e-10) {
+ out[0][0] = res00 / det;
+ out[0][1] = (m[2][1] * m[0][2] - m[0][1] * m[2][2]) / det;
+ out[0][2] = (m[0][1] * m[1][2] - m[1][1] * m[0][2]) / det;
+ out[1][0] = res10 / det;
+ out[1][1] = (m[0][0] * m[2][2] - m[2][0] * m[0][2]) / det;
+ out[1][2] = (m[1][0] * m[0][2] - m[0][0] * m[1][2]) / det;
+ out[2][0] = res20 / det;
+ out[2][1] = (m[2][0] * m[0][1] - m[0][0] * m[2][1]) / det;
+ out[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) / det;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+template
+Mat33 inverse(const Mat33 &m)
+{
+ Mat33 res;
+ inverse(static_cast::Data>(m), res);
+ return res;
+}
+
+template
+Mat33 inverse(T const m[3][3])
+{
+ Mat33 res;
+ inverse(m, res);
+ return res;
+}
+
+template
+bool inverse(const Mat33 &m, Mat33 &out)
+{
+ return inverse(static_cast::Data>(m), out);
+}
+
+
+template
+Mat33 dot_product(T const a[3][3], T const b[3][3])
+{
+ Mat33 res;
+
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ res[i][j] = 0;
+
+ for (int k = 0; k < 3; ++k) {
+ res[i][j] += a[i][k] * b[k][j];
+ }
+ }
+ }
+
+ return res;
+}
+
+template
+Mat33 dot_product(const Mat33 &a, T const b[3][3])
+{
+ return dot_product(static_cast::Data>(a), b);
+}
+
+template
+Mat33 dot_product(T const a[3][3], const Mat33 &b)
+{
+ return dot_product(a, static_cast::Data>(b));
+}
+
+template
+Mat33 dot_product(const Mat33 &a, const Mat33 &b)
+{
+ return dot_product(static_cast::Data>(a), static_cast::Data>(b));
+}
+
+
+template
+Vec3 dot_product(T const a[3][3], T const b[3])
+{
+ Vec3 res;
+
+ for (int i = 0; i < 3; ++i) {
+ res[i] = 0;
+ for (int k = 0; k < 3; ++k) {
+ res[i] += a[i][k] * b[k];
+ }
+ }
+
+ return res;
+}
+
+
+template
+Vec3 dot_product(const Mat33 &a, T const b[3])
+{
+ return dot_product(static_cast::Data>(a), b);
+}
+
+template
+Vec3 dot_product(T const a[3][3], const Vec3 &b)
+{
+ return dot_product(a, static_cast(b));
+}
+
+template
+Vec3 dot_product(const Mat33 &a, const Vec3 &b)
+{
+ return dot_product(static_cast::Data>(a), static_cast(b));
+}
+
+
+template
+Mat33 operator*(const Mat33 &m, T v)
+{
+ return Mat33(m[0][0] * v, m[0][1] * v, m[0][2] * v,
+ m[1][0] * v, m[1][1] * v, m[1][2] * v,
+ m[2][0] * v, m[2][1] * v, m[2][2] * v);
+}
+
+template
+Vec3 operator*(const Vec3 &a, T v)
+{
+ return Vec3(a[0] * v, a[1] * v, a[2] * v);
+}
+
+} // namespace rtengine
diff --git a/rtengine/perspectivecorrection.cc b/rtengine/perspectivecorrection.cc
index 7a56ef5a8..f4428faf2 100644
--- a/rtengine/perspectivecorrection.cc
+++ b/rtengine/perspectivecorrection.cc
@@ -297,7 +297,7 @@ PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *sr
neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST);
neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST);
neutral.icm.outputProfile = ColorManagementParams::NoICMString;
- src->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw);
+ src->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw, 0);
src->convertColorSpace(img.get(), pparams->icm, src->getWB());
neutral.commonTrans.autofill = false; // Ensures crop factor is correct.
diff --git a/rtengine/previewimage.cc b/rtengine/previewimage.cc
index acc9acd04..00c71a53b 100644
--- a/rtengine/previewimage.cc
+++ b/rtengine/previewimage.cc
@@ -120,7 +120,7 @@ PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext
double contrastThresholdDummy = 0.0;
rawImage.demosaic(params.raw, false, contrastThresholdDummy);
Imagefloat image(fw, fh);
- rawImage.getImage (wb, TR_NONE, &image, pp, params.toneCurve, params.raw);
+ rawImage.getImage (wb, TR_NONE, &image, pp, params.toneCurve, params.raw, 0);
rtengine::Image8 output(fw, fh);
rawImage.convertColorSpace(&image, params.icm, wb);
#ifdef _OPENMP
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index c2f2fd443..e64d50497 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -396,7 +396,7 @@ ToneCurveParams::ToneCurveParams() :
autoexp(false),
clip(0.02),
hrenabled(false),
- method("Blend"),
+ method("Coloropp"),
expcomp(0),
curve{
DCT_Linear
@@ -413,6 +413,7 @@ ToneCurveParams::ToneCurveParams() :
shcompr(50),
hlcompr(0),
hlbl(0),
+ hlth(1.0),
hlcomprthresh(0),
histmatching(false),
fromHistMatching(false),
@@ -439,6 +440,7 @@ bool ToneCurveParams::isPanningRelatedChange(const ToneCurveParams& other) const
&& shcompr == other.shcompr
&& hlcompr == other.hlcompr
&& hlbl == other.hlbl
+ && hlth == other.hlth
&& hlcomprthresh == other.hlcomprthresh
&& histmatching == other.histmatching
&& clampOOG == other.clampOOG);
@@ -463,6 +465,7 @@ bool ToneCurveParams::operator ==(const ToneCurveParams& other) const
&& shcompr == other.shcompr
&& hlcompr == other.hlcompr
&& hlbl == other.hlbl
+ && hlth == other.hlth
&& hlcomprthresh == other.hlcomprthresh
&& histmatching == other.histmatching
&& fromHistMatching == other.fromHistMatching
@@ -6012,6 +6015,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
saveToKeyfile(!pedited || pedited->toneCurve.hrenabled, "HLRecovery", "Enabled", toneCurve.hrenabled, keyFile);
saveToKeyfile(!pedited || pedited->toneCurve.method, "HLRecovery", "Method", toneCurve.method, keyFile);
saveToKeyfile(!pedited || pedited->toneCurve.hlbl, "HLRecovery", "Hlbl", toneCurve.hlbl, keyFile);
+ saveToKeyfile(!pedited || pedited->toneCurve.hlth, "HLRecovery", "Hlth", toneCurve.hlth, keyFile);
const std::map tc_mapping = {
{ToneCurveMode::STD, "Standard"},
@@ -7812,6 +7816,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
assignFromKeyfile(keyFile, "HLRecovery", "Enabled", pedited, toneCurve.hrenabled, pedited->toneCurve.hrenabled);
assignFromKeyfile(keyFile, "HLRecovery", "Method", pedited, toneCurve.method, pedited->toneCurve.method);
assignFromKeyfile(keyFile, "HLRecovery", "Hlbl", pedited, toneCurve.hlbl, pedited->toneCurve.hlbl);
+ assignFromKeyfile(keyFile, "HLRecovery", "Hlth", pedited, toneCurve.hlth, pedited->toneCurve.hlth);
}
if (keyFile.has_group("Channel Mixer")) {
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index 893a2a355..c0139072f 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -299,6 +299,7 @@ struct ToneCurveParams {
int shcompr;
int hlcompr; // Highlight Recovery's compression
int hlbl; // Highlight Recovery's compression
+ double hlth; // Highlight Recovery's threshold
int hlcomprthresh; // Highlight Recovery's threshold
bool histmatching; // histogram matching
bool fromHistMatching;
diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc
index 77a07183a..a68b7a011 100644
--- a/rtengine/rawimagesource.cc
+++ b/rtengine/rawimagesource.cc
@@ -468,6 +468,7 @@ RawImageSource::RawImageSource ()
{
embProfile = nullptr;
rgbSourceModified = false;
+
for (int i = 0; i < 4; ++i) {
psRedBrightness[i] = psGreenBrightness[i] = psBlueBrightness[i] = 1.f;
}
@@ -639,6 +640,57 @@ float calculate_scale_mul(float scale_mul[4], const float pre_mul_[4], const flo
return gain;
}
+void RawImageSource::wbMul2Camera(double &rm, double &gm, double &bm)
+{
+ double r = rm;
+ double g = gm;
+ double b = bm;
+
+ auto imatrices = getImageMatrices();
+
+ if (imatrices) {
+ double rr = imatrices->cam_rgb[0][0] * r + imatrices->cam_rgb[0][1] * g + imatrices->cam_rgb[0][2] * b;
+ double gg = imatrices->cam_rgb[1][0] * r + imatrices->cam_rgb[1][1] * g + imatrices->cam_rgb[1][2] * b;
+ double bb = imatrices->cam_rgb[2][0] * r + imatrices->cam_rgb[2][1] * g + imatrices->cam_rgb[2][2] * b;
+ r = rr;
+ g = gg;
+ b = bb;
+ }
+
+ rm = ri->get_pre_mul(0) / r;
+ gm = ri->get_pre_mul(1) / g;
+ bm = ri->get_pre_mul(2) / b;
+
+ rm /= gm;
+ bm /= gm;
+ gm = 1.0;
+}
+
+
+void RawImageSource::wbCamera2Mul(double &rm, double &gm, double &bm)
+{
+ auto imatrices = getImageMatrices();
+
+ double r = ri->get_pre_mul(0) / rm;
+ double g = ri->get_pre_mul(1) / gm;
+ double b = ri->get_pre_mul(2) / bm;
+
+ if (imatrices) {
+ double rr = imatrices->rgb_cam[0][0] * r + imatrices->rgb_cam[0][1] * g + imatrices->rgb_cam[0][2] * b;
+ double gg = imatrices->rgb_cam[1][0] * r + imatrices->rgb_cam[1][1] * g + imatrices->rgb_cam[1][2] * b;
+ double bb = imatrices->rgb_cam[2][0] * r + imatrices->rgb_cam[2][1] * g + imatrices->rgb_cam[2][2] * b;
+ r = rr;
+ g = gg;
+ b = bb;
+ }
+
+ rm = r / g;
+ bm = b / g;
+ gm = 1.0;
+}
+
+
+
void RawImageSource::getWBMults (const ColorTemp &ctemp, const RAWParams &raw, std::array& out_scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const
{
@@ -689,8 +741,8 @@ void RawImageSource::getWBMults (const ColorTemp &ctemp, const RAWParams &raw, s
autoGainComp = camInitialGain / initialGain;
}
-void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw)
-{
+void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw, int opposed)
+{// added int opposed to force getimage to use inpaint-opposed if enable, only once
MyMutex::MyLock lock(getImageMutex);
tran = defTransform(ri, tran);
@@ -705,7 +757,9 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima
gm = ri->get_pre_mul(1);
bm = ri->get_pre_mul(2);
} else {
- ctemp.getMultipliers (r, g, b);
+ // ctemp.getMultipliers (r, g, b);
+ r = g = b = 1;
+ wbCamera2Mul(r, g, b);
rm = imatrices.cam_rgb[0][0] * r + imatrices.cam_rgb[0][1] * g + imatrices.cam_rgb[0][2] * b;
gm = imatrices.cam_rgb[1][0] * r + imatrices.cam_rgb[1][1] * g + imatrices.cam_rgb[1][2] * b;
bm = imatrices.cam_rgb[2][0] * r + imatrices.cam_rgb[2][1] * g + imatrices.cam_rgb[2][2] * b;
@@ -790,22 +844,52 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima
int maxx = this->W, maxy = this->H, skip = pp.getSkip();
- // raw clip levels after white balance
+ bool iscolor = (hrp.method == "Color" || hrp.method == "Coloropp");
+ const bool doClip = (chmax[0] >= clmax[0] || chmax[1] >= clmax[1] || chmax[2] >= clmax[2]) && !hrp.hrenabled && hrp.clampOOG;
+ bool doHr = (hrp.hrenabled && !iscolor);
+ if (hrp.hrenabled && iscolor) {
+
+ if(hrp.method == "Coloropp" && opposed == 1) {//force Inpaint opposed if WB change, and opposed limited tne number to 1
+ rgbSourceModified = false;
+ }
+ if (!rgbSourceModified) {
+ if(hrp.method == "Color") {
+ if (settings->verbose) {
+ printf ("Applying Highlight Recovery: Color propagation.\n");
+ }
+ HLRecovery_inpaint (red, green, blue, hrp.hlbl);
+ } else if(hrp.method == "Coloropp" && ctemp.getTemp() >= 0) {
+ float s[3] = { rm, gm, bm };
+ highlight_recovery_opposed(s, ctemp, hrp.hlth);
+ }
+ rgbSourceModified = true;
+ }
+ }
+
+ // now apply the wb coefficients
+ if (ctemp.getTemp() >= 0) {
+ double r, g, b;
+ ctemp.getMultipliers(r, g, b);
+ wbMul2Camera(r, g, b);
+
+ rm *= r;
+ gm *= g;
+ bm *= b;
+ }
hlmax[0] = clmax[0] * rm;
hlmax[1] = clmax[1] * gm;
hlmax[2] = clmax[2] * bm;
- const bool doClip = (chmax[0] >= clmax[0] || chmax[1] >= clmax[1] || chmax[2] >= clmax[2]) && !hrp.hrenabled && hrp.clampOOG;
+ const float expcomp = std::pow(2, ri->getBaselineExposure());
+ rm *= expcomp;
+ gm *= expcomp;
+ bm *= expcomp;
float area = skip * skip;
rm /= area;
gm /= area;
bm /= area;
- bool doHr = (hrp.hrenabled && hrp.method != "Color");
- const float expcomp = std::pow(2, ri->getBaselineExposure());
- rm *= expcomp;
- gm *= expcomp;
- bm *= expcomp;
+
#ifdef _OPENMP
#pragma omp parallel if(!d1x) // omp disabled for D1x to avoid race conditions (see Issue 1088 http://code.google.com/p/rawtherapee/issues/detail?id=1088)
@@ -1715,7 +1799,6 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c
rgbSourceModified = false;
-
if (cache) {
if (!redCache) {
redCache = new array2D(W, H);
@@ -2414,7 +2497,6 @@ void RawImageSource::retinex(const ColorManagementParams& cmp, const RetinexPara
}
rgbSourceModified = false; // tricky handling for Color propagation
-
t5.set();
if (settings->verbose) {
@@ -2460,16 +2542,17 @@ void RawImageSource::flush()
void RawImageSource::HLRecovery_Global(const ToneCurveParams &hrp)
{
- if (hrp.hrenabled && hrp.method == "Color") {
- if (!rgbSourceModified) {
- if (settings->verbose) {
- printf ("Applying Highlight Recovery: Color propagation...\n");
- }
-
- HLRecovery_inpaint (red, green, blue, hrp.hlbl);
- rgbSourceModified = true;
- }
- }
+ // if (hrp.hrenabled && hrp.method == "Color") {
+ // if (!rgbSourceModified) {
+ // if (settings->verbose) {
+ // printf ("Applying Highlight Recovery: Color propagation...\n");
+ // }
+//
+ // HLRecovery_inpaint (red, green, blue, hrp.hlbl);
+//
+// rgbSourceModified = true;
+ // }
+// }
}
@@ -3478,6 +3561,7 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed
// very effective to reduce (or remove) the magenta, but with levels of grey !
void RawImageSource::HLRecovery_blend(float* rin, float* gin, float* bin, int width, float maxval, float* hlmax)
{
+
constexpr int ColorCount = 3;
// Transform matrixes rgb>lab and back
@@ -3702,6 +3786,7 @@ void RawImageSource::HLRecovery_CIELab (float* rin, float* gin, float* bin, floa
void RawImageSource::hlRecovery (const std::string &method, float* red, float* green, float* blue, int width, float* hlmax)
{
+// BENCHFUN
if (method == "Luminance") {
HLRecovery_Luminance (red, green, blue, red, green, blue, width, 65535.0);
@@ -3971,12 +4056,12 @@ void RawImageSource::getRowStartEnd (int x, int &start, int &end)
}
}
-
-static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const array2D & yc, const array2D & Yc, LUTf &xxx, LUTf &yyy, LUTf &YYY, LUTu &histxy)
+static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const array2D & yc, const array2D & Yc, LUTf &xxx, LUTf &yyy, LUTf &YYY, LUTu &histxy, bool purp)
{
- //calculate histogram x y in a range of 190 colors
- //this "choice" are guided by generally colors who are in nature skin, sky, etc. in those cases "steps" are small
+ // calculate histogram x y in a range of 236 colors
+ // this "choice" are guided by generally colors who are in nature skin, sky, etc. in those cases "steps" are small
// of course we can change to be more precise
+ // purp enable or not purple color in xyY - approximation...
#ifdef _OPENMP
#pragma omp parallel
#endif
@@ -3989,434 +4074,528 @@ static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const ar
yyythr.clear();
LUTf YYYthr(YYY.getSize());
YYYthr.clear();
+ // bool purp = false;
#ifdef _OPENMP
#pragma omp for schedule(dynamic, 4) nowait
#endif
- for (int y = 0; y < bfhitc ; y++) {
+
+ for (int y = 0; y < bfhitc ; y++)
+ {
for (int x = 0; x < bfwitc ; x++) {
int nh = -1;
+
if (xc[y][x] < 0.12f && xc[y][x] > 0.03f && yc[y][x] > 0.1f) { // near Prophoto
if (yc[y][x] < 0.2f) {
nh = 0;
//blue hard
- } else if (yc[y][x] < 0.3f) {
+ } else if (yc[y][x] < 0.25f) {
nh = 1;
- //blue
- } else if (yc[y][x] < 0.4f) {
+ } else if (yc[y][x] < 0.3f) {
nh = 2;
-
+ //blue
+ } else if (yc[y][x] < 0.35f) {
+ nh = 3;
+ } else if (yc[y][x] < 0.4f) {
+ nh = 4;
+ } else if (yc[y][x] < 0.45f) {
+ nh = 5;
} else if (yc[y][x] < 0.5f) {
//blue green
- nh = 3;
+ nh = 6;
+ } else if (yc[y][x] < 0.55f) {
+ nh = 7;
} else if (yc[y][x] < 0.6f) {
- nh = 4;
+ nh = 8;
+ } else if (yc[y][x] < 0.7f) {
+ nh = 9;
} else if (yc[y][x] < 0.82f) {
//green
- nh = 5;
+ nh = 10;
}
} else if (xc[y][x] < 0.24f && yc[y][x] > 0.05f) {
if (yc[y][x] < 0.2f) {
- nh = 6;
- } else if (yc[y][x] < 0.3f) {
- nh = 7;
- } else if (yc[y][x] < 0.4f) {
- nh = 8;
- } else if (yc[y][x] < 0.5f) {
- nh = 9;
- } else if (yc[y][x] < 0.6f) {
- nh = 10;
- } else if (yc[y][x] < 0.75f) {
nh = 11;
- }
- } else if (xc[y][x] < 0.28f && yc[y][x] > 0.1f) {//blue sky and other
- if (yc[y][x] < 0.2f) {
- nh = 12;
} else if (yc[y][x] < 0.25f) {
+ nh = 12;
+ } else if (yc[y][x] < 0.3f) {
nh = 13;
- } else if (yc[y][x] < 0.29f) {
+ } else if (yc[y][x] < 0.35f) {
nh = 14;
- } else if (yc[y][x] < 0.33f) {
- nh = 15;
- } else if (yc[y][x] < 0.37f) {
- nh = 16;
} else if (yc[y][x] < 0.4f) {
- nh = 17;
+ nh = 15;
} else if (yc[y][x] < 0.45f) {
- nh = 18;
+ nh = 16;
} else if (yc[y][x] < 0.5f) {
- nh = 19;
+ nh = 17;
+ } else if (yc[y][x] < 0.55f) {
+ nh = 18;
} else if (yc[y][x] < 0.6f) {
+ nh = 19;
+ } else if (yc[y][x] < 0.67f) {
nh = 20;
} else if (yc[y][x] < 0.75f) {
nh = 21;
}
- } else if (xc[y][x] < 0.31f && yc[y][x] > 0.1f) {//near neutral others
+ } else if (xc[y][x] < 0.28f && yc[y][x] > 0.1f) {//blue sky and other
if (yc[y][x] < 0.2f) {
nh = 22;
- } else if (yc[y][x] < 0.24f) {
+ } else if (yc[y][x] < 0.23f) {
nh = 23;
- } else if (yc[y][x] < 0.29f) {
+ } else if (yc[y][x] < 0.25f) {
nh = 24;
- } else if (yc[y][x] < 0.32f) {
+ } else if (yc[y][x] < 0.27f) {
nh = 25;
- } else if (yc[y][x] < 0.36f) {
+ } else if (yc[y][x] < 0.29f) {
nh = 26;
- } else if (yc[y][x] < 0.4f) {
+ } else if (yc[y][x] < 0.31f) {
nh = 27;
- } else if (yc[y][x] < 0.5f) {
+ } else if (yc[y][x] < 0.33f) {
nh = 28;
- } else if (yc[y][x] < 0.7f) {
+ } else if (yc[y][x] < 0.35f) {
nh = 29;
+ } else if (yc[y][x] < 0.37f) {
+ nh = 30;
+ } else if (yc[y][x] < 0.4f) {
+ nh = 31;
+ } else if (yc[y][x] < 0.45f) {
+ nh = 32;
+ } else if (yc[y][x] < 0.5f) {
+ nh = 33;
+ } else if (yc[y][x] < 0.55f) {
+ nh = 34;
+ } else if (yc[y][x] < 0.6f) {
+ nh = 35;
+ } else if (yc[y][x] < 0.67f) {
+ nh = 36;
+ } else if (yc[y][x] < 0.75f) {
+ nh = 37;
+ }
+ } else if (xc[y][x] < 0.31f && yc[y][x] > 0.1f) {//near neutral others
+ if (yc[y][x] < 0.2f) {
+ nh = 38;
+ } else if (yc[y][x] < 0.22f) {
+ nh = 39;
+ } else if (yc[y][x] < 0.24f) {
+ nh = 40;
+ } else if (yc[y][x] < 0.26f) {
+ nh = 41;
+ } else if (yc[y][x] < 0.29f) {
+ nh = 42;
+ } else if (yc[y][x] < 0.32f) {
+ nh = 43;
+ } else if (yc[y][x] < 0.36f) {
+ nh = 44;
+ } else if (yc[y][x] < 0.4f) {
+ nh = 45;
+ } else if (yc[y][x] < 0.45f) {
+ nh = 46;
+ } else if (yc[y][x] < 0.5f) {
+ nh = 47;
+ } else if (yc[y][x] < 0.6f) {
+ nh = 48;
+ } else if (yc[y][x] < 0.7f) {
+ nh = 49;
}
} else if (xc[y][x] < 0.325f && yc[y][x] > 0.1f) {//neutral 34
if (yc[y][x] < 0.2f) {
- nh = 30;
+ nh = 50;
+ } else if (yc[y][x] < 0.22f) {
+ nh = 51;
} else if (yc[y][x] < 0.24f) {
- nh = 31;
+ nh = 52;
} else if (yc[y][x] < 0.29f) {
- nh = 32;
+ nh = 53;
} else if (yc[y][x] < 0.32f) {
- nh = 33;
+ nh = 54;
} else if (yc[y][x] < 0.33f) {
- nh = 34;
+ nh = 55;
} else if (yc[y][x] < 0.335f) {
- nh = 35;
+ nh = 56;
} else if (yc[y][x] < 0.34f) {
- nh = 36;
+ nh = 57;
} else if (yc[y][x] < 0.35f) {
- nh = 37;
+ nh = 58;
} else if (yc[y][x] < 0.37f) {
- nh = 38;
+ nh = 59;
} else if (yc[y][x] < 0.4f) {
- nh = 39;
+ nh = 60;
} else if (yc[y][x] < 0.45f) {
- nh = 40;
+ nh = 61;
} else if (yc[y][x] < 0.5f) {
- nh = 41;
+ nh = 62;
} else if (yc[y][x] < 0.55f) {
- nh = 42;
+ nh = 63;
+ } else if (yc[y][x] < 0.6f) {
+ nh = 64;
+ } else if (yc[y][x] < 0.65f) {
+ nh = 65;
} else if (yc[y][x] < 0.7f) {
- nh = 43;
+ nh = 66;
}
} else if (xc[y][x] < 0.335f && yc[y][x] > 0.1f) {//neutral
if (yc[y][x] < 0.2f) {
- nh = 44;
+ nh = 67;
+ } else if (yc[y][x] < 0.22f) {
+ nh = 68;
} else if (yc[y][x] < 0.24f) {
- nh = 45;
+ nh = 69;
+ } else if (yc[y][x] < 0.27f) {
+ nh = 70;
} else if (yc[y][x] < 0.29f) {
- nh = 46;
+ nh = 71;
} else if (yc[y][x] < 0.32f) {
- nh = 47;
+ nh = 72;
} else if (yc[y][x] < 0.33f) {
- nh = 48;
+ nh = 73;
} else if (yc[y][x] < 0.335f) {
- nh = 49;
+ nh = 74;
} else if (yc[y][x] < 0.34f) {
- nh = 50;
+ nh = 75;
} else if (yc[y][x] < 0.345f) {
- nh = 51;
+ nh = 76;
} else if (yc[y][x] < 0.35f) {
- nh = 52;
+ nh = 77;
} else if (yc[y][x] < 0.355f) {
- nh = 53;
+ nh = 78;
} else if (yc[y][x] < 0.36f) {
- nh = 54;
+ nh = 79;
} else if (yc[y][x] < 0.37f) {
- nh = 55;
+ nh = 80;
} else if (yc[y][x] < 0.38f) {
- nh = 56;
+ nh = 81;
} else if (yc[y][x] < 0.4f) {
- nh = 57;
+ nh = 82;
} else if (yc[y][x] < 0.45f) {
- nh = 58;
+ nh = 83;
} else if (yc[y][x] < 0.5f) {
- nh = 59;
+ nh = 84;
} else if (yc[y][x] < 0.55f) {
- nh = 60;
+ nh = 85;
+ } else if (yc[y][x] < 0.6f) {
+ nh = 86;
+ } else if (yc[y][x] < 0.65f) {
+ nh = 87;
} else if (yc[y][x] < 0.7f) {
- nh = 61;
+ nh = 88;
}
} else if (xc[y][x] < 0.340f && yc[y][x] > 0.1f) {//neutral
if (yc[y][x] < 0.2f) {
- nh = 62;
+ nh = 89;
+ } else if (yc[y][x] < 0.22f) {
+ nh = 90;
} else if (yc[y][x] < 0.24f) {
- nh = 63;
+ nh = 91;
} else if (yc[y][x] < 0.29f) {
- nh = 64;
+ nh = 92;
} else if (yc[y][x] < 0.32f) {
- nh = 65;
+ nh = 93;
} else if (yc[y][x] < 0.325f) {
- nh = 66;
+ nh = 94;
} else if (yc[y][x] < 0.33f) {
- nh = 67;
+ nh = 95;
} else if (yc[y][x] < 0.335f) {
- nh = 68;
+ nh = 96;
} else if (yc[y][x] < 0.34f) {
- nh = 69;
+ nh = 97;
} else if (yc[y][x] < 0.345f) {
- nh = 70;
+ nh = 98;
} else if (yc[y][x] < 0.35f) {
- nh = 71;
+ nh = 99;
} else if (yc[y][x] < 0.355f) {
- nh = 72;
+ nh = 100;
} else if (yc[y][x] < 0.36f) {
- nh = 73;
+ nh = 101;
} else if (yc[y][x] < 0.37f) {
- nh = 74;
+ nh = 102;
} else if (yc[y][x] < 0.38f) {
- nh = 75;
+ nh = 103;
} else if (yc[y][x] < 0.4f) {
- nh = 76;
+ nh = 104;
} else if (yc[y][x] < 0.45f) {
- nh = 77;
+ nh = 105;
} else if (yc[y][x] < 0.5f) {
- nh = 78;
+ nh = 106;
} else if (yc[y][x] < 0.55f) {
- nh = 79;
+ nh = 107;
+ } else if (yc[y][x] < 0.6f) {
+ nh = 108;
+ } else if (yc[y][x] < 0.65f) {
+ nh = 109;
} else if (yc[y][x] < 0.7f) {
- nh = 80;
+ nh = 110;
}
} else if (xc[y][x] < 0.345f && yc[y][x] > 0.1f) {//neutral 37
if (yc[y][x] < 0.2f) {
- nh = 81;
+ nh = 111;
+ } else if (yc[y][x] < 0.22f) {
+ nh = 112;
} else if (yc[y][x] < 0.24f) {
- nh = 82;
+ nh = 113;
+ } else if (yc[y][x] < 0.26f) {
+ nh = 114;
} else if (yc[y][x] < 0.29f) {
- nh = 83;
+ nh = 115;
} else if (yc[y][x] < 0.32f) {
- nh = 84;
+ nh = 116;
} else if (yc[y][x] < 0.33f) {
- nh = 85;
+ nh = 117;
} else if (yc[y][x] < 0.335f) {
- nh = 86;
+ nh = 118;
} else if (yc[y][x] < 0.34f) {
- nh = 87;
+ nh = 119;
} else if (yc[y][x] < 0.345f) {
- nh = 88;
+ nh = 120;
} else if (yc[y][x] < 0.35f) {
- nh = 89;
+ nh = 121;
} else if (yc[y][x] < 0.355f) {
- nh = 90;
+ nh = 122;
} else if (yc[y][x] < 0.36f) {
- nh = 91;
+ nh = 123;
} else if (yc[y][x] < 0.37f) {
- nh = 92;
+ nh = 124;
} else if (yc[y][x] < 0.38f) {
- nh = 93;
+ nh = 125;
} else if (yc[y][x] < 0.39f) {
- nh = 94;
+ nh = 126;
} else if (yc[y][x] < 0.4f) {
- nh = 95;
+ nh = 127;
} else if (yc[y][x] < 0.42f) {
- nh = 96;
+ nh = 128;
} else if (yc[y][x] < 0.45f) {
- nh = 97;
+ nh = 129;
} else if (yc[y][x] < 0.48f) {
- nh = 98;
+ nh = 130;
} else if (yc[y][x] < 0.5f) {
- nh = 99;
+ nh = 131;
} else if (yc[y][x] < 0.55f) {
- nh = 100;
+ nh = 132;
} else if (yc[y][x] < 0.65f) {
- nh = 101;
+ nh = 133;
}
} else if (xc[y][x] < 0.355f && yc[y][x] > 0.1f) {//neutral 37
if (yc[y][x] < 0.2f) {
- nh = 102;
+ nh = 134;
+ } else if (yc[y][x] < 0.22f) {
+ nh = 135;
} else if (yc[y][x] < 0.24f) {
- nh = 103;
+ nh = 136;
+ } else if (yc[y][x] < 0.26f) {
+ nh = 137;
} else if (yc[y][x] < 0.29f) {
- nh = 104;
+ nh = 138;
} else if (yc[y][x] < 0.32f) {
- nh = 105;
+ nh = 139;
} else if (yc[y][x] < 0.33f) {
- nh = 106;
+ nh = 140;
} else if (yc[y][x] < 0.335f) {
- nh = 107;
+ nh = 141;
} else if (yc[y][x] < 0.34f) {
- nh = 108;
+ nh = 142;
} else if (yc[y][x] < 0.345f) {
- nh = 109;
+ nh = 143;
} else if (yc[y][x] < 0.35f) {
- nh = 110;
+ nh = 144;
} else if (yc[y][x] < 0.355f) {
- nh = 111;
+ nh = 145;
} else if (yc[y][x] < 0.36f) {
- nh = 112;
+ nh = 146;
} else if (yc[y][x] < 0.37f) {
- nh = 113;
+ nh = 147;
} else if (yc[y][x] < 0.38f) {
- nh = 114;
+ nh = 148;
} else if (yc[y][x] < 0.39f) {
- nh = 115;
+ nh = 149;
} else if (yc[y][x] < 0.4f) {
- nh = 116;
+ nh = 150;
} else if (yc[y][x] < 0.42f) {
- nh = 117;
+ nh = 151;
} else if (yc[y][x] < 0.45f) {
- nh = 118;
+ nh = 152;
} else if (yc[y][x] < 0.48f) {
- nh = 119;
+ nh = 153;
} else if (yc[y][x] < 0.5f) {
- nh = 120;
+ nh = 154;
} else if (yc[y][x] < 0.55f) {
- nh = 121;
+ nh = 155;
+ } else if (yc[y][x] < 0.6f) {
+ nh = 156;
} else if (yc[y][x] < 0.65f) {
- nh = 122;
+ nh = 157;
}
} else if (xc[y][x] < 0.365f && yc[y][x] > 0.15f) { //0.4
if (yc[y][x] < 0.2f) {
- nh = 123;
+ nh = 158;
+ } else if (yc[y][x] < 0.22f) {
+ nh = 159;
} else if (yc[y][x] < 0.24f) {
- nh = 124;
+ nh = 160;
+ } else if (yc[y][x] < 0.26f) {
+ nh = 161;
} else if (yc[y][x] < 0.29f) {
- nh = 125;
+ nh = 162;
} else if (yc[y][x] < 0.32f) {
- nh = 126;
+ nh = 163;
} else if (yc[y][x] < 0.33f) {
- nh = 127;
+ nh = 164;
} else if (yc[y][x] < 0.34f) {
- nh = 128;
+ nh = 165;
} else if (yc[y][x] < 0.35f) {
- nh = 129;
+ nh = 166;
} else if (yc[y][x] < 0.36f) {
- nh = 130;
+ nh = 167;
} else if (yc[y][x] < 0.37f) {
- nh = 131;
+ nh = 168;
} else if (yc[y][x] < 0.38f) {
- nh = 132;
+ nh = 169;
} else if (yc[y][x] < 0.39f) {
- nh = 133;
+ nh = 170;
} else if (yc[y][x] < 0.4f) {
- nh = 134;
+ nh = 171;
} else if (yc[y][x] < 0.42f) {
- nh = 135;
+ nh = 172;
} else if (yc[y][x] < 0.45f) {
- nh = 136;
+ nh = 173;
} else if (yc[y][x] < 0.5f) {
- nh = 137;
+ nh = 174;
} else if (yc[y][x] < 0.55f) {
- nh = 138;
+ nh = 175;
} else if (yc[y][x] < 0.63f) {
- nh = 139;
+ nh = 176;
}
} else if (xc[y][x] < 0.405f && yc[y][x] > 0.15f) {//45
- if (yc[y][x] < 0.2f) {
- nh = 140;
- } else if (yc[y][x] < 0.24f) {
- nh = 141;
- } else if (yc[y][x] < 0.29f) {
- nh = 142;
- } else if (yc[y][x] < 0.32f) {
- nh = 143;
- } else if (yc[y][x] < 0.34f) {
- nh = 144;
- } else if (yc[y][x] < 0.37f) {
- nh = 145;
- } else if (yc[y][x] < 0.4f) {
- nh = 146;
- } else if (yc[y][x] < 0.45f) {
- nh = 147;
- } else if (yc[y][x] < 0.5f) {
- nh = 148;
- } else if (yc[y][x] < 0.55f) {
- nh = 149;
- } else if (yc[y][x] < 0.6f) {
- nh = 150;
- }
- } else if (xc[y][x] < 0.445f && yc[y][x] > 0.15f) {//45
- if (yc[y][x] < 0.2f) {
- nh = 151;
- } else if (yc[y][x] < 0.24f) {
- nh = 152;
- } else if (yc[y][x] < 0.29f) {
- nh = 153;
- } else if (yc[y][x] < 0.32f) {
- nh = 154;
- } else if (yc[y][x] < 0.34f) {
- nh = 155;
- } else if (yc[y][x] < 0.37f) {
- nh = 156;
- } else if (yc[y][x] < 0.4f) {
- nh = 157;
- } else if (yc[y][x] < 0.45f) {
- nh = 158;
- } else if (yc[y][x] < 0.5f) {
- nh = 159;
- } else if (yc[y][x] < 0.55f) {
- nh = 160;
- } else if (yc[y][x] < 0.58f) {
- nh = 161;
- }
- } else if (xc[y][x] < 0.495f && yc[y][x] > 0.15f) {
- if (yc[y][x] < 0.2f) {
- nh = 162;
- } else if (yc[y][x] < 0.24f) {
- nh = 163;
- } else if (yc[y][x] < 0.29f) {
- nh = 164;
- } else if (yc[y][x] < 0.32f) {
- nh = 165;
- } else if (yc[y][x] < 0.34f) {
- nh = 166;
- } else if (yc[y][x] < 0.37f) {
- nh = 167;
- } else if (yc[y][x] < 0.4f) {
- nh = 168;
- } else if (yc[y][x] < 0.45f) {
- nh = 169;
- } else if (yc[y][x] < 0.5f) {
- nh = 170;
- } else if (yc[y][x] < 0.55f) {
- nh = 171;
- }
- } else if (xc[y][x] < 0.545f && yc[y][x] > 0.15f) {
- if (yc[y][x] < 0.2f) {
- nh = 172;
- } else if (yc[y][x] < 0.24f) {
- nh = 173;
- } else if (yc[y][x] < 0.29f) {
- nh = 174;
- } else if (yc[y][x] < 0.32f) {
- nh = 175;
- } else if (yc[y][x] < 0.34f) {
- nh = 176;
- } else if (yc[y][x] < 0.37f) {
+ if (yc[y][x] < 0.2f && purp) {//no take into account if purp = false
nh = 177;
- } else if (yc[y][x] < 0.4f) {
+ } else if (yc[y][x] < 0.22f && purp) {
nh = 178;
- } else if (yc[y][x] < 0.45f) {
+ } else if (yc[y][x] < 0.24f && purp) {
nh = 179;
- } else if (yc[y][x] < 0.5f) {
+ } else if (yc[y][x] < 0.26f && purp) {
nh = 180;
- }
- } else if (xc[y][x] < 0.595f && yc[y][x] > 0.15f) {
- if (yc[y][x] < 0.22f) {
+ } else if (yc[y][x] < 0.29f && purp) {
nh = 181;
- } else if (yc[y][x] < 0.25f) {
+ } else if (yc[y][x] < 0.32f) {
nh = 182;
- } else if (yc[y][x] < 0.3f) {
+ } else if (yc[y][x] < 0.34f) {
nh = 183;
- } else if (yc[y][x] < 0.35f) {
+ } else if (yc[y][x] < 0.37f) {
nh = 184;
} else if (yc[y][x] < 0.4f) {
nh = 185;
} else if (yc[y][x] < 0.45f) {
nh = 186;
+ } else if (yc[y][x] < 0.5f) {
+ nh = 187;
+ } else if (yc[y][x] < 0.55f) {
+ nh = 188;
+ } else if (yc[y][x] < 0.6f) {
+ nh = 189;
+ }
+ } else if (xc[y][x] < 0.445f && yc[y][x] > 0.15f) {//45
+ if (yc[y][x] < 0.2f && purp) {
+ nh = 190;
+ } else if (yc[y][x] < 0.22f && purp) {
+ nh = 191;
+ } else if (yc[y][x] < 0.24f && purp) {
+ nh = 192;
+ } else if (yc[y][x] < 0.26f && purp) {
+ nh = 193;
+ } else if (yc[y][x] < 0.29f && purp) {
+ nh = 194;
+ } else if (yc[y][x] < 0.32f && purp) {
+ nh = 195;
+ } else if (yc[y][x] < 0.34f && purp) {
+ nh = 196;
+ } else if (yc[y][x] < 0.37f) {
+ nh = 197;
+ } else if (yc[y][x] < 0.4f) {
+ nh = 198;
+ } else if (yc[y][x] < 0.45f) {
+ nh = 199;
+ } else if (yc[y][x] < 0.5f) {
+ nh = 200;
+ } else if (yc[y][x] < 0.55f) {
+ nh = 201;
+ } else if (yc[y][x] < 0.58f) {
+ nh = 202;
+ }
+ } else if (xc[y][x] < 0.495f && yc[y][x] > 0.15f) {
+ if (yc[y][x] < 0.2f && purp) {
+ nh = 203;
+ } else if (yc[y][x] < 0.22f && purp) {
+ nh = 204;
+ } else if (yc[y][x] < 0.24f && purp) {
+ nh = 205;
+ } else if (yc[y][x] < 0.26f && purp) {
+ nh = 206;
+ } else if (yc[y][x] < 0.29f && purp) {
+ nh = 207;
+ } else if (yc[y][x] < 0.32f && purp) {
+ nh = 208;
+ } else if (yc[y][x] < 0.34f && purp) {
+ nh = 209;
+ } else if (yc[y][x] < 0.37f) {
+ nh = 210;
+ } else if (yc[y][x] < 0.4f) {
+ nh = 211;
+ } else if (yc[y][x] < 0.45f) {
+ nh = 212;
+ } else if (yc[y][x] < 0.5f) {
+ nh = 213;
+ } else if (yc[y][x] < 0.55f) {
+ nh = 214;
+ }
+ } else if (xc[y][x] < 0.545f && yc[y][x] > 0.15f) {
+ if (yc[y][x] < 0.2f && purp) {
+ nh = 215;
+ } else if (yc[y][x] < 0.22f && purp) {
+ nh = 216;
+ } else if (yc[y][x] < 0.24f && purp) {
+ nh = 217;
+ } else if (yc[y][x] < 0.26f && purp) {
+ nh = 218;
+ } else if (yc[y][x] < 0.29f && purp) {
+ nh = 219;
+ } else if (yc[y][x] < 0.32f && purp) {
+ nh = 220;
+ } else if (yc[y][x] < 0.34f && purp) {
+ nh = 221;
+ } else if (yc[y][x] < 0.37f) {
+ nh = 222;
+ } else if (yc[y][x] < 0.4f) {
+ nh = 223;
+ } else if (yc[y][x] < 0.45f) {
+ nh = 224;
+ } else if (yc[y][x] < 0.5f) {
+ nh = 225;
+ }
+ } else if (xc[y][x] < 0.595f && yc[y][x] > 0.15f) {
+ if (yc[y][x] < 0.22f) {
+ nh = 226;
+ } else if (yc[y][x] < 0.25f) {
+ nh = 227;
+ } else if (yc[y][x] < 0.3f) {
+ nh = 228;
+ } else if (yc[y][x] < 0.35f) {
+ nh = 229;
+ } else if (yc[y][x] < 0.4f) {
+ nh = 230;
+ } else if (yc[y][x] < 0.45f) {
+ nh = 231;
}
} else if (xc[y][x] < 0.65f && yc[y][x] > 0.12f) {
if (yc[y][x] < 0.25f) {
- nh = 187;
+ nh = 232;
} else if (yc[y][x] < 0.3f) {
- nh = 188;
+ nh = 233;
} else if (yc[y][x] < 0.35f) {
- nh = 189;
+ nh = 234;
} else if (yc[y][x] < 0.45f) {
- nh = 190;
+ nh = 235;
}
} else if (xc[y][x] < 0.75f && yc[y][x] > 0.1f) {
- nh = 191;
+ nh = 236; //191
}
+
if (nh >= 0) {
histxythr[nh]++;
xxxthr[nh] += xc[y][x];
@@ -4425,6 +4604,7 @@ static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const ar
}
}
}
+
#ifdef _OPENMP
#pragma omp critical
#endif
@@ -4449,24 +4629,28 @@ float static studentXY(const array2D & YYcurr, const array2D & ref
somcurrY += YYcurr[i][tt];
//sum observations first group
}
+
somcurrY *= 100.f;
for (int i = 0; i < Nc; i++) {
somreffY += reffYY[i][tt];
//sum observations second group
}
+
somreffY *= 100.f;
for (int i = 0; i < sizcurr; i++) {
somcurr2Y += SQR(YYcurr[i][tt]);
//sum sqr observations first group
}
+
somcurr2Y *= SQR(100.f);
for (int i = 0; i < Nc; i++) {
somreff2Y += SQR(reffYY[i][tt]);
//sum sqr observations second group
}
+
somreff2Y *= SQR(100.f);
const float somsqueccurrY = somcurr2Y - SQR(somcurrY) / sizcurr;
@@ -4483,13 +4667,16 @@ float static studentXY(const array2D & YYcurr, const array2D & ref
//student coeeficient
}
-void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, const ColorManagementParams &cmp, const RAWParams &raw, const WBParams & wbpar)
+
+
+
+void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, const ColorManagementParams &cmp, const RAWParams &raw, const WBParams & wbpar, const ToneCurveParams &hrp)
{
/*
- Copyright (c) Jacques Desmis 6 - 2018 jdesmis@gmail.com
+ Copyright (c) Jacques Desmis 6 - 2018 jdesmis@gmail.com, update 1 - 2023
Copyright (c) Ingo Weyrich 3 - 2020 (heckflosse67@gmx.de)
- This algorithm try to find temperature correlation between 20 to 201 color between 201 spectral color and about 20 to 55 color found in the image between 192, I just found the idea in the web "correlate with chroma" instead of RGB grey point,but I don't use any algo found on the web.
+ This algorithm try to find temperature correlation between 20 to 80 colors between 201 spectral color and about 20 to 55 color found in the image between 236, I just found the idea in the web "correlate with chroma" instead of RGB grey point,but I don't use any algo found on the web.
I have test many many algorithms to find the first one that work :)
Probably (sure) there are improvement to do...
@@ -4538,16 +4725,17 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
You can change parameters in option.cc
Itcwb_thres : 34 by default ==> number of color used in final algorithm - between 10 and max 55
- Itcwb_sort : false by default, can improve algorithm if true, ==> sort value in something near chroma order, instead of histogram number
+ Itcwb_sorted : true by default, can improve algorithm if true, ==> sort value in something near chroma order, instead of histogram number
Itcwb_greenrange : 0 amplitude of green variation - between 0 to 2
Itcwb_greendeltatemp : 1 - delta temp in green iterate loop for "extra" - between 0 to 4
- Itcwb_forceextra : false - if true force algorithm "extra" ("extra" is used when camera wbsettings are wrong) to all images
+ Itcwb_forceextra : true by default - if true force algorithm "extra" ("extra" is used when camera wbsettings are wrong) to all images
Itcwb_sizereference : 3 by default, can be set to 5 ==> size of reference color compare to size of histogram real color
itcwb_delta : 1 by default can be set between 0 to 5 ==> delta temp to build histogram xy - if camera temp is not probably good
itcwb_stdobserver10 : true by default - use standard observer 10°, false = standard observer 2°
- itcwb_precis : 5 by default - can be set to 3 or 9 - 3 best sampling but more time...9 "old" settings - but low differences in times with 3 instead of 9 about twice time 160ms instead of 80ms for a big raw file
+ itcwb_precis : 3 by default - can be set to 3 or 9 - 3 best sampling but more time...9 "old" settings - but low differences in times with 3 instead of 9 about twice time 160ms instead of 80ms for a big raw file
+ itcwb_nopurple : true default - allow to bypass highlight recovery and inpait opposed when need flowers and not purple due to highlights...
*/
-// BENCHFUN
+ // BENCHFUN
TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix("sRGB");
const float wp[3][3] = {
@@ -4588,7 +4776,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
{0.590, 1.f},
{0.600, 1.f},
{0.610, 1.f},
- {0.620, 1.f},
+ {0.620, 1.f},//extended range
{0.630, 1.f},
{0.640, 1.f},
{0.650, 1.f},
@@ -4597,7 +4785,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
{0.680, 1.f},
{0.690, 1.f},
{0.700, 1.f},
- {0.714, 1.f},
+ {0.714, 1.f},//usual range
{0.727, 1.f},
{0.741, 1.f},
{0.755, 1.f},
@@ -4628,7 +4816,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
{0.971, 1.f},
{0.980, 1.f},
{0.990, 1.f},
- {1.000, 1.f},//55
+ {1.000, 1.f},//55 reference
{1.010, 1.f},
{1.020, 1.f},
{1.030, 1.f},
@@ -4659,14 +4847,14 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
{1.325, 1.f},
{1.350, 1.f},
{1.375, 1.f},
- {1.400, 1.f},
+ {1.400, 1.f},//usual range
{1.425, 1.f},
{1.450, 1.f},
{1.475, 1.f},
{1.500, 1.f},
{1.525, 1.f},
{1.550, 1.f},
- {1.575, 1.f},
+ {1.575, 1.f},//extended range
{1.600, 1.f},
{1.633, 1.f},
{1.666, 1.f},
@@ -4715,7 +4903,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
int end;
} RangeGreen;
- constexpr RangeGreen Rangestandard = {24, 86};
+ constexpr RangeGreen Rangestandard = {24, 86};//usual green range
constexpr RangeGreen Rangeextended = {15, 93};
const RangeGreen Rangemax = {0, N_g};
@@ -4796,7 +4984,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
{4927., 0.965414, 0.809229},
{4952., 0.964908, 0.814366},
{4977., 0.964415, 0.819412},
- {5002., 0.963934, 0.824438},
+ {5002., 0.963934, 0.824438},//57 reference
{5027., 0.963465, 0.829444},
{5052., 0.963008, 0.834429},
{5077., 0.962563, 0.839395},
@@ -4875,10 +5063,10 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
float gmm[N_t];
float bmm[N_t];
- constexpr int siza = 192;//size of histogram
+ constexpr int siza = 237; //192 untill 01/2023 size of histogram
- //tempref and greenref are camera wb values.
- // I used them by default to select good spectral values !!
+ // tempref and greenref are camera wb values.
+ // I used them by default to select good spectral values !! but they are changed after
tempref = rtengine::min(tempref, 12000.0);
int repref = 0;
@@ -4892,7 +5080,8 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
//calculate R G B multiplier in function illuminant and temperature
const bool isMono = (ri->getSensorType() == ST_FUJI_XTRANS && raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::MONO))
- || (ri->getSensorType() == ST_BAYER && raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::MONO));
+ || (ri->getSensorType() == ST_BAYER && raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::MONO));
+
for (int tt = 0; tt < N_t; ++tt) {
double r, g, b;
float rm, gm, bm;
@@ -4942,19 +5131,27 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
} ;
LUTu histxy(siza); //number of values for each pair xy
+
histxy.clear();
LUTf xxx(siza);//for color references calculated ==> max in images "like histogram"
+
xxx.clear();
+
LUTf yyy(siza);
+
yyy.clear();
+
LUTf YYY(siza);//not used directly, but necessary to keep good range
+
YYY.clear();
bool separated = true;
+
int w = -1;
array2D reff_spect_yy_camera(N_t, 2 * Nc + 2);
+
array2D reff_spect_xx_camera(N_t, 2 * Nc + 2);
//here we select the good spectral color inside the 113 values
@@ -4983,6 +5180,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
#ifdef _OPENMP
#pragma omp parallel for
#endif
+
for (int y = 0; y < bfh ; ++y) {
for (int x = 0; x < bfw ; ++x) {
const float RR = rmm[rep] * redloc[y][x];
@@ -4991,6 +5189,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
Color::rgbxyY(RR, GG, BB, xc[y][x], yc[y][x], Yc[y][x], wp);
}
}
+
//histogram xy depend of temp...but in most cases D45 ..D65..
//calculate for this image the mean values for each family of color, near histogram x y (number)
//xy vary from x 0..0.77 y 0..0.82
@@ -5000,8 +5199,14 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
// step about 0.02 x 0.32 0.34 y= 0.34 0.36 skin -- sky x 0.24 0.30 y 0.28 0.32
//big step about 0.2
- histoxyY(bfhitc, bfwitc, xc, yc, Yc, xxx, yyy, YYY, histxy);
- //return histogram x and y for each temp and in a range of 158 colors (siza)
+ bool purp = true;//if inpaint-opposed or something else enable purp
+
+ if (hrp.hrenabled && hrp.method == "Coloropp" && settings->itcwb_nopurple == true) {//we disabled (user) with settings if image are naturally with purple (flowers...)
+ purp = false;
+ }
+
+ histoxyY(bfhitc, bfwitc, xc, yc, Yc, xxx, yyy, YYY, histxy, purp);//purp enable, enable purple color in WB
+ //return histogram x and y for each temp and in a range of 235 colors (siza)
}
// free some memory
@@ -5032,15 +5237,19 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
int n4 = 0;
int n15 = 0;
int n30 = 0;
+
//part to improve
//determined the number of colors who be used after
for (int nh = 0; nh < siza; nh++) {
if (Wbhis[nh].histnum < 30) {
n30++; //keep only existing color but avoid to small
+
if (Wbhis[nh].histnum < 15) {
n15++; //keep only existing color but avoid to small
+
if (Wbhis[nh].histnum < 4) {
n4++; //keep only existing color but avoid to small
+
if (Wbhis[nh].histnum < 1) {
n1++; //keep only existing color but avoid to small
}
@@ -5065,7 +5274,11 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
int sizcurr2ref = sizcurrref - ntr;
const int sizcu30 = sizcurrref - n30;
- const int sizcu4 = rtengine::min(sizcu30, 55);
+ const int sizcu4 = rtengine::min(sizcu30, 55);//
+
+ if (settings->verbose) {
+ printf("ntr=%i sizcurr2ref=%i sizcu30=%i sizcu4=%i\n", ntr, sizcurr2ref, sizcu30, sizcu4);
+ }
chrom wbchro[sizcu4];
const float swpr = Txyz[repref].XX + Txyz[repref].ZZ + 1.f;
@@ -5080,6 +5293,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
}
float estimchrom = 0.f;
+
//estimate chromaticity for references
for (int nh = 0; nh < sizcu4; ++nh) {
const float chxy = std::sqrt(SQR(xx_curref[nh][repref] - xwpr) + SQR(yy_curref[nh][repref] - ywpr));
@@ -5093,10 +5307,12 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
}
estimchrom /= sizcu4;
+
if (settings->verbose) {
printf("estimchrom=%f\n", estimchrom);
}
- if (settings->itcwb_sort) { //sort in ascending with chroma values
+
+ if (settings->itcwb_sorted) { //sort in ascending with chroma values
std::sort(wbchro, wbchro + sizcu4, wbchro[0]);
}
@@ -5123,7 +5339,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
for (int nb = 1; nb <= maxnb; ++nb) { //max 5 iterations for Itcwb_thres=33, after trial 3 is good in most cases but in some cases 5
for (int i = 0; i < w; ++i) {
- float mindeltaE = 100000.f;
+ float mindeltaE = 100000.f;//we can change this value...
int kN = 0;
for (int j = 0; j < Nc ; j++) {
@@ -5210,7 +5426,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
}
}
- if (extra) {//always used because I made this choice, brings better results
+ if (extra) {//always used if extra = true because I made this choice, brings better results
struct Tempgreen {
float student;
int tempref;
@@ -5224,14 +5440,15 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
for (int i = 0; i < N_g; ++i) {//init variables with
Tgstud[i].student = 1000.f;//max value to initialize
- Tgstud[i].tempref = 57;//5002K
- Tgstud[i].greenref = 55;// 1.f
+ Tgstud[i].tempref = 57;//5002K position in the list
+ Tgstud[i].greenref = 55;// 1.f position in the list
}
const int dgoodref = rtengine::min(settings->itcwb_greendeltatemp, 4);
const int scantempbeg = rtengine::max(goodref - (dgoodref + 1), 1);
const int scantempend = rtengine::min(goodref + dgoodref, N_t - 1);
+
for (int gr = Rangegreenused.begin; gr < Rangegreenused.end; ++gr) {
float minstudgr = 100000.f;
int goodrefgr = 1;
@@ -5267,6 +5484,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
const float BB = bmm[tt] * B_curref_reduc[i][repref];
Color::rgbxyY(RR, GG, BB, xxyycurr_reduc[2 * i][tt], xxyycurr_reduc[2 * i + 1][tt], unused, wp);
}
+
//recalculate xy spectral now with good range of temp and green
for (int j = 0; j < Nc ; ++j) {
@@ -5275,6 +5493,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
}
int kkg = -1;
+
for (int i = 0; i < Nc ; ++i) {
if (good_spectral[i]) {
kkg++;
@@ -5282,6 +5501,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
reff_spect_xxyy[2 * kkg + 1][tt] = reff_spect_xxyy_prov[2 * i + 1][tt];
}
}
+
//now we have good spectral data
//calculate student correlation
const float abstudgr = std::fabs(studentXY(xxyycurr_reduc, reff_spect_xxyy, 2 * w, 2 * kkg, tt));
@@ -5290,6 +5510,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
minstudgr = abstudgr;
goodrefgr = tt;
}
+
//found the values
Tgstud[gr].tempref = goodrefgr;
Tgstud[gr].greenref = gr;
@@ -5300,48 +5521,35 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
std::sort(Tgstud, Tgstud + N_g, Tgstud[0]);
- //now search the value of green the nearest of 1 with a good student value
- // I take the 3 first values
- //I admit a symetrie in green coefiicient for rgb multiplier...probably not exactly true
- //perhaps we can used a Snedecor test ? but why...at least we have confidence interval > 90%
- int greengood;
- int greengoodprov;
- int goodrefprov;
- float studprov;
- const int goodref0 = Tgstud[0].tempref;
- const int greengood0 = Tgstud[0].greenref - 55;//55 green = 1
- const float stud0 = Tgstud[0].student;
- const int goodref1 = Tgstud[1].tempref;
- const float stud1 = Tgstud[1].student;
- const int greengood1 = Tgstud[1].greenref - 55;
- const int goodref2 = Tgstud[2].tempref;
- const int greengood2 = Tgstud[2].greenref - 55;
- const float stud2 = Tgstud[2].student;
+ // now search the value of green the nearest of 1 with a good student value, I think it is a good choice, perhaps no...
+ // I take the 5 first values
+ // I admit a symetrie in green coefiicient for rgb multiplier...probably not exactly true
+ // perhaps we can used a Snedecor test ? but why...at least we have confidence interval > 90%
+ int greengood = 55;
- if (std::fabs(greengood2) < std::fabs(greengood1)) {
- greengoodprov = greengood2;
- goodrefprov = goodref2;
- studprov = stud2;
- } else {
- greengoodprov = greengood1;
- goodrefprov = goodref1;
- studprov = stud1;
+ int maxkgood = 5;//we can change ...to test 3, 4, 5. High values perhaps less good student, but it is a compromise...
+ int mingood = std::min(std::fabs(Tgstud[0].greenref - 55), std::fabs(Tgstud[1].greenref - 55));
+ for (int k = 2; k < maxkgood; ++k) {
+ mingood = std::min(std::fabs(mingood), std::fabs(Tgstud[k].greenref - 55));
}
- if (std::fabs(greengoodprov) < std::fabs(greengood0)) {
- goodref = goodrefprov;
- greengood = greengoodprov + 55;
- studgood = studprov;
+ for (int k = 0; k < maxkgood ; ++k) {
+ if (mingood == fabs(Tgstud[k].greenref - 55)) {
+ greengood = Tgstud[k].greenref ;
+ goodref = Tgstud[k].tempref;
+ studgood = Tgstud[k].student;;
+ }
+ }
- } else {
- goodref = goodref0;
- greengood = greengood0 + 55;
- studgood = stud0;
+ if (settings->verbose) {
+ printf("Student_0=%f Student_k= %f\n", Tgstud[0].student, Tgstud[maxkgood - 1].student);
+ printf("mingood=%i greeng=%i goodref=%i stud=%f\n", mingood, greengood, goodref, (double) studgood);
}
tempitc = Txyz[goodref].Tem;
greenitc = gree[greengood].green;
+
if (estimchrom < 0.025f) {
float ac = -2.40f * estimchrom + 0.06f;//small empirical correction, maximum 0.06 if chroma=0 for all image, currently for very low chroma +0.02
greenitc += ac;
@@ -5355,13 +5563,14 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double
if (!extra) {
tempitc = Txyz[goodref].Tem;
}
+
//now we have temp green and student
if (settings->verbose) {
printf("ITCWB tempitc=%f gritc=%f stud=%f \n", tempitc, greenitc, studgood);
}
}
-void RawImageSource::WBauto(double & tempref, double & greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double & avg_rm, double & avg_gm, double & avg_bm, double & tempitc, double & greenitc, float & studgood, bool & twotimes, const WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams & cmp, const RAWParams & raw)
+void RawImageSource::WBauto(double & tempref, double & greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double & avg_rm, double & avg_gm, double & avg_bm, double & tempitc, double & greenitc, float & studgood, bool & twotimes, const WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams & cmp, const RAWParams & raw, const ToneCurveParams &hrp)
{
// BENCHFUN
//auto white balance
@@ -5382,8 +5591,7 @@ void RawImageSource::WBauto(double & tempref, double & greenref, array2D
}
tempitc = 5000.;
-
- ItcWB(extra, tempref, greenref, tempitc, greenitc, studgood, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, cmp, raw, wbpar);
+ ItcWB(extra, tempref, greenref, tempitc, greenitc, studgood, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, cmp, raw, wbpar, hrp);
}
}
@@ -5391,7 +5599,9 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int
{
// BENCHFUN
//used by auto WB local to calculate red, green, blue in local region
+
int precision = 5;
+
if (settings->itcwb_precis == 5) {
precision = 5;
} else if (settings->itcwb_precis < 5) {
@@ -5400,6 +5610,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int
precision = 9;
}
+
const int bfw = W / precision + ((W % precision) > 0 ? 1 : 0);// 5 arbitrary value can be change to 3 or 9 ;
const int bfh = H / precision + ((H % precision) > 0 ? 1 : 0);
@@ -5422,6 +5633,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int
#ifdef _OPENMP
#pragma omp parallel for reduction(+:avgL, nn)
#endif
+
for (int i = 0; i < H; i ++) {
for (int j = 0; j < W; j++) {
const float LL = 0.299f * red[i][j] + 0.587f * green[i][j] + 0.114f * blue[i][j];
@@ -5429,6 +5641,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int
nn++;
}
}
+
avgL /= nn;
double vari = 0.f;
@@ -5437,6 +5650,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int
#ifdef _OPENMP
#pragma omp parallel for reduction(+:vari, mm)
#endif
+
for (int i = 0; i < H; i++)
for (int j = 0; j < W; j++) {
const float LL = 0.299f * red[i][j] + 0.587f * green[i][j] + 0.114f * blue[i][j];
@@ -5450,8 +5664,10 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int
#ifdef _OPENMP
#pragma omp parallel for
#endif
+
for (int i = 0; i < bfh; ++i) {
const int ii = i * precision;
+
if (ii < H) {
for (int j = 0, jj = 0; j < bfw; ++j, jj += precision) {
redloc[i][j] = red[ii][jj] * multip;
@@ -5462,7 +5678,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int
}
}
-void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref, double & tempitc, double & greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double & rm, double & gm, double & bm, const WBParams & wbpar, const ColorManagementParams & cmp, const RAWParams & raw)
+void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref, double & tempitc, double & greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double & rm, double & gm, double & bm, const WBParams & wbpar, const ColorManagementParams & cmp, const RAWParams & raw, const ToneCurveParams &hrp)
{
// BENCHFUN
constexpr double clipHigh = 64000.0;
@@ -5477,6 +5693,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
double avg_b = 0;
int rn = 0, gn = 0, bn = 0;
double avg_rm, avg_gm, avg_bm;
+
if (wbpar.method == "autold") {
if (fuji) {
for (int i = 32; i < H - 32; i++) {
@@ -5486,7 +5703,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
for (int j = start; j < end; j++) {
if (ri->getSensorType() != ST_BAYER) {
- double dr = CLIP(initialGain * (rawData[i][3 * j] ));
+ double dr = CLIP(initialGain * (rawData[i][3 * j]));
double dg = CLIP(initialGain * (rawData[i][3 * j + 1]));
double db = CLIP(initialGain * (rawData[i][3 * j + 2]));
@@ -5525,18 +5742,18 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
if (ri->getSensorType() == ST_FUJI_XTRANS) {
const double compval = clipHigh / initialGain;
#ifdef _OPENMP
- #pragma omp parallel
+ #pragma omp parallel
#endif
{
double avg_c[3] = {0.0};
int cn[3] = {0};
#ifdef _OPENMP
- #pragma omp for schedule(dynamic,16) nowait
+ #pragma omp for schedule(dynamic,16) nowait
#endif
for (int i = 32; i < H - 32; i++) {
for (int j = 32; j < W - 32; j++) {
- // each loop read 1 rgb triplet value
+ // each loop read 1 rgb triplet value
double d = rawData[i][j];
if (d > compval) {
@@ -5550,7 +5767,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
}
#ifdef _OPENMP
- #pragma omp critical
+ #pragma omp critical
#endif
{
avg_r += avg_c[0];
@@ -5567,9 +5784,9 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
} else {
for (int i = 32; i < H - 32; i++)
for (int j = 32; j < W - 32; j++) {
- // each loop read 1 rgb triplet value
+ // each loop read 1 rgb triplet value
- double dr = CLIP(initialGain * (rawData[i][3 * j] ));
+ double dr = CLIP(initialGain * (rawData[i][3 * j]));
double dg = CLIP(initialGain * (rawData[i][3 * j + 1]));
double db = CLIP(initialGain * (rawData[i][3 * j + 2]));
@@ -5587,7 +5804,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
bn = rn;
}
} else {
- //determine GRBG coset; (ey,ex) is the offset of the R subarray
+ //determine GRBG coset; (ey,ex) is the offset of the R subarray
int ey, ex;
if (ri->ISGREEN(0, 0)) { //first pixel is G
@@ -5610,12 +5827,12 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
const double compval = clipHigh / initialGain;
#ifdef _OPENMP
- #pragma omp parallel for reduction(+:avg_r,avg_g,avg_b,rn,gn,bn) schedule(dynamic,8)
+ #pragma omp parallel for reduction(+:avg_r,avg_g,avg_b,rn,gn,bn) schedule(dynamic,8)
#endif
for (int i = 32; i < H - 32; i += 2)
for (int j = 32; j < W - 32; j += 2) {
- //average each Bayer quartet component individually if non-clipped
+ //average each Bayer quartet component individually if non-clipped
double d[2][2];
d[0][0] = rawData[i][j];
d[0][1] = rawData[i][j + 1];
@@ -5654,6 +5871,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
if (wbpar.method == "autitcgreen") {
bool twotimes = false;
int precision = 5;
+
if (settings->itcwb_precis == 5) {
precision = 5;
} else if (settings->itcwb_precis < 5) {
@@ -5664,7 +5882,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
const int bfw = W / precision + ((W % precision) > 0 ? 1 : 0);// 5 arbitrary value can be change to 3 or 9 ;
const int bfh = H / precision + ((H % precision) > 0 ? 1 : 0);
- WBauto(tempref, greenref, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, tempitc, greenitc, studgood, twotimes, wbpar, begx, begy, yEn, xEn, cx, cy, cmp, raw);
+ WBauto(tempref, greenref, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, tempitc, greenitc, studgood, twotimes, wbpar, begx, begy, yEn, xEn, cx, cy, cmp, raw, hrp);
}
redloc(0, 0);
@@ -5672,7 +5890,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
blueloc(0, 0);
if (settings->verbose) {
- printf ("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn));
+ printf("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn));
}
if (wbpar.method == "autitcgreen") {
@@ -5691,7 +5909,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref
}
-void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm)
+void RawImageSource::getAutoWBMultipliers(double &rm, double &gm, double &bm)
{
// BENCHFUN
constexpr double clipHigh = 64000.0;
@@ -5728,7 +5946,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm)
for (int j = start; j < end; j++) {
if (ri->getSensorType() != ST_BAYER) {
- double dr = CLIP(initialGain * (rawData[i][3 * j] ));
+ double dr = CLIP(initialGain * (rawData[i][3 * j]));
double dg = CLIP(initialGain * (rawData[i][3 * j + 1]));
double db = CLIP(initialGain * (rawData[i][3 * j + 2]));
@@ -5811,7 +6029,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm)
for (int j = 32; j < W - 32; j++) {
// each loop read 1 rgb triplet value
- double dr = CLIP(initialGain * (rawData[i][3 * j] ));
+ double dr = CLIP(initialGain * (rawData[i][3 * j]));
double dg = CLIP(initialGain * (rawData[i][3 * j + 1]));
double db = CLIP(initialGain * (rawData[i][3 * j + 2]));
@@ -5893,7 +6111,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm)
}
if (settings->verbose) {
- printf ("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn));
+ printf("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn));
}
// return ColorTemp (pow(avg_r/rn, 1.0/6.0)*img_r, pow(avg_g/gn, 1.0/6.0)*img_g, pow(avg_b/bn, 1.0/6.0)*img_b);
diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h
index 50b59e9dd..273271256 100644
--- a/rtengine/rawimagesource.h
+++ b/rtengine/rawimagesource.h
@@ -112,7 +112,7 @@ protected:
void hlRecovery(const std::string &method, float* red, float* green, float* blue, int width, float* hlmax);
void transformRect(const PreviewProps &pp, int tran, int &sx1, int &sy1, int &width, int &height, int &fw);
void transformPosition(int x, int y, int tran, int& tx, int& ty);
- void ItcWB(bool extra, double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::WBParams & wbpar);
+ void ItcWB(bool extra, double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::WBParams & wbpar, const procparams::ToneCurveParams &hrp);
unsigned FC(int row, int col) const;
inline void getRowStartEnd (int x, int &start, int &end);
@@ -141,12 +141,12 @@ public:
void processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, array2D &rawData, const float black[4]);
void copyOriginalPixels(const procparams::RAWParams &raw, RawImage *ri, const 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
- void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) override;
- void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) override;
+ void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) override;
+ void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) override;
void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) override;
void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const override;
- void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw) override;
+ void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw, int opposed) override;
eSensorType getSensorType () const override;
bool isMono () const override;
ColorTemp getWB () const override
@@ -199,7 +199,8 @@ public:
void MSR(float** luminance, float **originalLuminance, float **exLuminance, const LUTf& mapcurve, bool mapcontlutili, int width, int height, const procparams::RetinexParams &deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax);
void HLRecovery_inpaint (float** red, float** green, float** blue, int blur);
- static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval);
+ void highlight_recovery_opposed(float scale_mul[3], const ColorTemp &wb, float gainth);
+ static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval);
static void HLRecovery_CIELab (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval, double cam[3][3], double icam[3][3]);
static void HLRecovery_blend (float* rin, float* gin, float* bin, int width, float maxval, float* hlmax);
static void init ();
@@ -310,6 +311,9 @@ protected:
void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override;
void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) override;
void applyDngGainMap(const float black[4], const std::vector &gainMaps);
+public:
+ void wbMul2Camera(double &rm, double &gm, double &bm) override;
+ void wbCamera2Mul(double &rm, double &gm, double &bm) override;
};
}
diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc
index 3916adfbe..eb4a3f888 100644
--- a/rtengine/refreshmap.cc
+++ b/rtengine/refreshmap.cc
@@ -94,7 +94,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = {
HDR, // EvCACorr,
ALLNORAW, // EvHREnabled,
0, // EvHRAmount : obsolete,
- ALLNORAW, // EvHRMethod,
+ ALLNORAW|M_RAW, // EvHRMethod,
DEMOSAIC, // EvWProfile,
OUTPUTPROFILE, // EvOProfile,
ALLNORAW, // EvIProfile,
diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc
index ccbbb5f21..86fa60d57 100644
--- a/rtengine/rtthumbnail.cc
+++ b/rtengine/rtthumbnail.cc
@@ -349,7 +349,7 @@ Image8 *load_inspector_mode(const Glib::ustring &fname, eSensorType &sensorType,
PreviewProps pp(0, 0, w, h, 1);
Imagefloat tmp(w, h);
- src.getImage(src.getWB(), TR_NONE, &tmp, pp, neutral.toneCurve, neutral.raw);
+ src.getImage(src.getWB(), TR_NONE, &tmp, pp, neutral.toneCurve, neutral.raw, 0);
src.convertColorSpace(&tmp, neutral.icm, src.getWB());
Image8 *img = new Image8(w, h);
diff --git a/rtengine/settings.h b/rtengine/settings.h
index d804b010f..3544bc310 100644
--- a/rtengine/settings.h
+++ b/rtengine/settings.h
@@ -45,6 +45,7 @@ public:
bool monitorBPC; ///< Black Point Compensation for the Labimage->Monitor transform (directly, i.e. not soft-proofing and no WCS in between)
bool autoMonitorProfile; ///< Try to auto-determine the correct monitor color profile
bool autocielab;
+ bool observer10;
bool rgbcurveslumamode_gamut;// controls gamut enforcement for RGB curves in lumamode
bool verbose;
Glib::ustring darkFramesPath; ///< The default directory for dark frames
@@ -95,7 +96,7 @@ public:
// bool showtooltip;
int itcwb_thres;
- bool itcwb_sort;
+ bool itcwb_sorted;
int itcwb_greenrange;
int itcwb_greendeltatemp;
bool itcwb_forceextra;
@@ -103,6 +104,7 @@ public:
int itcwb_delta;
bool itcwb_stdobserver10;
int itcwb_precis;
+ bool itcwb_nopurple;
//wavelet levels
double edghi;
double edglo;
diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc
index a951aa456..55102bdf0 100644
--- a/rtengine/simpleprocess.cc
+++ b/rtengine/simpleprocess.cc
@@ -262,7 +262,7 @@ private:
pl->setProgress(0.40);
}
- imgsrc->HLRecovery_Global(params.toneCurve);
+ // imgsrc->HLRecovery_Global(params.toneCurve);
if (pl) {
@@ -373,7 +373,7 @@ private:
int beg_tileW = wcr * tileWskip + tileWskip / 2.f - crW / 2.f;
int beg_tileH = hcr * tileHskip + tileHskip / 2.f - crH / 2.f;
PreviewProps ppP(beg_tileW, beg_tileH, crW, crH, skipP);
- imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw);
+ imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0);
//baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve);
// we only need image reduced to 1/4 here
@@ -597,7 +597,7 @@ private:
for (int wcr = 0; wcr <= 2; wcr++) {
for (int hcr = 0; hcr <= 2; hcr++) {
PreviewProps ppP(coordW[wcr], coordH[hcr], crW, crH, 1);
- imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw);
+ imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0);
//baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve);
@@ -757,7 +757,7 @@ private:
}
baseImg = new Imagefloat(fw, fh);
- imgsrc->getImage(currWB, tr, baseImg, pp, params.toneCurve, params.raw);
+ imgsrc->getImage(currWB, tr, baseImg, pp, params.toneCurve, params.raw, 1);
if (pl) {
pl->setProgress(0.50);
diff --git a/rtengine/spot.cc b/rtengine/spot.cc
index 5ed090712..09186a399 100644
--- a/rtengine/spot.cc
+++ b/rtengine/spot.cc
@@ -459,7 +459,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s
}
}
- imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw);
+ imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw, 0);
if (cmp) {
imgsrc->convertColorSpace(srcImage, *cmp, currWB);
}
@@ -479,7 +479,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s
dstImage->b(y, x) = 60000.f;
}
}
- imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw);
+ imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw, 0);
if (cmp) {
imgsrc->convertColorSpace(dstImage, *cmp, currWB);
}
diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc
index 8cb8fa792..a3f2502f0 100644
--- a/rtengine/stdimagesource.cc
+++ b/rtengine/stdimagesource.cc
@@ -193,7 +193,7 @@ int StdImageSource::load (const Glib::ustring &fname)
return 0;
}
-void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw)
+void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw, int opposed)
{
// the code will use OpenMP as of now.
@@ -311,11 +311,11 @@ void StdImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr)
}
}
-void StdImageSource::WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams &cmp, const RAWParams &raw)
+void StdImageSource::WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams &cmp, const RAWParams &raw, const ToneCurveParams &hrp)
{
}
-void StdImageSource::getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const WBParams & wbpar, const ColorManagementParams &cmp, const RAWParams &raw)
+void StdImageSource::getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const WBParams & wbpar, const ColorManagementParams &cmp, const RAWParams &raw, const ToneCurveParams &hrp)
{
if (redAWBMul != -1.) {
rm = redAWBMul;
@@ -324,7 +324,7 @@ void StdImageSource::getAutoWBMultipliersitc(double &tempref, double &greenref,
return;
}
- img->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc,studgood, begx, begy, yEn, xEn, cx, cy, bf_h, bf_w, rm, gm, bm, params->wb, params->icm, params->raw);
+ img->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc,studgood, begx, begy, yEn, xEn, cx, cy, bf_h, bf_w, rm, gm, bm, params->wb, params->icm, params->raw, params->toneCurve);
redAWBMul = rm;
greenAWBMul = gm;
@@ -367,6 +367,20 @@ void StdImageSource::flush() {
img->allocate(0, 0);
};
+void StdImageSource::wbMul2Camera(double &rm, double &gm, double &bm)
+{
+ rm = 1.0 / rm;
+ gm = 1.0 / gm;
+ bm = 1.0 / bm;
+}
+
+
+void StdImageSource::wbCamera2Mul(double &rm, double &gm, double &bm)
+{
+ rm = 1.0 / rm;
+ gm = 1.0 / gm;
+ bm = 1.0 / bm;
+}
}
diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h
index f83c58a04..90c4be654 100644
--- a/rtengine/stdimagesource.h
+++ b/rtengine/stdimagesource.h
@@ -58,7 +58,7 @@ public:
int load (const Glib::ustring &fname) override;
void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const override {};
- void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw) override;
+ void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw, int opposed) override;
void getrgbloc (int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) override {};
ColorTemp getWB () const override
{
@@ -66,8 +66,8 @@ public:
}
void getAutoWBMultipliers (double &rm, double &gm, double &bm) override;
ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) override;
- void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) override;
- void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) override;
+ void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) override;
+ void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) override;
eSensorType getSensorType() const override {return ST_NONE;}
bool isMono() const override {return false;}
@@ -123,6 +123,8 @@ public:
void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override { R = G = B = 0;}
+ void wbMul2Camera(double &rm, double &gm, double &bm) override;
+ void wbCamera2Mul(double &rm, double &gm, double &bm) override;
void flush () override;
void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) override {};
diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt
index 8d2f38225..cb5126631 100644
--- a/rtgui/CMakeLists.txt
+++ b/rtgui/CMakeLists.txt
@@ -162,6 +162,7 @@ set(NONCLISOURCEFILES
thumbnail.cc
tonecurve.cc
toolbar.cc
+ toollocationpref.cc
toolpanel.cc
toolpanelcoord.cc
vibrance.cc
diff --git a/rtgui/bayerpreprocess.cc b/rtgui/bayerpreprocess.cc
index 793496b5f..e8b965736 100644
--- a/rtgui/bayerpreprocess.cc
+++ b/rtgui/bayerpreprocess.cc
@@ -28,7 +28,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-BayerPreProcess::BayerPreProcess() : FoldableToolPanel(this, "bayerpreprocess", M("TP_PREPROCESS_LABEL"), options.prevdemo != PD_Sidecar)
+const Glib::ustring BayerPreProcess::TOOL_NAME = "bayerpreprocess";
+
+BayerPreProcess::BayerPreProcess() : FoldableToolPanel(this, TOOL_NAME, M("TP_PREPROCESS_LABEL"), options.prevdemo != PD_Sidecar)
{
auto m = ProcEventMapper::getInstance();
EvLineDenoiseDirection = m->newEvent(DARKFRAME, "HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION");
diff --git a/rtgui/bayerpreprocess.h b/rtgui/bayerpreprocess.h
index 16b469626..8b5f8d981 100644
--- a/rtgui/bayerpreprocess.h
+++ b/rtgui/bayerpreprocess.h
@@ -37,6 +37,7 @@ protected:
rtengine::ProcEvent EvPDAFLinesFilter;
public:
+ static const Glib::ustring TOOL_NAME;
BayerPreProcess ();
diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc
index 4d1657a47..e7e038e52 100644
--- a/rtgui/bayerprocess.cc
+++ b/rtgui/bayerprocess.cc
@@ -28,9 +28,10 @@
using namespace rtengine;
using namespace rtengine::procparams;
+const Glib::ustring BayerProcess::TOOL_NAME = "bayerprocess";
BayerProcess::BayerProcess () :
- FoldableToolPanel(this, "bayerprocess", M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar),
+ FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar),
oldMethod(-1)
{
diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h
index b9c63e9b2..00a5c8aac 100644
--- a/rtgui/bayerprocess.h
+++ b/rtgui/bayerprocess.h
@@ -76,6 +76,7 @@ protected:
rtengine::ProcEvent EvDemosaicPixelshiftDemosaicMethod;
rtengine::ProcEvent EvPixelshiftAverage;
public:
+ static const Glib::ustring TOOL_NAME;
BayerProcess ();
~BayerProcess () override;
diff --git a/rtgui/bayerrawexposure.cc b/rtgui/bayerrawexposure.cc
index 157abc2cf..834384a91 100644
--- a/rtgui/bayerrawexposure.cc
+++ b/rtgui/bayerrawexposure.cc
@@ -26,7 +26,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, "bayerrawexposure", M("TP_EXPOS_BLACKPOINT_LABEL"), options.prevdemo != PD_Sidecar)
+const Glib::ustring BayerRAWExposure::TOOL_NAME = "bayerrawexposure";
+
+BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOS_BLACKPOINT_LABEL"), options.prevdemo != PD_Sidecar)
{
PexBlack1 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_1"), -2048, 2048, 1.0, 0)); //black level
PexBlack1->setAdjusterListener (this);
diff --git a/rtgui/bayerrawexposure.h b/rtgui/bayerrawexposure.h
index eb18aa0e3..53c5817f8 100644
--- a/rtgui/bayerrawexposure.h
+++ b/rtgui/bayerrawexposure.h
@@ -31,6 +31,8 @@ class BayerRAWExposure final :
public FoldableToolPanel
{
public:
+ static const Glib::ustring TOOL_NAME;
+
BayerRAWExposure ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override;
diff --git a/rtgui/blackwhite.cc b/rtgui/blackwhite.cc
index d869903b5..6e618ea3b 100644
--- a/rtgui/blackwhite.cc
+++ b/rtgui/blackwhite.cc
@@ -34,8 +34,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
+const Glib::ustring BlackWhite::TOOL_NAME = "blackwhite";
-BlackWhite::BlackWhite (): FoldableToolPanel(this, "blackwhite", M("TP_BWMIX_LABEL"), false, true)
+BlackWhite::BlackWhite (): FoldableToolPanel(this, TOOL_NAME, M("TP_BWMIX_LABEL"), false, true)
{
CurveListener::setMulti(true);
diff --git a/rtgui/blackwhite.h b/rtgui/blackwhite.h
index 505d842db..fe41ccda0 100644
--- a/rtgui/blackwhite.h
+++ b/rtgui/blackwhite.h
@@ -40,6 +40,7 @@ class BlackWhite final :
public ColorProvider
{
public:
+ static const Glib::ustring TOOL_NAME;
BlackWhite ();
~BlackWhite () override;
diff --git a/rtgui/cacorrection.cc b/rtgui/cacorrection.cc
index 971c0a284..52ed782df 100644
--- a/rtgui/cacorrection.cc
+++ b/rtgui/cacorrection.cc
@@ -27,7 +27,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-CACorrection::CACorrection () : FoldableToolPanel(this, "cacorrection", M("TP_CACORRECTION_LABEL"))
+const Glib::ustring CACorrection::TOOL_NAME = "cacorrection";
+
+CACorrection::CACorrection () : FoldableToolPanel(this, TOOL_NAME, M("TP_CACORRECTION_LABEL"))
{
Gtk::Image* icaredL = Gtk::manage (new RTImage ("circle-red-cyan-small.png"));
diff --git a/rtgui/cacorrection.h b/rtgui/cacorrection.h
index 12d6396eb..7afccb4de 100644
--- a/rtgui/cacorrection.h
+++ b/rtgui/cacorrection.h
@@ -34,6 +34,7 @@ protected:
Adjuster* blue;
public:
+ static const Glib::ustring TOOL_NAME;
CACorrection ();
diff --git a/rtgui/chmixer.cc b/rtgui/chmixer.cc
index 619d7be3e..e54ddfc5d 100644
--- a/rtgui/chmixer.cc
+++ b/rtgui/chmixer.cc
@@ -25,7 +25,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-ChMixer::ChMixer (): FoldableToolPanel(this, "chmixer", M("TP_CHMIXER_LABEL"), false, true)
+const Glib::ustring ChMixer::TOOL_NAME = "chmixer";
+
+ChMixer::ChMixer (): FoldableToolPanel(this, TOOL_NAME, M("TP_CHMIXER_LABEL"), false, true)
{
imgIcon[0] = Gtk::manage (new RTImage ("circle-red-small.png"));
diff --git a/rtgui/chmixer.h b/rtgui/chmixer.h
index d80b89cf7..831449c30 100644
--- a/rtgui/chmixer.h
+++ b/rtgui/chmixer.h
@@ -36,6 +36,7 @@ protected:
Gtk::Image *imgIcon[9];
public:
+ static const Glib::ustring TOOL_NAME;
ChMixer ();
diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc
index 89661a884..5531a55c8 100644
--- a/rtgui/colorappearance.cc
+++ b/rtgui/colorappearance.cc
@@ -44,6 +44,8 @@
using namespace rtengine;
using namespace rtengine::procparams;
+const Glib::ustring ColorAppearance::TOOL_NAME = "colorappearance";
+
static double wbSlider2Temp (double sval)
{
@@ -212,7 +214,7 @@ static double wbTemp2Slider (double temp)
}
-ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance", M ("TP_COLORAPP_LABEL"), false, true)
+ColorAppearance::ColorAppearance () : FoldableToolPanel (this, TOOL_NAME, M ("TP_COLORAPP_LABEL"), false, true)
{
CurveListener::setMulti (true);
std::vector milestones;
diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h
index d3953c11f..dcf19b977 100644
--- a/rtgui/colorappearance.h
+++ b/rtgui/colorappearance.h
@@ -39,6 +39,8 @@ class ColorAppearance final :
public ColorProvider
{
public:
+ static const Glib::ustring TOOL_NAME;
+
ColorAppearance ();
~ColorAppearance () override;
diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc
index 019bedff6..d9928cd13 100644
--- a/rtgui/colortoning.cc
+++ b/rtgui/colortoning.cc
@@ -14,6 +14,7 @@
using namespace rtengine;
using namespace rtengine::procparams;
+const Glib::ustring ColorToning::TOOL_NAME = "colortoning";
namespace {
@@ -33,7 +34,7 @@ inline float round_ab(float v)
} // namespace
-ColorToning::ColorToning () : FoldableToolPanel(this, "colortoning", M("TP_COLORTONING_LABEL"), false, true)
+ColorToning::ColorToning () : FoldableToolPanel(this, TOOL_NAME, M("TP_COLORTONING_LABEL"), false, true)
{
nextbw = 0;
CurveListener::setMulti(true);
diff --git a/rtgui/colortoning.h b/rtgui/colortoning.h
index be3a83c2d..e763a069c 100644
--- a/rtgui/colortoning.h
+++ b/rtgui/colortoning.h
@@ -30,6 +30,8 @@ class ColorToning final :
public AdjusterListener
{
public:
+ static const Glib::ustring TOOL_NAME;
+
ColorToning ();
~ColorToning() override;
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override;
diff --git a/rtgui/crop.cc b/rtgui/crop.cc
index 853cec255..21a32b653 100644
--- a/rtgui/crop.cc
+++ b/rtgui/crop.cc
@@ -29,6 +29,8 @@
using namespace rtengine;
using namespace rtengine::procparams;
+const Glib::ustring Crop::TOOL_NAME = "crop";
+
namespace
{
@@ -124,7 +126,7 @@ private:
};
Crop::Crop():
- FoldableToolPanel(this, "crop", M("TP_CROP_LABEL"), false, true),
+ FoldableToolPanel(this, TOOL_NAME, M("TP_CROP_LABEL"), false, true),
crop_ratios(new CropRatios),
opt(0),
wDirty(true),
diff --git a/rtgui/crop.h b/rtgui/crop.h
index c6636b917..83eb6bbbb 100644
--- a/rtgui/crop.h
+++ b/rtgui/crop.h
@@ -41,6 +41,8 @@ class Crop final :
public rtengine::SizeListener
{
public:
+ static const Glib::ustring TOOL_NAME;
+
Crop();
~Crop() override;
diff --git a/rtgui/darkframe.cc b/rtgui/darkframe.cc
index 5c71d9918..83c7fe81c 100644
--- a/rtgui/darkframe.cc
+++ b/rtgui/darkframe.cc
@@ -30,7 +30,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-DarkFrame::DarkFrame () : FoldableToolPanel(this, "darkframe", M("TP_DARKFRAME_LABEL")), dfChanged(false), lastDFauto(false), dfp(nullptr), israw(true)
+const Glib::ustring DarkFrame::TOOL_NAME = "darkframe";
+
+DarkFrame::DarkFrame () : FoldableToolPanel(this, TOOL_NAME, M("TP_DARKFRAME_LABEL")), dfChanged(false), lastDFauto(false), dfp(nullptr), israw(true)
{
hbdf = Gtk::manage(new Gtk::Box());
hbdf->set_spacing(4);
diff --git a/rtgui/darkframe.h b/rtgui/darkframe.h
index cbd7816d6..086ee7ec5 100644
--- a/rtgui/darkframe.h
+++ b/rtgui/darkframe.h
@@ -62,6 +62,7 @@ protected:
bool israw;
public:
+ static const Glib::ustring TOOL_NAME;
DarkFrame ();
diff --git a/rtgui/defringe.cc b/rtgui/defringe.cc
index 7aae8377a..72388ac8c 100644
--- a/rtgui/defringe.cc
+++ b/rtgui/defringe.cc
@@ -30,7 +30,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-Defringe::Defringe () : FoldableToolPanel(this, "defringe", M("TP_DEFRINGE_LABEL"), true, true)
+const Glib::ustring Defringe::TOOL_NAME = "defringe";
+
+Defringe::Defringe () : FoldableToolPanel(this, TOOL_NAME, M("TP_DEFRINGE_LABEL"), true, true)
{
std::vector bottomMilestones;
diff --git a/rtgui/defringe.h b/rtgui/defringe.h
index ebf1eecd8..d939ff926 100644
--- a/rtgui/defringe.h
+++ b/rtgui/defringe.h
@@ -46,6 +46,7 @@ protected:
bool edges;
public:
+ static const Glib::ustring TOOL_NAME;
Defringe ();
~Defringe () override;
diff --git a/rtgui/dehaze.cc b/rtgui/dehaze.cc
index 76d309afc..b77b76945 100644
--- a/rtgui/dehaze.cc
+++ b/rtgui/dehaze.cc
@@ -29,7 +29,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-Dehaze::Dehaze(): FoldableToolPanel(this, "dehaze", M("TP_DEHAZE_LABEL"), false, true)
+const Glib::ustring Dehaze::TOOL_NAME = "dehaze";
+
+Dehaze::Dehaze(): FoldableToolPanel(this, TOOL_NAME, M("TP_DEHAZE_LABEL"), false, true)
{
auto m = ProcEventMapper::getInstance();
EvDehazeEnabled = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_ENABLED");
diff --git a/rtgui/dehaze.h b/rtgui/dehaze.h
index 155efa522..1da50d7dd 100644
--- a/rtgui/dehaze.h
+++ b/rtgui/dehaze.h
@@ -39,6 +39,7 @@ private:
rtengine::ProcEvent EvDehazeSaturation;
public:
+ static const Glib::ustring TOOL_NAME;
Dehaze();
diff --git a/rtgui/dirpyrdenoise.cc b/rtgui/dirpyrdenoise.cc
index 3bf7c21f4..f2b780eba 100644
--- a/rtgui/dirpyrdenoise.cc
+++ b/rtgui/dirpyrdenoise.cc
@@ -33,7 +33,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-DirPyrDenoise::DirPyrDenoise () : FoldableToolPanel(this, "dirpyrdenoise", M("TP_DIRPYRDENOISE_LABEL"), true, true), lastmedian(false)
+const Glib::ustring DirPyrDenoise::TOOL_NAME = "dirpyrdenoise";
+
+DirPyrDenoise::DirPyrDenoise () : FoldableToolPanel(this, TOOL_NAME, M("TP_DIRPYRDENOISE_LABEL"), true, true), lastmedian(false)
{
std::vector milestones;
CurveListener::setMulti(true);
diff --git a/rtgui/dirpyrdenoise.h b/rtgui/dirpyrdenoise.h
index 71c9b1894..dadd96988 100644
--- a/rtgui/dirpyrdenoise.h
+++ b/rtgui/dirpyrdenoise.h
@@ -40,6 +40,8 @@ class DirPyrDenoise final :
public ColorProvider
{
public:
+ static const Glib::ustring TOOL_NAME;
+
DirPyrDenoise ();
~DirPyrDenoise () override;
diff --git a/rtgui/dirpyrequalizer.cc b/rtgui/dirpyrequalizer.cc
index 9393d7c42..46966ea45 100644
--- a/rtgui/dirpyrequalizer.cc
+++ b/rtgui/dirpyrequalizer.cc
@@ -24,7 +24,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-DirPyrEqualizer::DirPyrEqualizer () : FoldableToolPanel(this, "dirpyrequalizer", M("TP_DIRPYREQUALIZER_LABEL"), true, true)
+const Glib::ustring DirPyrEqualizer::TOOL_NAME = "dirpyrequalizer";
+
+DirPyrEqualizer::DirPyrEqualizer () : FoldableToolPanel(this, TOOL_NAME, M("TP_DIRPYREQUALIZER_LABEL"), true, true)
{
std::vector milestones;
diff --git a/rtgui/dirpyrequalizer.h b/rtgui/dirpyrequalizer.h
index bb03e1a53..39b201b9b 100644
--- a/rtgui/dirpyrequalizer.h
+++ b/rtgui/dirpyrequalizer.h
@@ -56,6 +56,7 @@ protected:
bool lastgamutlab;
public:
+ static const Glib::ustring TOOL_NAME;
DirPyrEqualizer ();
~DirPyrEqualizer () override;
diff --git a/rtgui/distortion.cc b/rtgui/distortion.cc
index 6e2bd7a35..a5138eb99 100644
--- a/rtgui/distortion.cc
+++ b/rtgui/distortion.cc
@@ -27,7 +27,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-Distortion::Distortion (): FoldableToolPanel(this, "distortion", M("TP_DISTORTION_LABEL"))
+const Glib::ustring Distortion::TOOL_NAME = "distortion";
+
+Distortion::Distortion (): FoldableToolPanel(this, TOOL_NAME, M("TP_DISTORTION_LABEL"))
{
rlistener = nullptr;
diff --git a/rtgui/distortion.h b/rtgui/distortion.h
index 7ef33d73a..98044bacf 100644
--- a/rtgui/distortion.h
+++ b/rtgui/distortion.h
@@ -37,6 +37,7 @@ protected:
LensGeomListener * rlistener;
public:
+ static const Glib::ustring TOOL_NAME;
Distortion ();
diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc
index 8e62805c6..0e5a2d515 100644
--- a/rtgui/editorpanel.cc
+++ b/rtgui/editorpanel.cc
@@ -2864,6 +2864,13 @@ void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition)
}
+void EditorPanel::updateToolPanelToolLocations(
+ const std::vector &favorites, bool cloneFavoriteTools)
+{
+ if (tpc) {
+ tpc->updateToolLocations(favorites, cloneFavoriteTools);
+ }
+}
void EditorPanel::defaultMonitorProfileChanged (const Glib::ustring &profile_name, bool auto_monitor_profile)
{
diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h
index fa7f7943b..98a475a7c 100644
--- a/rtgui/editorpanel.h
+++ b/rtgui/editorpanel.h
@@ -197,6 +197,8 @@ public:
void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC);
void updateTPVScrollbar (bool hide);
void updateHistogramPosition (int oldPosition, int newPosition);
+ void updateToolPanelToolLocations(
+ const std::vector &favorites, bool cloneFavoriteTools);
void defaultMonitorProfileChanged (const Glib::ustring &profile_name, bool auto_monitor_profile);
diff --git a/rtgui/editwindow.cc b/rtgui/editwindow.cc
index 0584edf77..0364b0afa 100644
--- a/rtgui/editwindow.cc
+++ b/rtgui/editwindow.cc
@@ -487,3 +487,11 @@ void EditWindow::set_title_decorated(Glib::ustring fname)
set_title("RawTherapee " + M("EDITWINDOW_TITLE") + subtitle);
}
+
+void EditWindow::updateToolPanelToolLocations(
+ const std::vector &favorites, bool cloneFavoriteTools)
+{
+ for (const auto& panel : epanels) {
+ panel.second->updateToolPanelToolLocations(favorites, cloneFavoriteTools);
+ }
+}
diff --git a/rtgui/editwindow.h b/rtgui/editwindow.h
index 27d4598c1..0b10cb67e 100644
--- a/rtgui/editwindow.h
+++ b/rtgui/editwindow.h
@@ -66,6 +66,8 @@ public:
bool selectEditorPanel(const std::string &name);
bool closeOpenEditors();
bool isProcessing();
+ void updateToolPanelToolLocations(
+ const std::vector &favorites, bool cloneFavoriteTools);
void toFront();
bool keyPressed (GdkEventKey* event);
diff --git a/rtgui/epd.cc b/rtgui/epd.cc
index d032cf28d..073c5ecdd 100644
--- a/rtgui/epd.cc
+++ b/rtgui/epd.cc
@@ -26,7 +26,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-EdgePreservingDecompositionUI::EdgePreservingDecompositionUI () : FoldableToolPanel(this, "epd", M("TP_EPD_LABEL"), true, true)
+const Glib::ustring EdgePreservingDecompositionUI::TOOL_NAME = "epd";
+
+EdgePreservingDecompositionUI::EdgePreservingDecompositionUI () : FoldableToolPanel(this, TOOL_NAME, M("TP_EPD_LABEL"), true, true)
{
strength = Gtk::manage(new Adjuster (M("TP_EPD_STRENGTH"), -1.0, 2.0, 0.01, 0.5));
diff --git a/rtgui/epd.h b/rtgui/epd.h
index 6a5160623..1d866d690 100644
--- a/rtgui/epd.h
+++ b/rtgui/epd.h
@@ -36,6 +36,7 @@ protected:
Adjuster *reweightingIterates;
public:
+ static const Glib::ustring TOOL_NAME;
EdgePreservingDecompositionUI();
diff --git a/rtgui/fattaltonemap.cc b/rtgui/fattaltonemap.cc
index 89a1e9e30..d4ed90612 100644
--- a/rtgui/fattaltonemap.cc
+++ b/rtgui/fattaltonemap.cc
@@ -31,7 +31,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-FattalToneMapping::FattalToneMapping(): FoldableToolPanel(this, "fattal", M("TP_TM_FATTAL_LABEL"), true, true)
+const Glib::ustring FattalToneMapping::TOOL_NAME = "fattal";
+
+FattalToneMapping::FattalToneMapping(): FoldableToolPanel(this, TOOL_NAME, M("TP_TM_FATTAL_LABEL"), true, true)
{
auto m = ProcEventMapper::getInstance();
EvTMFattalAnchor = m->newEvent(HDR, "HISTORY_MSG_TM_FATTAL_ANCHOR");
diff --git a/rtgui/fattaltonemap.h b/rtgui/fattaltonemap.h
index 3d36ec7d2..f5c19f15c 100644
--- a/rtgui/fattaltonemap.h
+++ b/rtgui/fattaltonemap.h
@@ -33,6 +33,7 @@ protected:
rtengine::ProcEvent EvTMFattalAnchor;
public:
+ static const Glib::ustring TOOL_NAME;
FattalToneMapping();
diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc
index 9dc2a656c..adcd6985d 100644
--- a/rtgui/filepanel.cc
+++ b/rtgui/filepanel.cc
@@ -437,3 +437,11 @@ void FilePanel::updateTPVScrollbar (bool hide)
{
tpc->updateTPVScrollbar (hide);
}
+
+void FilePanel::updateToolPanelToolLocations(
+ const std::vector &favorites, bool cloneFavoriteTools)
+{
+ if (tpc) {
+ tpc->updateToolLocations(favorites, cloneFavoriteTools);
+ }
+}
diff --git a/rtgui/filepanel.h b/rtgui/filepanel.h
index ba5dfa7c9..4a006f002 100644
--- a/rtgui/filepanel.h
+++ b/rtgui/filepanel.h
@@ -83,6 +83,8 @@ public:
bool handleShortcutKey (GdkEventKey* event);
bool handleShortcutKeyRelease(GdkEventKey *event);
void updateTPVScrollbar (bool hide);
+ void updateToolPanelToolLocations(
+ const std::vector &favorites, bool cloneFavoriteTools);
private:
void on_NB_switch_page(Gtk::Widget* page, guint page_num);
diff --git a/rtgui/filmnegative.cc b/rtgui/filmnegative.cc
index dca041c9b..f1d3aaf45 100644
--- a/rtgui/filmnegative.cc
+++ b/rtgui/filmnegative.cc
@@ -28,6 +28,8 @@
#include "../rtengine/procparams.h"
#include "../rtengine/color.h"
+const Glib::ustring FilmNegative::TOOL_NAME = "filmnegative";
+
namespace
{
@@ -184,7 +186,7 @@ void rgb2temp(const RGB &refOut, double &outLev, double &temp, double &green)
}
FilmNegative::FilmNegative() :
- FoldableToolPanel(this, "filmnegative", M("TP_FILMNEGATIVE_LABEL"), false, true),
+ FoldableToolPanel(this, TOOL_NAME, M("TP_FILMNEGATIVE_LABEL"), false, true),
EditSubscriber(ET_OBJECTS),
NEUTRAL_TEMP(rtengine::ColorTemp(1., 1., 1., 1.)),
evFilmNegativeExponents(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_VALUES")),
diff --git a/rtgui/filmnegative.h b/rtgui/filmnegative.h
index 21a7dce5c..722625fa2 100644
--- a/rtgui/filmnegative.h
+++ b/rtgui/filmnegative.h
@@ -52,6 +52,8 @@ class FilmNegative final :
public rtengine::FilmNegListener
{
public:
+ static const Glib::ustring TOOL_NAME;
+
FilmNegative();
~FilmNegative() override;
diff --git a/rtgui/filmsimulation.cc b/rtgui/filmsimulation.cc
index d19c84c6f..fb38f87dc 100644
--- a/rtgui/filmsimulation.cc
+++ b/rtgui/filmsimulation.cc
@@ -12,6 +12,8 @@
using namespace rtengine;
using namespace rtengine::procparams;
+const Glib::ustring FilmSimulation::TOOL_NAME = "filmsimulation";
+
namespace
{
@@ -61,7 +63,7 @@ bool notifySlowParseDir (const std::chrono::system_clock::time_point& startedAt)
}
FilmSimulation::FilmSimulation()
- : FoldableToolPanel( this, "filmsimulation", M("TP_FILMSIMULATION_LABEL"), false, true )
+ : FoldableToolPanel( this, TOOL_NAME, M("TP_FILMSIMULATION_LABEL"), false, true )
{
m_clutComboBox = Gtk::manage( new ClutComboBox(options.clutsDir) );
diff --git a/rtgui/filmsimulation.h b/rtgui/filmsimulation.h
index cfe7016bb..ed30b866e 100644
--- a/rtgui/filmsimulation.h
+++ b/rtgui/filmsimulation.h
@@ -56,6 +56,8 @@ private:
class FilmSimulation : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel
{
public:
+ static const Glib::ustring TOOL_NAME;
+
FilmSimulation();
void adjusterChanged(Adjuster* a, double newval) override;
diff --git a/rtgui/flatfield.cc b/rtgui/flatfield.cc
index f493ba0b9..21cdb4315 100644
--- a/rtgui/flatfield.cc
+++ b/rtgui/flatfield.cc
@@ -31,7 +31,9 @@
using namespace rtengine;
using namespace rtengine::procparams;
-FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_LABEL"))
+const Glib::ustring FlatField::TOOL_NAME = "flatfield";
+
+FlatField::FlatField () : FoldableToolPanel(this, TOOL_NAME, M("TP_FLATFIELD_LABEL"))
{
auto m = ProcEventMapper::getInstance();
EvFlatFieldFromMetaData = m->newEvent(DARKFRAME, "HISTORY_MSG_FF_FROMMETADATA");
diff --git a/rtgui/flatfield.h b/rtgui/flatfield.h
index be46d5a1d..efb8a2cec 100644
--- a/rtgui/flatfield.h
+++ b/rtgui/flatfield.h
@@ -71,6 +71,7 @@ protected:
IdleRegister idle_register;
public:
+ static const Glib::ustring TOOL_NAME;
FlatField ();
~FlatField () override;
diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc
index 1274da9ab..26be51975 100644
--- a/rtgui/gradient.cc
+++ b/rtgui/gradient.cc
@@ -25,7 +25,9 @@ enum GeometryIndex {
}
-Gradient::Gradient () : FoldableToolPanel(this, "gradient", M("TP_GRADIENT_LABEL"), false, true), EditSubscriber(ET_OBJECTS), lastObject(-1), draggedPointOldAngle(-1000.)
+const Glib::ustring Gradient::TOOL_NAME = "gradient";
+
+Gradient::Gradient () : FoldableToolPanel(this, TOOL_NAME, M("TP_GRADIENT_LABEL"), false, true), EditSubscriber(ET_OBJECTS), lastObject(-1), draggedPointOldAngle(-1000.)
{
editHBox = Gtk::manage (new Gtk::Box());
diff --git a/rtgui/gradient.h b/rtgui/gradient.h
index dc0371932..d7754007c 100644
--- a/rtgui/gradient.h
+++ b/rtgui/gradient.h
@@ -38,6 +38,7 @@ protected:
void releaseEdit();
public:
+ static const Glib::ustring TOOL_NAME;
Gradient ();
~Gradient () override;
diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h
index 938c81c42..152b626de 100644
--- a/rtgui/guiutils.h
+++ b/rtgui/guiutils.h
@@ -20,6 +20,7 @@
#include
#include