diff --git a/rtdata/languages/default b/rtdata/languages/default index eb220fe35..63947dfed 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1560,6 +1560,12 @@ 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_GAMMA_NONE;None +TP_RETINEX_GAMMA_LOW;Low +TP_RETINEX_GAMMA_MID;Middle +TP_RETINEX_GAMMA_HIGH;High +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 TP_RETINEX_HSLSPACE_LOG;HSL-Logarithmic diff --git a/rtengine/color.cc b/rtengine/color.cc index ed6e9cae6..b403ee7dc 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -50,6 +50,11 @@ LUTf Color::gammatab_26_11; LUTf Color::igammatab_24_17; LUTf Color::gammatab_24_17a; LUTf Color::gammatab_13_2; +LUTf Color::igammatab_13_2; +LUTf Color::gammatab_115_2; +LUTf Color::igammatab_115_2; +LUTf Color::gammatab_145_3; +LUTf Color::igammatab_145_3; // Wikipedia sRGB: Unlike most other RGB color spaces, the sRGB gamma cannot be expressed as a single numerical value. // The overall gamma is approximately 2.2, consisting of a linear (gamma 1.0) section near black, and a non-linear section elsewhere involving a 2.4 exponent @@ -162,6 +167,11 @@ void Color::init () igammatab_24_17(65536, 0); gammatab_24_17a(65536, LUT_CLIP_ABOVE | LUT_CLIP_BELOW); gammatab_13_2(65536, 0); + igammatab_13_2(65536, 0); + gammatab_115_2(65536, 0); + igammatab_115_2(65536, 0); + gammatab_145_3(65536, 0); + igammatab_145_3(65536, 0); for (int i = 0; i < 65536; i++) { gammatab_srgb[i] = (65535.0 * gamma2 (i / 65535.0)); @@ -199,7 +209,27 @@ void Color::init () for (int i = 0; i < 65536; i++) { gammatab_13_2[i] = (65535.0 * gamma13_2 (i / 65535.0)); } + + for (int i = 0; i < 65536; i++) { + igammatab_13_2[i] = (65535.0 * igamma13_2 (i / 65535.0)); + } + for (int i = 0; i < 65536; i++) { + gammatab_115_2[i] = (65535.0 * gamma115_2 (i / 65535.0)); + } + + for (int i = 0; i < 65536; i++) { + igammatab_115_2[i] = (65535.0 * igamma115_2 (i / 65535.0)); + } + + for (int i = 0; i < 65536; i++) { + gammatab_145_3[i] = (65535.0 * gamma145_3 (i / 65535.0)); + } + + for (int i = 0; i < 65536; i++) { + igammatab_145_3[i] = (65535.0 * igamma145_3 (i / 65535.0)); + } + for (int i = 0; i < 65536; i++) { gammatab_26_11[i] = (65535.0 * gamma26_11 (i / 65535.0)); } diff --git a/rtengine/color.h b/rtengine/color.h index 70dbcddf5..53d5a8b19 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -142,6 +142,11 @@ public: static LUTf igammatab_24_17; static LUTf gammatab_24_17a; static LUTf gammatab_13_2; + static LUTf igammatab_13_2; + static LUTf gammatab_115_2; + static LUTf igammatab_115_2; + static LUTf gammatab_145_3; + static LUTf igammatab_145_3; // look-up tables for the simple exponential gamma static LUTf gammatab; @@ -951,7 +956,32 @@ public: { return x <= 0.016613 ? x * 2.0 : 1.009968 * exp(log(x) / 1.3) - 0.016613; } + + static inline double igamma13_2 (double x) + { + return x <= 0.033226 ? x / 2.0 : exp(log((x + 0.009968) / 1.009968) * 1.3); + } + static inline double gamma115_2 (double x) + { + return x <= 0.001692 ? x * 2.0 : 1.000508 * exp(log(x) / 1.15) - 0.001692; + } + + static inline double igamma115_2 (double x) + { + return x <= 0.003384 ? x / 2.0 : exp(log((x + 0.000508) / 1.000508) * 1.15); + } + + static inline double gamma145_3 (double x) + { + return x <= 0.009115 ? x * 3.0 : 1.012305 * exp(log(x) / 1.45) - 0.009115; + } + + static inline double igamma145_3 (double x) + { + return x <= 0.027345 ? x / 3.0 : exp(log((x + 0.012305) / 1.012305) * 1.45); + } + // gamma function with adjustable parameters //same as above with values calculate with Calcgamma above diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 1a6216750..79e072d77 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -446,6 +446,7 @@ enum ProcEvent { EvLlimd = 417, EvretinexColorSpace = 418, //change to 418 if we want a separate history entry "Retinex - Color space" EvLCDHCurve = 419, + Evretinexgamma = 420, NUMOFEVENTS }; } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 1655c5eb5..ed0bf85c8 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -190,6 +190,7 @@ void RetinexParams::setDefaults() getDefaultCDHCurve(cdHcurve); retinexMethod = "high"; retinexcolorspace = "Lab"; + gammaretinex = "none"; medianmap = true; } @@ -1510,6 +1511,10 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_string ("Retinex", "Retinexcolorspace", retinex.retinexcolorspace); } + if (!pedited || pedited->retinex.gammaretinex) { + keyFile.set_string ("Retinex", "Gammaretinex", retinex.gammaretinex); + } + if (!pedited || pedited->retinex.cdcurve) { Glib::ArrayHandle cdcurve = retinex.cdcurve; keyFile.set_double_list("Retinex", "CDCurve", cdcurve); @@ -3810,6 +3815,14 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Retinex", "Gammaretinex")) { + retinex.gammaretinex = keyFile.get_string ("Retinex", "Gammaretinex"); + + if (pedited) { + pedited->retinex.gammaretinex = true; + } + } + if (keyFile.has_key ("Retinex", "Enabled")) { retinex.enabled = keyFile.get_boolean ("Retinex", "Enabled"); @@ -7270,6 +7283,7 @@ bool ProcParams::operator== (const ProcParams& other) && retinex.offs == other.retinex.offs && retinex.retinexMethod == other.retinex.retinexMethod && retinex.retinexcolorspace == other.retinex.retinexcolorspace + && retinex.gammaretinex == other.retinex.gammaretinex && retinex.vart == other.retinex.vart && retinex.medianmap == other.retinex.medianmap && retinex.enabled == other.retinex.enabled diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 91dfbf7bc..f1d70d503 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -279,6 +279,7 @@ public: int offs; Glib::ustring retinexMethod; Glib::ustring retinexcolorspace; + Glib::ustring gammaretinex; int vart; int limd; bool medianmap; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 52345b807..a9c4016c9 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1811,6 +1811,31 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar conversionBuffer[0] (W - 2 * border, H - 2 * border); conversionBuffer[1] (W - 2 * border, H - 2 * border); conversionBuffer[2] (W - 2 * border, H - 2 * border); + + LUTf *retinexgamtab;//gamma before and after Retinex to restore tones + 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); + +if(retinexParams.gammaretinex != "none") {//gamma +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = border; i < H - border; i++ ) { + for (int j = border; j < W - border; j++ ) { + float R_,G_,B_; + R_=red[i][j]; + G_=green[i][j]; + B_=blue[i][j]; + red[i][j] = (*retinexgamtab)[R_]; + green[i][j] = (*retinexgamtab)[G_]; + blue[i][j] = (*retinexgamtab)[B_]; + } + } +} if(useHsl) { #ifdef _OPENMP @@ -1916,8 +1941,16 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar for (int j = border; j < W - border; j++) { float X, Y, Z, L, aa, bb; int pos; + float R_,G_,B_; + R_ = red[i][j]; + G_ = green[i][j]; + B_ = blue[i][j]; //rgb=>lab - Color::rgbxyz(red[i][j], green[i][j], blue[i][j], X, Y, Z, wp); + // 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); conversionBuffer[0][i - border][j - border] = aa; @@ -1944,6 +1977,9 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } } + + + } void RawImageSource::retinexPrepareCurves(RetinexParams retinexParams, LUTf &cdcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) @@ -1968,6 +2004,13 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, LUTf if (settings->verbose) { printf ("Applying Retinex\n"); } + LUTf *retinexigamtab;//gamma before and after Retinex to restore tones + if(deh.gammaretinex == "low") + retinexigamtab = &(Color::igammatab_115_2); + else if(deh.gammaretinex == "mid") + retinexigamtab = &(Color::igammatab_13_2); + else if(deh.gammaretinex == "hig") + retinexigamtab = &(Color::igammatab_145_3); // 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 @@ -2104,9 +2147,11 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, LUTf vfloat R, G, B; Color::Lab2XYZ(LVFU(LBuffer[i - border][j - border]), LVFU(conversionBuffer[0][i - border][j - border]), LVFU(conversionBuffer[1][i - border][j - border]), x_, y_, z_) ; Color::xyz2rgb(x_, y_, z_, R, G, B, wipv); + _mm_storeu_ps(&red[i][j], R); _mm_storeu_ps(&green[i][j], G); - _mm_storeu_ps(&blue[i][j], B); + _mm_storeu_ps(&blue[i][j], B); + } #endif @@ -2119,8 +2164,25 @@ 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 +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = border; i < H - border; i++ ) { + for (int j = border; j < W - border; j++ ) { + float R_,G_,B_; + R_=red[i][j]; + G_=green[i][j]; + B_=blue[i][j]; + red[i][j] = (*retinexigamtab)[R_]; + green[i][j] = (*retinexigamtab)[G_]; + blue[i][j] = (*retinexigamtab)[B_]; + } + } } t5.set(); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 9acea5dd6..71ff47c6d 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -442,6 +442,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { ALLNORAW, // EvRetinexmedianmap ALLNORAW, // EvLlimd DEMOSAIC, // Evretinexcolorspace + DEMOSAIC, // EvRetinexgamma ALLNORAW // EvLCDHCurve diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 77f2d50f8..e3fa2de1e 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -53,6 +53,7 @@ void ParamsEdited::set (bool v) retinex.cdHcurve = v; retinex.retinexMethod = v; retinex.retinexcolorspace = v; + retinex.gammaretinex = v; retinex.enabled = v; retinex.str = v; retinex.scal = v; @@ -524,6 +525,7 @@ void ParamsEdited::initFrom (const std::vector retinex.transmissionCurve = retinex.transmissionCurve && p.retinex.transmissionCurve == other.retinex.transmissionCurve; retinex.retinexMethod = retinex.retinexMethod && p.retinex.retinexMethod == other.retinex.retinexMethod; retinex.retinexcolorspace = retinex.retinexcolorspace && p.retinex.retinexcolorspace == other.retinex.retinexcolorspace; + 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.neigh = retinex.neigh && p.retinex.neigh == other.retinex.neigh; @@ -1048,6 +1050,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.retinex.retinexcolorspace = mods.retinex.retinexcolorspace; } + if (retinex.gammaretinex) { + toEdit.retinex.gammaretinex = mods.retinex.gammaretinex; + } + 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 7600b3bb1..850c8589d 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -66,6 +66,7 @@ public: bool offs; bool retinexMethod; bool retinexcolorspace; + bool gammaretinex; bool vart; bool limd; bool method; diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index b1c290e14..a6a435356 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -46,7 +46,7 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), retinexcolorspace->append_text (M("TP_RETINEX_HSLSPACE_LIN")); retinexcolorspace->set_active(0); retinexColorSpaceConn = retinexcolorspace->signal_changed().connect ( sigc::mem_fun(*this, &Retinex::retinexColorSpaceChanged) ); - + dhbox->pack_start(*retinexMethod); dhbox->pack_start(*retinexcolorspace); @@ -96,6 +96,18 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), transmissionCurveEditorG->curveListComplete(); + gambox = Gtk::manage (new Gtk::HBox ()); + labgam = Gtk::manage (new Gtk::Label (M("TP_RETINEX_GAM") + ":")); + gambox->pack_start (*labgam, Gtk::PACK_SHRINK, 1); + + gammaretinex = Gtk::manage (new MyComboBoxText ()); + gammaretinex->append_text (M("TP_RETINEX_GAMMA_NONE")); + 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->set_active(0); + gammaretinexConn = gammaretinex->signal_changed().connect ( sigc::mem_fun(*this, &Retinex::gammaretinexChanged) ); + gammaretinex->set_tooltip_markup (M("TP_RETINEX_GAMMA_TOOLTIP")); str = Gtk::manage (new Adjuster (M("TP_RETINEX_STRENGTH"), 0, 100., 1., 20.)); @@ -103,7 +115,7 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), expsettings = new MyExpander (false, M("TP_RETINEX_SETTINGS")); expsettings->signal_button_release_event().connect_notify( sigc::bind( sigc::mem_fun(this, &Retinex::foldAllButMe), expsettings) ); - + retinexVBox->pack_start (*str); str->show (); @@ -142,6 +154,11 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), settingsVBox->pack_start (*curveEditorGDH, Gtk::PACK_SHRINK, 4); curveEditorGDH->show(); + gambox->pack_start(*gammaretinex); + + settingsVBox->pack_start(*gambox); + gammaretinex->show(); + settingsVBox->pack_start (*scal); scal->show (); @@ -212,6 +229,7 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), disableListener(); retinexColorSpaceChanged(); + gammaretinexChanged(); medianmapChanged(); enableListener(); @@ -326,6 +344,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) disableListener (); retinexMethodConn.block(true); retinexColorSpaceConn.block(true); + gammaretinexConn.block(true); if (pedited) { @@ -347,6 +366,10 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) retinexcolorspace->set_active_text(M("GENERAL_UNCHANGED")); } + if (!pedited->retinex.gammaretinex) { + gammaretinex->set_active_text(M("GENERAL_UNCHANGED")); + } + cdshape->setUnChanged (!pedited->retinex.cdcurve); cdshapeH->setUnChanged (!pedited->retinex.cdHcurve); transmissionShape->setUnChanged (!pedited->retinex.transmissionCurve); @@ -385,8 +408,19 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) retinexcolorspace->set_active (2); } + if (pp->retinex.gammaretinex == "none") { + gammaretinex->set_active (0); + } else if (pp->retinex.gammaretinex == "low") { + gammaretinex->set_active (1); + } else if (pp->retinex.gammaretinex == "mid") { + gammaretinex->set_active (2); + } else if (pp->retinex.gammaretinex == "hig") { + gammaretinex->set_active (3); + } + retinexMethodChanged (); retinexColorSpaceChanged(); + gammaretinexChanged(); medianmapConn.block(true); medianmapChanged (); @@ -397,6 +431,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) retinexMethodConn.block(false); retinexColorSpaceConn.block(false); + gammaretinexConn.block(false); transmissionShape->setCurve (pp->retinex.transmissionCurve); @@ -424,6 +459,7 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) if (pedited) { pedited->retinex.retinexMethod = retinexMethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->retinex.retinexcolorspace = retinexcolorspace->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->retinex.gammaretinex = gammaretinex->get_active_text() != M("GENERAL_UNCHANGED"); //%%%%%%%%%%%%%%%%%%%%%% pedited->retinex.str = str->getEditedState (); @@ -456,6 +492,17 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) } else if (retinexcolorspace->get_active_row_number() == 2) { pp->retinex.retinexcolorspace = "HSLLIN"; } + + if (gammaretinex->get_active_row_number() == 0) { + pp->retinex.gammaretinex = "none"; + } else if (gammaretinex->get_active_row_number() == 1) { + pp->retinex.gammaretinex = "low"; + } else if (gammaretinex->get_active_row_number() == 2) { + pp->retinex.gammaretinex = "mid"; + } else if (gammaretinex->get_active_row_number() == 3) { + pp->retinex.gammaretinex = "hig"; + } + } void Retinex::retinexMethodChanged() @@ -492,6 +539,16 @@ void Retinex::retinexColorSpaceChanged() } } +void Retinex::gammaretinexChanged() +{ + + ColorSpaceUpdateUI(); + + if (listener) { + listener->panelChanged (Evretinexgamma, gammaretinex->get_active_text ()); + } +} + void Retinex::medianmapChanged () { if (batchMode) { diff --git a/rtgui/retinex.h b/rtgui/retinex.h index 305682660..4b01865db 100644 --- a/rtgui/retinex.h +++ b/rtgui/retinex.h @@ -32,8 +32,12 @@ protected: Gtk::Label* labmdh; Gtk::HBox* dhbox; + Gtk::Label* labgam; + Gtk::HBox* gambox; + MyComboBoxText* retinexMethod; MyComboBoxText* retinexcolorspace; + MyComboBoxText* gammaretinex; Gtk::CheckButton* medianmap; double nextmin; double nextmax; @@ -52,6 +56,7 @@ protected: CurveEditorGroup* transmissionCurveEditorG; sigc::connection retinexMethodConn; sigc::connection retinexColorSpaceConn; + sigc::connection gammaretinexConn; FlatCurveEditor* transmissionShape; bool lastmedianmap; sigc::connection medianmapConn; @@ -77,6 +82,7 @@ public: void curveChanged (CurveEditor* ce); void retinexMethodChanged(); void retinexColorSpaceChanged(); + void gammaretinexChanged(); void ColorSpaceUpdateUI(); void writeOptions (std::vector &tpOpen); void updateToolState (std::vector &tpOpen);