diff --git a/rtdata/languages/default b/rtdata/languages/default index 3ec76b494..3064c13e3 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1475,6 +1475,7 @@ HISTORY_MSG_LOCALCONTRAST_DARKNESS;Local Contrast - Darkness HISTORY_MSG_LOCALCONTRAST_ENABLED;Local Contrast HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;Local Contrast - Lightness HISTORY_MSG_LOCALCONTRAST_RADIUS;Local Contrast - Radius +HISTORY_MSG_LOCALLAB_TE_PIVOT;Local - Equalizer pivot HISTORY_MSG_METADATA_MODE;Metadata copy mode HISTORY_MSG_MICROCONTRAST_CONTRAST;Microcontrast - Contrast threshold HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;CS - Auto threshold @@ -3433,6 +3434,7 @@ TP_LOCALLAB_STYPE_TOOLTIP;You can choose between:\nSymmetrical - left handle lin TP_LOCALLAB_SYM;Symmetrical (mouse) TP_LOCALLAB_SYMSL;Symmetrical (mouse + sliders) TP_LOCALLAB_TARGET_GRAY;Mean luminance (Yb%) +TP_LOCALLAB_TE_PIVOT;Pivot (Ev) TP_LOCALLAB_THRES;Threshold structure TP_LOCALLAB_THRESDELTAE;ΔE scope threshold TP_LOCALLAB_THRESRETI;Threshold diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 70aed428c..12487cdbd 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -492,8 +492,8 @@ enum class BlurType { void colorToningLabGrid(LabImage *lab, int xstart, int xend, int ystart, int yend, bool MultiThread); //void shadowsHighlights(LabImage *lab); void shadowsHighlights(LabImage *lab, bool ena, int labmode, int hightli, int shado, int rad, int scal, int hltonal, int shtonal); - bool toneEqualizer(Imagefloat *rgb); - static void toneEqualizer(array2D &R, array2D &G, array2D &B, const procparams::ToneEqualizerParams & params, const Glib::ustring &workingProfile, double scale, bool multithread, bool show_color_map); + void toneEqualizer(Imagefloat *rgb); + void toneEqualizer(Imagefloat *rgb, const procparams::ToneEqualizerParams ¶ms, const Glib::ustring &workingProfile, double scale, bool multiThread); void softLight(LabImage *lab, const procparams::SoftLightParams &softLightParams); void labColorCorrectionRegions(LabImage *lab); diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 7a427b0eb..005b960a5 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -702,6 +702,7 @@ struct local_params { float mulloc[6]; int mullocsh[5]; int detailsh; + double tePivot; float threshol; float chromacb; float strengt; @@ -1691,6 +1692,7 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall lp.detailsh = locallab.spots.at(sp).detailSH; + lp.tePivot = locallab.spots.at(sp).tePivot; lp.threshol = thresho; lp.chromacb = chromcbdl; lp.expvib = locallab.spots.at(sp).expvibrance && lp.activspot ; @@ -2257,12 +2259,14 @@ void ImProcFunctions::getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg, } } -void tone_eq(array2D &R, array2D &G, array2D &B, const struct local_params & lp, const Glib::ustring &workingProfile, double scale, bool multithread) +void tone_eq(ImProcFunctions *ipf, Imagefloat *rgb, const struct local_params &lp, const Glib::ustring &workingProfile, double scale, bool multithread) { ToneEqualizerParams params; + params.enabled = true; params.regularization = lp.detailsh; + params.pivot = lp.tePivot; std::copy(lp.mullocsh, lp.mullocsh + params.bands.size(), params.bands.begin()); - ImProcFunctions::toneEqualizer(R, G, B, params, workingProfile, scale, multithread, false); + ipf->toneEqualizer(rgb, params, workingProfile, scale, multithread); } void ImProcFunctions::loccont(int bfw, int bfh, LabImage* tmp1, float rad, float stren, int sk) { @@ -7586,12 +7590,7 @@ void ImProcFunctions::InverseColorLight_Local(bool tonequ, bool tonecurv, int sp } if (tonequ) { - tmpImage->normalizeFloatTo1(); - array2D Rtemp(GW, GH, tmpImage->r.ptrs, ARRAY2D_BYREFERENCE); - array2D Gtemp(GW, GH, tmpImage->g.ptrs, ARRAY2D_BYREFERENCE); - array2D Btemp(GW, GH, tmpImage->b.ptrs, ARRAY2D_BYREFERENCE); - tone_eq(Rtemp, Gtemp, Btemp, lp, params->icm.workingProfile, sk, multiThread); - tmpImage->normalizeFloatTo65535(); + tone_eq(this, tmpImage.get(), lp, params->icm.workingProfile, sk, multiThread); } rgb2lab(*tmpImage, *temp, params->icm.workingProfile); @@ -15766,12 +15765,7 @@ void ImProcFunctions::Lab_Local( } if (tonequ) { - tmpImage->normalizeFloatTo1(); - array2D Rtemp(bfw, bfh, tmpImage->r.ptrs, ARRAY2D_BYREFERENCE); - array2D Gtemp(bfw, bfh, tmpImage->g.ptrs, ARRAY2D_BYREFERENCE); - array2D Btemp(bfw, bfh, tmpImage->b.ptrs, ARRAY2D_BYREFERENCE); - tone_eq(Rtemp, Gtemp, Btemp, lp, params->icm.workingProfile, scal, multiThread); - tmpImage->normalizeFloatTo65535(); + tone_eq(this, tmpImage, lp, params->icm.workingProfile, scal, multiThread); } rgb2lab(*tmpImage, *bufexpfin, params->icm.workingProfile); diff --git a/rtengine/iptoneequalizer.cc b/rtengine/iptoneequalizer.cc index c177b8f98..a661d6b41 100644 --- a/rtengine/iptoneequalizer.cc +++ b/rtengine/iptoneequalizer.cc @@ -25,19 +25,13 @@ const std::vector> colormap = { {1.f, 0.f, 0.f} }; -} - -namespace rtengine -{ - -void ImProcFunctions::toneEqualizer( +void toneEqualizer( array2D &R, array2D &G, array2D &B, - const struct ToneEqualizerParams ¶ms, + const rtengine::ToneEqualizerParams ¶ms, const Glib::ustring &workingProfile, double scale, - bool multithread, - bool show_color_map) + bool multithread) // adapted from the tone equalizer of darktable /* Copyright 2019 Alberto Griggio @@ -102,18 +96,18 @@ void ImProcFunctions::toneEqualizer( conv(params.bands[4], 3.f, 2.f) // 4 EV }; - TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(workingProfile); + rtengine::TMatrix ws = rtengine::ICCStore::getInstance()->workingSpaceMatrix(workingProfile); #ifdef _OPENMP #pragma omp parallel for if (multithread) #endif for (int y = 0; y < H; ++y) { for (int x = 0; x < W; ++x) { - Y[y][x] = Color::rgbLuminance(R[y][x], G[y][x], B[y][x], ws); + Y[y][x] = rtengine::Color::rgbLuminance(R[y][x], G[y][x], B[y][x], ws); } } - int detail = LIM(params.regularization + 5, 0, 5); + int detail = rtengine::LIM(params.regularization + 5, 0, 5); int radius = detail / scale + 0.5; float epsilon2 = 0.01f + 0.002f * rtengine::max(detail - 3, 0); @@ -131,7 +125,7 @@ void ImProcFunctions::toneEqualizer( #endif for (int y = 0; y < H; ++y) { for (int x = 0; x < W; ++x) { - float l = LIM(log2(rtengine::max(Y[y][x], 1e-9f)), centers[0], centers[11]); + float l = rtengine::LIM(log2(rtengine::max(Y[y][x], 1e-9f)), centers[0], centers[11]); float ll = round(l * base_posterization) / base_posterization; Y2[y][x] = Y[y][x]; Y[y][x] = exp2(ll); @@ -145,7 +139,7 @@ void ImProcFunctions::toneEqualizer( const auto gauss = [](float b, float x) -> float { - return xexpf((-SQR(x - b) / 4.0f)); + return xexpf((-rtengine::SQR(x - b) / 4.0f)); }; // For every pixel luminance, the sum of the gaussian masks @@ -175,12 +169,12 @@ void ImProcFunctions::toneEqualizer( }; std::vector> cur_colormap; - if (show_color_map) { - lcmsMutex->lock(); - cmsHPROFILE in = ICCStore::getInstance()->getsRGBProfile(); - cmsHPROFILE out = ICCStore::getInstance()->workingSpace(workingProfile); + if (params.show_colormap) { + rtengine::lcmsMutex->lock(); + cmsHPROFILE in = rtengine::ICCStore::getInstance()->getsRGBProfile(); + cmsHPROFILE out = rtengine::ICCStore::getInstance()->workingSpace(workingProfile); cmsHTRANSFORM xform = cmsCreateTransform(in, TYPE_RGB_FLT, out, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); - lcmsMutex->unlock(); + rtengine::lcmsMutex->unlock(); for (auto &c : colormap) { cur_colormap.push_back(c); @@ -197,7 +191,7 @@ void ImProcFunctions::toneEqualizer( std::array ret = { 0.f, 0.f, 0.f }; // convert to log space - const float luma = max(log2(max(y, 0.f)), -18.0f); + const float luma = rtengine::max(log2(rtengine::max(y, 0.f)), -18.0f); // build the correction as the sum of the contribution of each // luminance channel to current pixel @@ -208,7 +202,7 @@ void ImProcFunctions::toneEqualizer( } } for (int i = 0; i < 3; ++i) { - ret[i] = LIM01(ret[i] / w_sum); + ret[i] = rtengine::LIM01(ret[i] / w_sum); } return ret; @@ -227,7 +221,7 @@ void ImProcFunctions::toneEqualizer( const auto vgauss = [](vfloat b, vfloat x) -> vfloat { static const vfloat fourv = F2V(4.f); - return xexpf((-SQR(x - b) / fourv)); + return xexpf((-rtengine::SQR(x - b) / fourv)); }; vfloat zerov = F2V(0.f); @@ -258,7 +252,7 @@ void ImProcFunctions::toneEqualizer( #endif // __SSE2__ - if (show_color_map) { + if (params.show_colormap) { LUTf lut_r(65537), lut_g(65537), lut_b(65537); for (int i = 0; i < 65536; ++i) { float y = float(i)/65535.f; @@ -332,15 +326,26 @@ void ImProcFunctions::toneEqualizer( } -bool ImProcFunctions::toneEqualizer(Imagefloat *rgb) +} + + +namespace rtengine { - if (!params->toneEqualizer.enabled) { - return false; + +void ImProcFunctions::toneEqualizer( + Imagefloat *rgb, + const ToneEqualizerParams ¶ms, + const Glib::ustring &workingProfile, + double scale, + bool multiThread) +{ + if (!params.enabled) { + return; } BENCHFUN - const float gain = 1.f / 65535.f * std::pow(2.f, -params->toneEqualizer.pivot); + const float gain = 1.f / 65535.f * std::pow(2.f, -params.pivot); rgb->multiply(gain, multiThread); @@ -351,12 +356,14 @@ bool ImProcFunctions::toneEqualizer(Imagefloat *rgb) array2D G(W, H, rgb->g.ptrs, ARRAY2D_BYREFERENCE); array2D B(W, H, rgb->b.ptrs, ARRAY2D_BYREFERENCE); - bool show_color_map = params->toneEqualizer.show_colormap; - toneEqualizer(R, G, B, params->toneEqualizer, params->icm.workingProfile, scale, multiThread, show_color_map); + ::toneEqualizer(R, G, B, params, workingProfile, scale, multiThread); rgb->multiply(1.f/gain, multiThread); +} - return show_color_map; +void ImProcFunctions::toneEqualizer(Imagefloat *rgb) +{ + toneEqualizer(rgb, params->toneEqualizer, params->icm.workingProfile, scale, multiThread); } } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index edc7d7980..52d6be8dd 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -3324,6 +3324,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : slomaskSH(0.0), lapmaskSH(0.0), detailSH(0), + tePivot(0.), reparsh(100.), LmaskSHcurve{ static_cast(DCT_NURBS), @@ -4769,6 +4770,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && slomaskSH == other.slomaskSH && lapmaskSH == other.lapmaskSH && detailSH == other.detailSH + && tePivot == other.tePivot && reparsh == other.reparsh && LmaskSHcurve == other.LmaskSHcurve && fatamountSH == other.fatamountSH @@ -6562,6 +6564,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->gammaskSH, "Locallab", "GammaskSH_" + index_str, spot.gammaskSH, keyFile); saveToKeyfile(!pedited || spot_edited->slomaskSH, "Locallab", "SlomaskSH_" + index_str, spot.slomaskSH, keyFile); saveToKeyfile(!pedited || spot_edited->detailSH, "Locallab", "DetailSH_" + index_str, spot.detailSH, keyFile); + saveToKeyfile(!pedited || spot_edited->tePivot, "Locallab", "TePivot_" + index_str, spot.tePivot, keyFile); saveToKeyfile(!pedited || spot_edited->reparsh, "Locallab", "Reparsh_" + index_str, spot.reparsh, keyFile); saveToKeyfile(!pedited || spot_edited->LmaskSHcurve, "Locallab", "LmaskSHCurve_" + index_str, spot.LmaskSHcurve, keyFile); saveToKeyfile(!pedited || spot_edited->fatamountSH, "Locallab", "FatamountSH_" + index_str, spot.fatamountSH, keyFile); @@ -8668,6 +8671,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "SlomaskSH_" + index_str, pedited, spot.slomaskSH, spotEdited.slomaskSH); assignFromKeyfile(keyFile, "Locallab", "LapmaskSH_" + index_str, pedited, spot.lapmaskSH, spotEdited.lapmaskSH); assignFromKeyfile(keyFile, "Locallab", "DetailSH_" + index_str, pedited, spot.detailSH, spotEdited.detailSH); + assignFromKeyfile(keyFile, "Locallab", "TePivot_" + index_str, pedited, spot.tePivot, spotEdited.tePivot); assignFromKeyfile(keyFile, "Locallab", "Reparsh_" + index_str, pedited, spot.reparsh, spotEdited.reparsh); assignFromKeyfile(keyFile, "Locallab", "LmaskSHCurve_" + index_str, pedited, spot.LmaskSHcurve, spotEdited.LmaskSHcurve); assignFromKeyfile(keyFile, "Locallab", "FatamountSH_" + index_str, pedited, spot.fatamountSH, spotEdited.fatamountSH); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index ddee7cbf3..ba58cd32c 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1214,6 +1214,7 @@ struct LocallabParams { double slomaskSH; double lapmaskSH; int detailSH; + double tePivot; double reparsh; std::vector LmaskSHcurve; double fatamountSH; diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index 51da93ab3..250bd958f 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -3971,6 +3971,7 @@ LocallabShadow::LocallabShadow(): } ()), detailSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DETAILSH"), -5, 5, 1, 0))), + tePivot(Gtk::manage(new Adjuster(M("TP_LOCALLAB_TE_PIVOT"), -12, 12, 0.05, 0))), highlights(Gtk::manage(new Adjuster(M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), 0, 100, 1, 0))), h_tonalwidth(Gtk::manage(new Adjuster(M("TP_SHADOWSHLIGHTS_HLTONALW"), 10, 100, 1, 70))), shadows(Gtk::manage(new Adjuster(M("TP_SHADOWSHLIGHTS_SHADOWS"), 0, 100, 1, 0))), @@ -4011,7 +4012,8 @@ LocallabShadow::LocallabShadow(): LmaskSHshape(static_cast(mask2SHCurveEditorG->addCurve(CT_Diagonal, "L(L)"))), fatSHFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_FATSHFRA")))), fatamountSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATAMOUNT"), 1., 100., 1., 1.))), - fatanchorSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATANCHOR"), 1., 100., 1., 50., Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))) + fatanchorSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATANCHOR"), 1., 100., 1., 50., Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))), + EvlocallabTePivot(ProcEventMapper::getInstance()->newEvent(AUTOEXP, "HISTORY_MSG_LOCALLAB_TE_PIVOT")) { set_orientation(Gtk::ORIENTATION_VERTICAL); @@ -4028,6 +4030,7 @@ LocallabShadow::LocallabShadow(): } detailSH->setAdjusterListener(this); + tePivot->setAdjusterListener(this); reparsh->setAdjusterListener(this); highlights->setAdjusterListener(this); @@ -4138,6 +4141,7 @@ LocallabShadow::LocallabShadow(): } pack_start(*detailSH); + pack_start(*tePivot); pack_start(*highlights); pack_start(*h_tonalwidth); pack_start(*shadows); @@ -4358,6 +4362,7 @@ void LocallabShadow::read(const rtengine::procparams::ProcParams* pp, const Para decays->setValue((double)spot.decays); detailSH->setValue((double)spot.detailSH); + tePivot->setValue(spot.tePivot); reparsh->setValue(spot.reparsh); highlights->setValue((double)spot.highlights); h_tonalwidth->setValue((double)spot.h_tonalwidth); @@ -4423,6 +4428,7 @@ void LocallabShadow::write(rtengine::procparams::ProcParams* pp, ParamsEdited* p } spot.detailSH = detailSH->getIntValue(); + spot.tePivot = tePivot->getValue(); spot.reparsh = reparsh->getValue(); spot.highlights = highlights->getIntValue(); spot.h_tonalwidth = h_tonalwidth->getIntValue(); @@ -4471,6 +4477,7 @@ void LocallabShadow::setDefaults(const rtengine::procparams::ProcParams* defPara } detailSH->setDefault((double)defSpot.detailSH); + tePivot->setDefault(defSpot.tePivot); reparsh->setDefault(defSpot.reparsh); highlights->setDefault((double)defSpot.highlights); h_tonalwidth->setDefault((double)defSpot.h_tonalwidth); @@ -4522,6 +4529,13 @@ void LocallabShadow::adjusterChanged(Adjuster* a, double newval) } } + if (a == tePivot) { + if (listener) { + listener->panelChanged(EvlocallabTePivot, + tePivot->getTextValue() + " (" + escapeHtmlChars(getSpotName()) + ")"); + } + } + if (a == reparsh) { if (listener) { listener->panelChanged(Evlocallabreparsh, @@ -5038,6 +5052,7 @@ void LocallabShadow::updateShadowGUI2() gamFrame->hide(); detailSH->hide(); + tePivot->hide(); highlights->show(); h_tonalwidth->show(); shadows->show(); @@ -5053,6 +5068,7 @@ void LocallabShadow::updateShadowGUI2() } detailSH->show(); + tePivot->show(); highlights->hide(); h_tonalwidth->hide(); shadows->hide(); diff --git a/rtgui/locallabtools.h b/rtgui/locallabtools.h index e7fcfc1d0..72c6730e8 100644 --- a/rtgui/locallabtools.h +++ b/rtgui/locallabtools.h @@ -451,6 +451,7 @@ private: Adjuster* const reparsh; const std::array multipliersh; Adjuster* const detailSH; + Adjuster* const tePivot; Adjuster* const highlights; Adjuster* const h_tonalwidth; Adjuster* const shadows; @@ -492,6 +493,8 @@ private: Adjuster* const fatamountSH; Adjuster* const fatanchorSH; + rtengine::ProcEvent EvlocallabTePivot; + sigc::connection shMethodConn, inversshConn, showmaskSHMethodConn, showmaskSHMethodConninv, enaSHMaskConn; public: diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 598e15673..5ef83ed86 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -1283,6 +1283,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).slomaskSH = locallab.spots.at(j).slomaskSH && pSpot.slomaskSH == otherSpot.slomaskSH; locallab.spots.at(j).lapmaskSH = locallab.spots.at(j).lapmaskSH && pSpot.lapmaskSH == otherSpot.lapmaskSH; locallab.spots.at(j).detailSH = locallab.spots.at(j).detailSH && pSpot.detailSH == otherSpot.detailSH; + locallab.spots.at(j).tePivot = locallab.spots.at(j).tePivot && pSpot.tePivot == otherSpot.tePivot; locallab.spots.at(j).reparsh = locallab.spots.at(j).reparsh && pSpot.reparsh == otherSpot.reparsh; locallab.spots.at(j).LmaskSHcurve = locallab.spots.at(j).LmaskSHcurve && pSpot.LmaskSHcurve == otherSpot.LmaskSHcurve; locallab.spots.at(j).fatamountSH = locallab.spots.at(j).fatamountSH && pSpot.fatamountSH == otherSpot.fatamountSH; @@ -4182,6 +4183,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).detailSH = mods.locallab.spots.at(i).detailSH; } + if (locallab.spots.at(i).tePivot) { + toEdit.locallab.spots.at(i).tePivot = mods.locallab.spots.at(i).tePivot; + } + if (locallab.spots.at(i).reparsh) { toEdit.locallab.spots.at(i).reparsh = mods.locallab.spots.at(i).reparsh; } @@ -7624,6 +7629,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : slomaskSH(v), lapmaskSH(v), detailSH(v), + tePivot(v), reparsh(v), LmaskSHcurve(v), fatamountSH(v), @@ -8320,6 +8326,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) slomaskSH = v; lapmaskSH = v; detailSH = v; + tePivot = v; reparsh = v; LmaskSHcurve = v; fatamountSH = v; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index f34eba69b..f5f318088 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -589,6 +589,7 @@ public: bool slomaskSH; bool lapmaskSH; bool detailSH; + bool tePivot; bool reparsh; bool LmaskSHcurve; bool fatamountSH;