diff --git a/rtdata/languages/default b/rtdata/languages/default
index 278b0f5e3..ed0d098b2 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -650,7 +650,9 @@ HISTORY_MSG_417;Retinex - Transmission median
HISTORY_MSG_418;Retinex - Threshold
HISTORY_MSG_419;Retinex - Color space
HISTORY_MSG_420;Retinex - Histogram - HSL
-HISTORY_MSG_421;Retinex - Gamma
+HISTORY_MSG_421;Retinex - Gamma retinex
+HISTORY_MSG_422;Retinex - gamma
+HISTORY_MSG_423;Retinex - slope
HISTORY_NEWSNAPSHOT;Add
HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s
HISTORY_SNAPSHOTS;Snapshots
@@ -1561,11 +1563,14 @@ TP_RETINEX_CURVEEDITOR_CD;L=f(L)
TP_RETINEX_CURVEEDITOR_CD_TOOLTIP;Correct raw data to reduce halos and artifacts
TP_RETINEX_GAIN;Gain
TP_RETINEX_GAIN_TOOLTIP;Acts on the transmission in combination with offset, this is very different from others settings. Used for black or white pixels, and for better balance the histogram.
-TP_RETINEX_GAM;Gamma
+TP_RETINEX_GAM;Gamma retinex
TP_RETINEX_GAMMA_NONE;None
TP_RETINEX_GAMMA_LOW;Low
TP_RETINEX_GAMMA_MID;Middle
TP_RETINEX_GAMMA_HIGH;High
+TP_RETINEX_GAMMA_FREE;Free
+TP_RETINEX_GAMMA;Gamma
+TP_RETINEX_SLOPE;Slope
TP_RETINEX_GAMMA_TOOLTIP;Restore tones by applying gamma before and after Retinex\nDifferent from Retinex curves or others curves (Lab, Exposure,..)
TP_RETINEX_HIGH;High
TP_RETINEX_HSLSPACE_LIN;HSL-Linear
diff --git a/rtengine/color.cc b/rtengine/color.cc
index b403ee7dc..03a9bda93 100644
--- a/rtengine/color.cc
+++ b/rtengine/color.cc
@@ -233,7 +233,7 @@ void Color::init ()
for (int i = 0; i < 65536; i++) {
gammatab_26_11[i] = (65535.0 * gamma26_11 (i / 65535.0));
}
-
+//gammatab_145_3
for (int i = 0; i < 65536; i++) {
igammatab_26_11[i] = (65535.0 * igamma26_11 (i / 65535.0));
}
diff --git a/rtengine/color.h b/rtengine/color.h
index 53d5a8b19..1eb799cda 100644
--- a/rtengine/color.h
+++ b/rtengine/color.h
@@ -981,6 +981,17 @@ public:
{
return x <= 0.027345 ? x / 3.0 : exp(log((x + 0.012305) / 1.012305) * 1.45);
}
+
+//gamma for Retinex
+ static inline double gammareti (double x, double gamma, double start, double slope, double mul, double add)
+ {
+ return (x <= start ? x*slope : exp(log(x) / gamma) * mul - add);
+ }
+ static inline double igammareti (double x, double gamma, double start, double slope, double mul, double add)
+ {
+ return (x <= start * slope ? x / slope : exp(log((x + add) / mul) * gamma) );
+ }
+
// gamma function with adjustable parameters
diff --git a/rtengine/procevents.h b/rtengine/procevents.h
index 0f87bf1bd..ddae2f583 100644
--- a/rtengine/procevents.h
+++ b/rtengine/procevents.h
@@ -448,6 +448,8 @@ enum ProcEvent {
EvretinexColorSpace = 418, // 418 if we want a separate history entry "Retinex - Color space", 406 if we don't
EvLCDHCurve = 419,
Evretinexgamma = 420,
+ EvLgam = 421,
+ EvLslope = 422,
NUMOFEVENTS
};
}
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index b2162bed7..566bcd13a 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -142,6 +142,8 @@ void RetinexParams::setDefaults()
enabled = false;
str = 20;
scal = 3;
+ gam = 1.30;
+ slope = 3.;
neigh = 80;
gain = 50;
offs = 0;
@@ -1436,6 +1438,14 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol
keyFile.set_integer ("Retinex", "Scal", retinex.scal);
}
+ if (!pedited || pedited->retinex.gam) {
+ keyFile.set_double ("Retinex", "Gam", retinex.gam);
+ }
+
+ if (!pedited || pedited->retinex.slope) {
+ keyFile.set_double ("Retinex", "Slope", retinex.slope);
+ }
+
if (!pedited || pedited->retinex.enabled) {
keyFile.set_boolean ("Retinex", "Enabled", retinex.enabled);
}
@@ -3818,6 +3828,22 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited)
}
}
+ if (keyFile.has_key ("Retinex", "Gam")) {
+ retinex.gam = keyFile.get_double ("Retinex", "Gam");
+
+ if (pedited) {
+ pedited->retinex.gam = true;
+ }
+ }
+
+ if (keyFile.has_key ("Retinex", "Slope")) {
+ retinex.slope = keyFile.get_double ("Retinex", "Slope");
+
+ if (pedited) {
+ pedited->retinex.slope = true;
+ }
+ }
+
if (keyFile.has_key ("Retinex", "Gain")) {
retinex.gain = keyFile.get_integer ("Retinex", "Gain");
@@ -7240,6 +7266,8 @@ bool ProcParams::operator== (const ProcParams& other)
&& retinex.transmissionCurve == other.retinex.transmissionCurve
&& retinex.str == other.retinex.str
&& retinex.scal == other.retinex.scal
+ && retinex.gam == other.retinex.gam
+ && retinex.slope == other.retinex.slope
&& retinex.neigh == other.retinex.neigh
&& retinex.gain == other.retinex.gain
&& retinex.limd == other.retinex.limd
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index 9bd5ecb29..4c631b6c8 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -274,6 +274,8 @@ public:
std::vector transmissionCurve;
int str;
int scal;
+ double gam;
+ double slope;
int neigh;
int gain;
int offs;
diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc
index a9c4016c9..8897dca15 100644
--- a/rtengine/rawimagesource.cc
+++ b/rtengine/rawimagesource.cc
@@ -1813,14 +1813,36 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar
conversionBuffer[2] (W - 2 * border, H - 2 * border);
LUTf *retinexgamtab;//gamma before and after Retinex to restore tones
+ LUTf lutTonereti;
+ lutTonereti(65536);
+
if(retinexParams.gammaretinex == "low")
retinexgamtab = &(Color::gammatab_115_2);
else if(retinexParams.gammaretinex == "mid")
retinexgamtab = &(Color::gammatab_13_2);
else if(retinexParams.gammaretinex == "hig")
retinexgamtab = &(Color::gammatab_145_3);
+ else if(retinexParams.gammaretinex == "fre"){
+ double g_a0, g_a1, g_a2, g_a3, g_a4, g_a5;
+ double pwr = 1.0 / retinexParams.gam;
+ double gamm = retinexParams.gam;
+ double ts = retinexParams.slope;
+ int mode = 0, imax = 0;
+ Color::calcGamma(pwr, ts, mode, imax, g_a0, g_a1, g_a2, g_a3, g_a4, g_a5); // call to calcGamma with selected gamma and slope
+ // printf("g_a0=%f g_a1=%f g_a2=%f g_a3=%f g_a4=%f\n", g_a0,g_a1,g_a2,g_a3,g_a4);
+ for (int i = 0; i < 65536; i++) {
+ double val = (i) / 65535.;
+ double start = g_a3;
+ double add = g_a3;
+ double mul = 1. + g_a4;
+ double x;
+ x = Color::gammareti (val, gamm, start, ts, mul , add);
+ lutTonereti[i] = CLIP(x * 65535.);// CLIP avoid in some case extra values
+ }
+ retinexgamtab = &lutTonereti;
+ }
-if(retinexParams.gammaretinex != "none") {//gamma
+if(retinexParams.gammaretinex != "none" && retinexParams.str != 0) {//gamma
#ifdef _OPENMP
#pragma omp parallel for
#endif
@@ -1832,7 +1854,7 @@ if(retinexParams.gammaretinex != "none") {//gamma
B_=blue[i][j];
red[i][j] = (*retinexgamtab)[R_];
green[i][j] = (*retinexgamtab)[G_];
- blue[i][j] = (*retinexgamtab)[B_];
+ blue[i][j] = (*retinexgamtab)[B_];
}
}
}
@@ -1946,10 +1968,6 @@ if(retinexParams.gammaretinex != "none") {//gamma
G_ = green[i][j];
B_ = blue[i][j];
//rgb=>lab
- // R_ = (*retinexigamtab)[red[i][j]];
- // G_ = (*retinexigamtab)[green[i][j]];
- // B_ = (*retinexigamtab)[blue[i][j]];
-
Color::rgbxyz(R_, G_, B_, X, Y, Z, wp);
//convert Lab
Color::XYZ2Lab(X, Y, Z, L, aa, bb);
@@ -2004,6 +2022,9 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, LUTf
if (settings->verbose) {
printf ("Applying Retinex\n");
}
+ LUTf lutToneireti;
+ lutToneireti(65536);
+
LUTf *retinexigamtab;//gamma before and after Retinex to restore tones
if(deh.gammaretinex == "low")
retinexigamtab = &(Color::igammatab_115_2);
@@ -2011,7 +2032,25 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, LUTf
retinexigamtab = &(Color::igammatab_13_2);
else if(deh.gammaretinex == "hig")
retinexigamtab = &(Color::igammatab_145_3);
-
+ else if(deh.gammaretinex == "fre"){
+ double g_a0, g_a1, g_a2, g_a3, g_a4, g_a5;
+ double pwr = 1.0 / deh.gam;
+ double gamm = deh.gam;
+ double ts = deh.slope;
+ int mode = 0, imax = 0;
+ Color::calcGamma(pwr, ts, mode, imax, g_a0, g_a1, g_a2, g_a3, g_a4, g_a5); // call to calcGamma with selected gamma and slope
+ // printf("g_a0=%f g_a1=%f g_a2=%f g_a3=%f g_a4=%f\n", g_a0,g_a1,g_a2,g_a3,g_a4);
+ for (int i = 0; i < 65536; i++) {
+ double val = (i) / 65535.;
+ double x;
+ double mul = 1. + g_a4;
+ double add = g_a4;
+ double start = g_a2;
+ x = Color::igammareti (val, gamm, start, ts, mul , add);
+ lutToneireti[i] = CLIP(x * 65535.);
+ }
+ retinexigamtab = &lutToneireti;
+ }
// We need a buffer with original L data to allow correct blending
// red, green and blue still have original size of raw, but we can't use the borders
const int HNew = H - 2 * border;
@@ -2164,11 +2203,10 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, LUTf
red[i][j] = R;
green[i][j] = G;
blue[i][j] = B;
-
}
}
}
-if(deh.gammaretinex != "none"){//inverse gamma
+if(deh.gammaretinex != "none" && deh.str !=0){//inverse gamma
#ifdef _OPENMP
#pragma omp parallel for
#endif
@@ -2180,7 +2218,7 @@ if(deh.gammaretinex != "none"){//inverse gamma
B_=blue[i][j];
red[i][j] = (*retinexigamtab)[R_];
green[i][j] = (*retinexigamtab)[G_];
- blue[i][j] = (*retinexigamtab)[B_];
+ blue[i][j] = (*retinexigamtab)[B_];
}
}
}
diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc
index 1ce5a4211..4ad96ebd2 100644
--- a/rtengine/refreshmap.cc
+++ b/rtengine/refreshmap.cc
@@ -447,6 +447,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = {
ALLNORAW, // EvLlimd
DEMOSAIC, // Evretinexcolorspace
ALLNORAW, // EvLCDHCurve
- DEMOSAIC // Evretinexgamma
+ DEMOSAIC, // Evretinexgamma
+ DEMOSAIC, // EvLgam
+ DEMOSAIC // EvLslope
};
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index e3fa2de1e..dc142f6de 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -57,6 +57,8 @@ void ParamsEdited::set (bool v)
retinex.enabled = v;
retinex.str = v;
retinex.scal = v;
+ retinex.gam = v;
+ retinex.slope = v;
retinex.neigh = v;
retinex.gain = v;
retinex.offs = v;
@@ -528,6 +530,8 @@ void ParamsEdited::initFrom (const std::vector
retinex.gammaretinex = retinex.gammaretinex && p.retinex.gammaretinex == other.retinex.gammaretinex;
retinex.str = retinex.str && p.retinex.str == other.retinex.str;
retinex.scal = retinex.scal && p.retinex.scal == other.retinex.scal;
+ retinex.gam = retinex.gam && p.retinex.gam == other.retinex.gam;
+ retinex.slope = retinex.slope && p.retinex.slope == other.retinex.slope;
retinex.neigh = retinex.neigh && p.retinex.neigh == other.retinex.neigh;
retinex.gain = retinex.gain && p.retinex.gain == other.retinex.gain;
retinex.offs = retinex.offs && p.retinex.offs == other.retinex.offs;
@@ -1053,6 +1057,14 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
if (retinex.gammaretinex) {
toEdit.retinex.gammaretinex = mods.retinex.gammaretinex;
}
+
+ if (retinex.gam) {
+ toEdit.retinex.gam = mods.retinex.gam;
+ }
+
+ if (retinex.slope) {
+ toEdit.retinex.slope = mods.retinex.slope;
+ }
if (retinex.str) {
toEdit.retinex.str = dontforceSet && options.baBehav[ADDSET_DH_STR] ? toEdit.retinex.str + mods.retinex.str : mods.retinex.str;
diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h
index 850c8589d..bfe7fbe02 100644
--- a/rtgui/paramsedited.h
+++ b/rtgui/paramsedited.h
@@ -61,6 +61,8 @@ public:
bool enabled;
bool str;
bool scal;
+ bool gam;
+ bool slope;
bool neigh;
bool gain;
bool offs;
diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc
index 9c4b2e3e2..1a848a037 100644
--- a/rtgui/retinex.cc
+++ b/rtgui/retinex.cc
@@ -105,10 +105,13 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"),
gammaretinex->append_text (M("TP_RETINEX_GAMMA_LOW"));
gammaretinex->append_text (M("TP_RETINEX_GAMMA_MID"));
gammaretinex->append_text (M("TP_RETINEX_GAMMA_HIGH"));
+ gammaretinex->append_text (M("TP_RETINEX_GAMMA_FREE"));
gammaretinex->set_active(0);
gammaretinexConn = gammaretinex->signal_changed().connect ( sigc::mem_fun(*this, &Retinex::gammaretinexChanged) );
gammaretinex->set_tooltip_markup (M("TP_RETINEX_GAMMA_TOOLTIP"));
+ gam = Gtk::manage (new Adjuster (M("TP_RETINEX_GAMMA"), 1.1, 1.6, 0.01, 1.30));
+ slope = Gtk::manage (new Adjuster (M("TP_RETINEX_SLOPE"), 2., 20., 0.1, 3.));
str = Gtk::manage (new Adjuster (M("TP_RETINEX_STRENGTH"), 0, 100., 1., 20.));
neigh = Gtk::manage (new Adjuster (M("TP_RETINEX_NEIGHBOR"), 6, 100., 1., 80.));
@@ -158,6 +161,13 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"),
settingsVBox->pack_start(*gambox);
gammaretinex->show();
+
+ settingsVBox->pack_start (*gam);
+ gam->show ();
+
+ settingsVBox->pack_start (*slope);
+ slope->show ();
+
settingsVBox->pack_start (*scal);
scal->show ();
@@ -193,6 +203,18 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"),
if (scal->delay < 200) {
scal->delay = 200;
}
+
+ gam->setAdjusterListener (this);
+
+ if (gam->delay < 500) {
+ gam->delay = 500;
+ }
+
+ slope->setAdjusterListener (this);
+
+ if (slope->delay < 500) {
+ slope->delay = 500;
+ }
neigh->setAdjusterListener (this);
@@ -350,6 +372,8 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited)
if (pedited) {
scal->setEditedState (pedited->retinex.scal ? Edited : UnEdited);
neigh->setEditedState (pedited->retinex.neigh ? Edited : UnEdited);
+ gam->setEditedState (pedited->retinex.gam ? Edited : UnEdited);
+ slope->setEditedState (pedited->retinex.slope ? Edited : UnEdited);
gain->setEditedState (pedited->retinex.gain ? Edited : UnEdited);
offs->setEditedState (pedited->retinex.offs ? Edited : UnEdited);
vart->setEditedState (pedited->retinex.vart ? Edited : UnEdited);
@@ -383,6 +407,8 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited)
scal->setValue (pp->retinex.scal);
vart->setValue (pp->retinex.vart);
limd->setValue (pp->retinex.limd);
+ gam->setValue (pp->retinex.gam);
+ slope->setValue (pp->retinex.slope);
setEnabled (pp->retinex.enabled);
@@ -416,6 +442,8 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited)
gammaretinex->set_active (2);
} else if (pp->retinex.gammaretinex == "hig") {
gammaretinex->set_active (3);
+ } else if (pp->retinex.gammaretinex == "fre") {
+ gammaretinex->set_active (4);
}
retinexMethodChanged ();
@@ -445,6 +473,8 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited)
pp->retinex.str = str->getValue ();
pp->retinex.scal = (int)scal->getValue ();
+ pp->retinex.gam = gam->getValue ();
+ pp->retinex.slope = slope->getValue ();
pp->retinex.neigh = neigh->getValue ();
pp->retinex.gain = (int)gain->getValue ();
pp->retinex.offs = (int)offs->getValue ();
@@ -464,6 +494,8 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited)
//%%%%%%%%%%%%%%%%%%%%%%
pedited->retinex.str = str->getEditedState ();
pedited->retinex.scal = scal->getEditedState ();
+ pedited->retinex.gam = gam->getEditedState ();
+ pedited->retinex.slope = slope->getEditedState ();
pedited->retinex.neigh = neigh->getEditedState ();
pedited->retinex.gain = gain->getEditedState ();
pedited->retinex.offs = offs->getEditedState ();
@@ -501,6 +533,8 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited)
pp->retinex.gammaretinex = "mid";
} else if (gammaretinex->get_active_row_number() == 3) {
pp->retinex.gammaretinex = "hig";
+ } else if (gammaretinex->get_active_row_number() == 4) {
+ pp->retinex.gammaretinex = "fre";
}
}
@@ -531,7 +565,6 @@ void Retinex::ColorSpaceUpdateUI ()
void Retinex::retinexColorSpaceChanged()
{
-
ColorSpaceUpdateUI();
if (listener) {
@@ -541,6 +574,15 @@ void Retinex::retinexColorSpaceChanged()
void Retinex::gammaretinexChanged()
{
+ if (!batchMode) {
+ if(gammaretinex->get_active_row_number() == 4) {
+ gam->show();
+ slope->show();
+ } else if(gammaretinex->get_active_row_number() != 4) {
+ gam->hide();
+ slope->hide();
+ }
+ }
ColorSpaceUpdateUI();
@@ -589,6 +631,8 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi
scal->setDefault (defParams->retinex.scal);
vart->setDefault (defParams->retinex.vart);
limd->setDefault (defParams->retinex.limd);
+ gam->setDefault (defParams->retinex.gam);
+ slope->setDefault (defParams->retinex.slope);
if (pedited) {
neigh->setDefaultEditedState (pedited->retinex.neigh ? Edited : UnEdited);
@@ -598,6 +642,8 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi
scal->setDefaultEditedState (pedited->retinex.scal ? Edited : UnEdited);
vart->setDefaultEditedState (pedited->retinex.vart ? Edited : UnEdited);
limd->setDefaultEditedState (pedited->retinex.limd ? Edited : UnEdited);
+ gam->setDefaultEditedState (pedited->retinex.gam ? Edited : UnEdited);
+ slope->setDefaultEditedState (pedited->retinex.slope ? Edited : UnEdited);
} else {
neigh->setDefaultEditedState (Irrelevant);
@@ -607,6 +653,8 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi
limd->setDefaultEditedState (Irrelevant);
str->setDefaultEditedState (Irrelevant);
scal->setDefaultEditedState (Irrelevant);
+ gam->setDefaultEditedState (Irrelevant);
+ slope->setDefaultEditedState (Irrelevant);
}
}
@@ -644,6 +692,10 @@ void Retinex::adjusterChanged (Adjuster* a, double newval)
listener->panelChanged (EvLvart, vart->getTextValue());
} else if (a == limd) {
listener->panelChanged (EvLlimd, limd->getTextValue());
+ } else if (a == gam) {
+ listener->panelChanged (EvLgam, gam->getTextValue());
+ } else if (a == slope) {
+ listener->panelChanged (EvLslope, slope->getTextValue());
}
}
@@ -696,6 +748,8 @@ void Retinex::trimValues (rtengine::procparams::ProcParams* pp)
offs->trimValue(pp->retinex.offs);
vart->trimValue(pp->retinex.vart);
limd->trimValue(pp->retinex.limd);
+ gam->trimValue(pp->retinex.gam);
+ slope->trimValue(pp->retinex.slope);
}
void Retinex::updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve,/* LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histLRETI)
@@ -713,6 +767,8 @@ void Retinex::setBatchMode (bool batchMode)
offs->showEditedCB ();
str->showEditedCB ();
scal->showEditedCB ();
+ gam->showEditedCB ();
+ slope->showEditedCB ();
vart->showEditedCB ();
limd->showEditedCB ();
curveEditorGD->setBatchMode (batchMode);
diff --git a/rtgui/retinex.h b/rtgui/retinex.h
index 4b01865db..a563fa271 100644
--- a/rtgui/retinex.h
+++ b/rtgui/retinex.h
@@ -28,6 +28,8 @@ protected:
Adjuster* offs;
Adjuster* vart;
Adjuster* limd;
+ Adjuster* gam;
+ Adjuster* slope;
MyExpander* expsettings;
Gtk::Label* labmdh;