From bd3bd809b5415b875c0a8d38c18cfb0c1cc2e34a Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 1 May 2022 16:13:27 -0700 Subject: [PATCH 01/14] Port tone equalizer from ART Merge with local adjustments tone equalizer image processing function for consistent results. To-do: Enable for batch editing and add pivot/colormap to the local adjustments version. --- rtdata/languages/default | 15 ++ rtengine/CMakeLists.txt | 1 + rtengine/imagefloat.cc | 68 ++++--- rtengine/imagefloat.h | 5 +- rtengine/improccoordinator.cc | 1 + rtengine/improcfun.cc | 6 + rtengine/improcfun.h | 4 +- rtengine/iplocallab.cc | 227 +-------------------- rtengine/iptoneequalizer.cc | 362 ++++++++++++++++++++++++++++++++++ rtengine/procparams.cc | 44 +++++ rtengine/procparams.h | 17 ++ rtgui/CMakeLists.txt | 1 + rtgui/adjuster.cc | 27 ++- rtgui/adjuster.h | 2 + rtgui/paramsedited.cc | 30 +++ rtgui/paramsedited.h | 9 + rtgui/partialpastedlg.cc | 9 + rtgui/partialpastedlg.h | 2 + rtgui/thumbnail.cc | 1 + rtgui/toneequalizer.cc | 169 ++++++++++++++++ rtgui/toneequalizer.h | 56 ++++++ rtgui/toolpanelcoord.cc | 2 + rtgui/toolpanelcoord.h | 2 + 23 files changed, 794 insertions(+), 266 deletions(-) create mode 100644 rtengine/iptoneequalizer.cc create mode 100644 rtgui/toneequalizer.cc create mode 100644 rtgui/toneequalizer.h diff --git a/rtdata/languages/default b/rtdata/languages/default index a3e99cfc2..6dd32ef7b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1520,6 +1520,11 @@ HISTORY_MSG_SPOT_ENTRY;Spot removal - Point modif. HISTORY_MSG_TEMPOUT;CAM02 automatic temperature HISTORY_MSG_THRESWAV;Balance threshold HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - Anchor +HISTORY_MSG_TONE_EQUALIZER_BANDS;Tone equalizer - Bands +HISTORY_MSG_TONE_EQUALIZER_ENABLED;Tone equalizer +HISTORY_MSG_TONE_EQUALIZER_PIVOT;Tone equalizer - Pivot +HISTORY_MSG_TONE_EQUALIZER_REGULARIZATION;Tone equalizer - Regularization +HISTORY_MSG_TONE_EQUALIZER_SHOW_COLOR_MAP;Tone equalizer - Tonal map HISTORY_MSG_TRANS_METHOD;Geometry - Method HISTORY_MSG_WAVBALCHROM;Equalizer chrominance HISTORY_MSG_WAVBALLUM;Equalizer luminance @@ -1827,6 +1832,7 @@ PARTIALPASTE_SHARPENMICRO;Microcontrast PARTIALPASTE_SOFTLIGHT;Soft light PARTIALPASTE_SPOT;Spot removal PARTIALPASTE_TM_FATTAL;Dynamic range compression +PARTIALPASTE_TONE_EQUALIZER;Tone equalizer PARTIALPASTE_VIBRANCE;Vibrance PARTIALPASTE_VIGNETTING;Vignetting correction PARTIALPASTE_WHITEBALANCE;White balance @@ -3837,6 +3843,15 @@ TP_TM_FATTAL_AMOUNT;Amount TP_TM_FATTAL_ANCHOR;Anchor TP_TM_FATTAL_LABEL;Dynamic Range Compression TP_TM_FATTAL_THRESHOLD;Detail +TP_TONE_EQUALIZER_BAND_0;Blacks +TP_TONE_EQUALIZER_BAND_1;Shadows +TP_TONE_EQUALIZER_BAND_2;Midtones +TP_TONE_EQUALIZER_BAND_3;Highlights +TP_TONE_EQUALIZER_BAND_4;Whites +TP_TONE_EQUALIZER_DETAIL;Regularization +TP_TONE_EQUALIZER_LABEL;Tone Equalizer +TP_TONE_EQUALIZER_PIVOT;Pivot (Ev) +TP_TONE_EQUALIZER_SHOW_COLOR_MAP;Show tonal map TP_VIBRANCE_AVOIDCOLORSHIFT;Avoid color shift TP_VIBRANCE_CURVEEDITOR_SKINTONES;HH TP_VIBRANCE_CURVEEDITOR_SKINTONES_LABEL;Skin-tones diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 1f3cf352b..3cc8df625 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -133,6 +133,7 @@ set(RTENGINESOURCEFILES ipsharpen.cc ipsharpenedges.cc ipsoftlight.cc + iptoneequalizer.cc iptransform.cc ipvibrance.cc ipwavelet.cc diff --git a/rtengine/imagefloat.cc b/rtengine/imagefloat.cc index 7bc75fe6d..e4cb28e6b 100644 --- a/rtengine/imagefloat.cc +++ b/rtengine/imagefloat.cc @@ -341,6 +341,38 @@ void Imagefloat::getStdImage (const ColorTemp &ctemp, int tran, Imagefloat* imag #endif } +// From ART. +void Imagefloat::multiply(float factor, bool multithread) +{ + const int W = width; + const int H = height; +#ifdef __SSE2__ + vfloat vfactor = F2V(factor); +#endif + +#ifdef _OPENMP +# pragma omp parallel for firstprivate(W, H) schedule(dynamic, 5) if (multithread) +#endif + for (int y = 0; y < H; y++) { + int x = 0; +#ifdef __SSE2__ + for (; x < W-3; x += 4) { + vfloat rv = LVF(r(y, x)); + vfloat gv = LVF(g(y, x)); + vfloat bv = LVF(b(y, x)); + STVF(r(y, x), rv * vfactor); + STVF(g(y, x), gv * vfactor); + STVF(b(y, x), bv * vfactor); + } +#endif + for (; x < W; ++x) { + r(y, x) *= factor; + g(y, x) *= factor; + b(y, x) *= factor; + } + } +} + void Imagefloat::normalizeFloat(float srcMinVal, float srcMaxVal) { @@ -362,43 +394,15 @@ void Imagefloat::normalizeFloat(float srcMinVal, float srcMaxVal) } // convert values's range to [0;1] ; this method assumes that the input values's range is [0;65535] -void Imagefloat::normalizeFloatTo1() +void Imagefloat::normalizeFloatTo1(bool multithread) { - - const int w = width; - const int h = height; - -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic, 5) -#endif - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - r(y, x) /= 65535.f; - g(y, x) /= 65535.f; - b(y, x) /= 65535.f; - } - } + multiply(1.f/65535.f, multithread); } // convert values's range to [0;65535 ; this method assumes that the input values's range is [0;1] -void Imagefloat::normalizeFloatTo65535() +void Imagefloat::normalizeFloatTo65535(bool multithread) { - - const int w = width; - const int h = height; - -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic, 5) -#endif - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - r(y, x) *= 65535.f; - g(y, x) *= 65535.f; - b(y, x) *= 65535.f; - } - } + multiply(65535.f, multithread); } // Parallelized transformation; create transform with cmsFLAGS_NOCACHE! diff --git a/rtengine/imagefloat.h b/rtengine/imagefloat.h index fc3ba318d..3bee52d9a 100644 --- a/rtengine/imagefloat.h +++ b/rtengine/imagefloat.h @@ -207,9 +207,10 @@ public: return (uint32_t) ((lsign << 31) | (exponent << 23) | mantissa); } + void multiply(float factor, bool multithread); void normalizeFloat(float srcMinVal, float srcMaxVal) override; - void normalizeFloatTo1(); - void normalizeFloatTo65535(); + void normalizeFloatTo1(bool multithread=true); + void normalizeFloatTo65535(bool multithread=true); void ExecCMSTransform(cmsHTRANSFORM hTransform); void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy); }; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 33cce1842..cb9f6500f 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -2734,6 +2734,7 @@ void ImProcCoordinator::process() || params->epd != nextParams->epd || params->fattal != nextParams->fattal || params->sh != nextParams->sh + || params->toneEqualizer != nextParams->toneEqualizer || params->crop != nextParams->crop || params->coarse != nextParams->coarse || params->commonTrans != nextParams->commonTrans diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 15ebcc2e6..e50e28a01 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -2258,6 +2258,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // For tonecurve histogram const float lumimulf[3] = {static_cast(lumimul[0]), static_cast(lumimul[1]), static_cast(lumimul[2])}; + std::unique_ptr workimg_copy; + if (params->toneEqualizer.enabled) { + working = working->copy(); + workimg_copy.reset(working); + toneEqualizer(working); + } #define TS 112 diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 1be1d0371..70aed428c 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -97,6 +97,7 @@ struct LocalContrastParams; struct LocallabParams; struct SharpeningParams; struct SoftLightParams; +struct ToneEqualizerParams; struct VibranceParams; struct VignettingParams; struct WaveletParams; @@ -491,7 +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 softLight(LabImage *lab, const procparams::SoftLightParams &softLightParams); void labColorCorrectionRegions(LabImage *lab); diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index ac87c75d7..7a427b0eb 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -2258,230 +2258,11 @@ 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) -// adapted from the tone equalizer of darktable -/* - Copyright 2019 Alberto Griggio - Small adaptation to Local Adjustment 10 2019 Jacques Desmis - This file is part of darktable, - copyright (c) 2018 Aurelien Pierre. - - 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 . -*/ - { - // BENCHFUN - - const int W = R.getWidth(); - const int H = R.getHeight(); - array2D Y(W, H); - - const auto log2 = - [](float x) -> float { - static const float l2 = xlogf(2); - return xlogf(x) / l2; - }; - - const auto exp2 = - [](float x) -> float { - return pow_F(2.f, x); - }; - // Build the luma channels: band-pass filters with gaussian windows of - // std 2 EV, spaced by 2 EV - const float centers[12] = { - -18.0f, -16.0f, -14.0f, -12.0f, -10.0f, -8.0f, -6.0f, - -4.0f, -2.0f, 0.0f, 2.0f, 4.0f - }; - - const auto conv = [&](int v, float lo, float hi) -> float { - const float f = v < 0 ? lo : hi; - return exp2(float(v) / 100.f * f); - }; - const float factors[12] = { - conv(lp.mullocsh[0], 2.f, 3.f), // -18 EV - conv(lp.mullocsh[0], 2.f, 3.f), // -16 EV - conv(lp.mullocsh[0], 2.f, 3.f), // -14 EV - conv(lp.mullocsh[0], 2.f, 3.f), // -12 EV - conv(lp.mullocsh[0], 2.f, 3.f), // -10 EV - conv(lp.mullocsh[0], 2.f, 3.f), // -8 EV - conv(lp.mullocsh[1], 2.f, 3.f), // -6 EV - conv(lp.mullocsh[2], 2.5f, 2.5f), // -4 EV - conv(lp.mullocsh[3], 3.f, 2.f), // -2 EV - conv(lp.mullocsh[4], 3.f, 2.f), // 0 EV - conv(lp.mullocsh[4], 3.f, 2.f), // 2 EV - conv(lp.mullocsh[4], 3.f, 2.f) // 4 EV - }; - - TMatrix ws = 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); - } - } - - int detail = LIM(lp.detailsh + 5, 0, 5); - int radius = detail / scale + 0.5; - float epsilon2 = 0.01f + 0.002f * rtengine::max(detail - 3, 0); - - if (radius > 0) { - rtengine::guidedFilterLog(10.f, Y, radius, epsilon2, multithread); - } - - if (lp.detailsh > 0) { - array2D Y2(W, H); - constexpr float base_epsilon = 0.02f; - constexpr float base_posterization = 5.f; - -#ifdef _OPENMP - #pragma omp parallel for if (multithread) -#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 ll = round(l * base_posterization) / base_posterization; - Y2[y][x] = Y[y][x]; - Y[y][x] = exp2(ll); - } - } - - radius = 350.0 / scale; - epsilon2 = base_epsilon / float(6 - rtengine::min(lp.detailsh, 5)); - rtengine::guidedFilter(Y2, Y, Y, radius, epsilon2, multithread); - } - - const auto gauss = - [](float b, float x) -> float { - return xexpf((-SQR(x - b) / 4.0f)); - }; - - // For every pixel luminance, the sum of the gaussian masks - float w_sum = 0.f; - - for (int i = 0; i < 12; ++i) { - w_sum += gauss(centers[i], 0.f); - } - - const auto process_pixel = - [&](float y) -> float { - // convert to log space - 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 - float correction = 0.0f; - - for (int c = 0; c < 12; ++c) - { - correction += gauss(centers[c], luma) * factors[c]; - } - - correction /= w_sum; - - return correction; - }; - - LUTf lut(65536); - - for (int i = 0; i < 65536; ++i) { - float y = float(i) / 65535.f; - float c = process_pixel(y); - lut[i] = c; - } - - -#ifdef __SSE2__ - vfloat vfactors[12]; - vfloat vcenters[12]; - - for (int i = 0; i < 12; ++i) { - vfactors[i] = F2V(factors[i]); - vcenters[i] = F2V(centers[i]); - } - - const auto vgauss = - [](vfloat b, vfloat x) -> vfloat { - static const vfloat fourv = F2V(4.f); - return xexpf((-SQR(x - b) / fourv)); - }; - - vfloat zerov = F2V(0.f); - vfloat vw_sum = F2V(w_sum); - - const vfloat noisev = F2V(-18.f); - const vfloat xlog2v = F2V(xlogf(2.f)); - - const auto vprocess_pixel = - [&](vfloat y) -> vfloat { - const vfloat luma = vmaxf(xlogf(vmaxf(y, zerov)) / xlog2v, noisev); - - vfloat correction = zerov; - - for (int c = 0; c < 12; ++c) - { - correction += vgauss(vcenters[c], luma) * vfactors[c]; - } - - correction /= vw_sum; - - return correction; - }; - - - vfloat v1 = F2V(1.f); - vfloat v65535 = F2V(65535.f); -#endif // __SSE2__ - - -#ifdef _OPENMP - #pragma omp parallel for if (multithread) -#endif - for (int y = 0; y < H; ++y) { - int x = 0; - - -#ifdef __SSE2__ - - for (; x < W - 3; x += 4) { - vfloat cY = LVFU(Y[y][x]); - vmask m = vmaskf_gt(cY, v1); - vfloat corr; - - if (_mm_movemask_ps((vfloat)m)) { - corr = vprocess_pixel(cY); - } else { - corr = lut[cY * v65535]; - } - - STVF(R[y][x], LVF(R[y][x]) * corr); - STVF(G[y][x], LVF(G[y][x]) * corr); - STVF(B[y][x], LVF(B[y][x]) * corr); - } - -#endif // __SSE2__ - - for (; x < W; ++x) { - float cY = Y[y][x]; - float corr = cY > 1.f ? process_pixel(cY) : lut[cY * 65535.f]; - R[y][x] *= corr; - G[y][x] *= corr; - B[y][x] *= corr; - } - } - + ToneEqualizerParams params; + params.regularization = lp.detailsh; + std::copy(lp.mullocsh, lp.mullocsh + params.bands.size(), params.bands.begin()); + ImProcFunctions::toneEqualizer(R, G, B, params, workingProfile, scale, multithread, false); } void ImProcFunctions::loccont(int bfw, int bfh, LabImage* tmp1, float rad, float stren, int sk) { diff --git a/rtengine/iptoneequalizer.cc b/rtengine/iptoneequalizer.cc new file mode 100644 index 000000000..c177b8f98 --- /dev/null +++ b/rtengine/iptoneequalizer.cc @@ -0,0 +1,362 @@ +#include "color.h" +#include "guidedfilter.h" +#include "iccstore.h" +#include "imagefloat.h" +#include "improcfun.h" +#include "sleef.h" +#include "StopWatch.h" + + +namespace +{ + +const std::vector> colormap = { + {0.5f, 0.f, 0.5f}, + {0.5f, 0.f, 0.5f}, + {0.5f, 0.f, 0.5f}, + {0.5f, 0.f, 0.5f}, + {0.5f, 0.f, 0.5f}, + {0.5f, 0.f, 0.5f}, // blacks + {0.f, 0.f, 1.f}, // shadows + {0.5f, 0.5f, 0.5f}, // midtones + {1.f, 1.f, 0.f}, // highlights + {1.f, 0.f, 0.f}, // whites + {1.f, 0.f, 0.f}, + {1.f, 0.f, 0.f} +}; + +} + + +namespace rtengine +{ + +void ImProcFunctions::toneEqualizer( + array2D &R, array2D &G, array2D &B, + const struct ToneEqualizerParams ¶ms, + const Glib::ustring &workingProfile, + double scale, + bool multithread, + bool show_color_map) +// adapted from the tone equalizer of darktable +/* + Copyright 2019 Alberto Griggio + Small adaptation to Local Adjustment 10 2019 Jacques Desmis + This file is part of darktable, + copyright (c) 2018 Aurelien Pierre. + + 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 . +*/ + +{ + // BENCHFUN + + const int W = R.getWidth(); + const int H = R.getHeight(); + array2D Y(W, H); + + const auto log2 = + [](float x) -> float { + static const float l2 = xlogf(2); + return xlogf(x) / l2; + }; + + const auto exp2 = + [](float x) -> float { + return pow_F(2.f, x); + }; + // Build the luma channels: band-pass filters with gaussian windows of + // std 2 EV, spaced by 2 EV + const float centers[12] = { + -18.0f, -16.0f, -14.0f, -12.0f, -10.0f, -8.0f, -6.0f, + -4.0f, -2.0f, 0.0f, 2.0f, 4.0f + }; + + const auto conv = [&](int v, float lo, float hi) -> float { + const float f = v < 0 ? lo : hi; + return exp2(float(v) / 100.f * f); + }; + const float factors[12] = { + conv(params.bands[0], 2.f, 3.f), // -18 EV + conv(params.bands[0], 2.f, 3.f), // -16 EV + conv(params.bands[0], 2.f, 3.f), // -14 EV + conv(params.bands[0], 2.f, 3.f), // -12 EV + conv(params.bands[0], 2.f, 3.f), // -10 EV + conv(params.bands[0], 2.f, 3.f), // -8 EV + conv(params.bands[1], 2.f, 3.f), // -6 EV + conv(params.bands[2], 2.5f, 2.5f), // -4 EV + conv(params.bands[3], 3.f, 2.f), // -2 EV + conv(params.bands[4], 3.f, 2.f), // 0 EV + conv(params.bands[4], 3.f, 2.f), // 2 EV + conv(params.bands[4], 3.f, 2.f) // 4 EV + }; + + TMatrix ws = 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); + } + } + + int detail = LIM(params.regularization + 5, 0, 5); + int radius = detail / scale + 0.5; + float epsilon2 = 0.01f + 0.002f * rtengine::max(detail - 3, 0); + + if (radius > 0) { + rtengine::guidedFilterLog(10.f, Y, radius, epsilon2, multithread); + } + + if (params.regularization > 0) { + array2D Y2(W, H); + constexpr float base_epsilon = 0.02f; + constexpr float base_posterization = 5.f; + +#ifdef _OPENMP + #pragma omp parallel for if (multithread) +#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 ll = round(l * base_posterization) / base_posterization; + Y2[y][x] = Y[y][x]; + Y[y][x] = exp2(ll); + } + } + + radius = 350.0 / scale; + epsilon2 = base_epsilon / float(6 - rtengine::min(params.regularization, 5)); + rtengine::guidedFilter(Y2, Y, Y, radius, epsilon2, multithread); + } + + const auto gauss = + [](float b, float x) -> float { + return xexpf((-SQR(x - b) / 4.0f)); + }; + + // For every pixel luminance, the sum of the gaussian masks + float w_sum = 0.f; + + for (int i = 0; i < 12; ++i) { + w_sum += gauss(centers[i], 0.f); + } + + const auto process_pixel = + [&](float y) -> float { + // convert to log space + 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 + float correction = 0.0f; + + for (int c = 0; c < 12; ++c) + { + correction += gauss(centers[c], luma) * factors[c]; + } + + correction /= w_sum; + + return correction; + }; + + std::vector> cur_colormap; + if (show_color_map) { + lcmsMutex->lock(); + cmsHPROFILE in = ICCStore::getInstance()->getsRGBProfile(); + cmsHPROFILE out = ICCStore::getInstance()->workingSpace(workingProfile); + cmsHTRANSFORM xform = cmsCreateTransform(in, TYPE_RGB_FLT, out, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); + lcmsMutex->unlock(); + + for (auto &c : colormap) { + cur_colormap.push_back(c); + auto &cc = cur_colormap.back(); + cmsDoTransform(xform, &cc[0], &cc[0], 1); + } + + cmsDeleteTransform(xform); + } + + const auto process_colormap = + [&](float y) -> std::array + { + std::array ret = { 0.f, 0.f, 0.f }; + + // convert to log space + const float luma = max(log2(max(y, 0.f)), -18.0f); + + // build the correction as the sum of the contribution of each + // luminance channel to current pixel + for (int c = 0; c < 12; ++c) { + float w = gauss(centers[c], luma); + for (int i = 0; i < 3; ++i) { + ret[i] += w * cur_colormap[c][i]; + } + } + for (int i = 0; i < 3; ++i) { + ret[i] = LIM01(ret[i] / w_sum); + } + + return ret; + }; + + +#ifdef __SSE2__ + vfloat vfactors[12]; + vfloat vcenters[12]; + + for (int i = 0; i < 12; ++i) { + vfactors[i] = F2V(factors[i]); + vcenters[i] = F2V(centers[i]); + } + + const auto vgauss = + [](vfloat b, vfloat x) -> vfloat { + static const vfloat fourv = F2V(4.f); + return xexpf((-SQR(x - b) / fourv)); + }; + + vfloat zerov = F2V(0.f); + vfloat vw_sum = F2V(w_sum); + + const vfloat noisev = F2V(-18.f); + const vfloat xlog2v = F2V(xlogf(2.f)); + + const auto vprocess_pixel = + [&](vfloat y) -> vfloat { + const vfloat luma = vmaxf(xlogf(vmaxf(y, zerov)) / xlog2v, noisev); + + vfloat correction = zerov; + + for (int c = 0; c < 12; ++c) + { + correction += vgauss(vcenters[c], luma) * vfactors[c]; + } + + correction /= vw_sum; + + return correction; + }; + + + vfloat v1 = F2V(1.f); + vfloat v65535 = F2V(65535.f); +#endif // __SSE2__ + + + if (show_color_map) { + LUTf lut_r(65537), lut_g(65537), lut_b(65537); + for (int i = 0; i < 65536; ++i) { + float y = float(i)/65535.f; + auto rgb = process_colormap(y); + lut_r[i] = rgb[0]; + lut_g[i] = rgb[1]; + lut_b[i] = rgb[2]; + } + lut_r[65536] = cur_colormap.back()[0]; + lut_g[65536] = cur_colormap.back()[1]; + lut_b[65536] = cur_colormap.back()[2]; + +#ifdef _OPENMP +# pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + float cY = Y[y][x] * 65535.f; + R[y][x] = lut_r[cY]; + G[y][x] = lut_g[cY]; + B[y][x] = lut_b[cY]; + } + } + return; + } + + + LUTf lut(65536); + + for (int i = 0; i < 65536; ++i) { + float y = float(i) / 65535.f; + float c = process_pixel(y); + lut[i] = c; + } + +#ifdef _OPENMP + #pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < H; ++y) { + int x = 0; + + +#ifdef __SSE2__ + + for (; x < W - 3; x += 4) { + vfloat cY = LVFU(Y[y][x]); + vmask m = vmaskf_gt(cY, v1); + vfloat corr; + + if (_mm_movemask_ps((vfloat)m)) { + corr = vprocess_pixel(cY); + } else { + corr = lut[cY * v65535]; + } + + STVF(R[y][x], LVF(R[y][x]) * corr); + STVF(G[y][x], LVF(G[y][x]) * corr); + STVF(B[y][x], LVF(B[y][x]) * corr); + } + +#endif // __SSE2__ + + for (; x < W; ++x) { + float cY = Y[y][x]; + float corr = cY > 1.f ? process_pixel(cY) : lut[cY * 65535.f]; + R[y][x] *= corr; + G[y][x] *= corr; + B[y][x] *= corr; + } + } + +} + +bool ImProcFunctions::toneEqualizer(Imagefloat *rgb) +{ + if (!params->toneEqualizer.enabled) { + return false; + } + + BENCHFUN + + const float gain = 1.f / 65535.f * std::pow(2.f, -params->toneEqualizer.pivot); + + rgb->multiply(gain, multiThread); + + const int W = rgb->getWidth(); + const int H = rgb->getHeight(); + + array2D R(W, H, rgb->r.ptrs, ARRAY2D_BYREFERENCE); + 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); + + rgb->multiply(1.f/gain, multiThread); + + return show_color_map; +} + +} diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 9a9e4fef1..555af6879 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -1786,6 +1786,30 @@ bool SHParams::operator !=(const SHParams& other) const return !(*this == other); } +ToneEqualizerParams::ToneEqualizerParams() : + enabled(false), + bands{0, 0, 0, 0, 0}, + regularization(4), + show_colormap(false), + pivot(0) +{ +} + +bool ToneEqualizerParams::operator ==(const ToneEqualizerParams &other) const +{ + return + enabled == other.enabled + && bands == other.bands + && regularization == other.regularization + && show_colormap == other.show_colormap + && pivot == other.pivot; +} + +bool ToneEqualizerParams::operator !=(const ToneEqualizerParams &other) const +{ + return !(*this == other); +} + CropParams::CropParams() : enabled(false), x(-1), @@ -5814,6 +5838,8 @@ void ProcParams::setDefaults() sh = {}; + toneEqualizer = {}; + crop = {}; coarse = {}; @@ -6241,6 +6267,14 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->sh.radius, "Shadows & Highlights", "Radius", sh.radius, keyFile); saveToKeyfile(!pedited || pedited->sh.lab, "Shadows & Highlights", "Lab", sh.lab, keyFile); +// Tone equalizer + saveToKeyfile(!pedited || pedited->toneEqualizer.enabled, "ToneEqualizer", "Enabled", toneEqualizer.enabled, keyFile); + for (size_t i = 0; i < toneEqualizer.bands.size(); ++i) { + saveToKeyfile(!pedited || pedited->toneEqualizer.bands, "ToneEqualizer", "Band" + std::to_string(i), toneEqualizer.bands[i], keyFile); + } + saveToKeyfile(!pedited || pedited->toneEqualizer.regularization, "ToneEqualizer", "Regularization", toneEqualizer.regularization, keyFile); + saveToKeyfile(!pedited || pedited->toneEqualizer.pivot, "ToneEqualizer", "Pivot", toneEqualizer.pivot, keyFile); + // Crop saveToKeyfile(!pedited || pedited->crop.enabled, "Crop", "Enabled", crop.enabled, keyFile); saveToKeyfile(!pedited || pedited->crop.x, "Crop", "X", crop.x, keyFile); @@ -8226,6 +8260,15 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } } + if (keyFile.has_group("ToneEqualizer")) { + assignFromKeyfile(keyFile, "ToneEqualizer", "Enabled", pedited, toneEqualizer.enabled, pedited->toneEqualizer.enabled); + for (size_t i = 0; i < toneEqualizer.bands.size(); ++i) { + assignFromKeyfile(keyFile, "ToneEqualizer", "Band" + std::to_string(i), pedited, toneEqualizer.bands[i], pedited->toneEqualizer.bands); + } + assignFromKeyfile(keyFile, "ToneEqualizer", "Regularization", pedited, toneEqualizer.regularization, pedited->toneEqualizer.regularization); + assignFromKeyfile(keyFile, "ToneEqualizer", "Pivot", pedited, toneEqualizer.pivot, pedited->toneEqualizer.pivot); + } + if (keyFile.has_group("Crop")) { assignFromKeyfile(keyFile, "Crop", "Enabled", pedited, crop.enabled, pedited->crop.enabled); assignFromKeyfile(keyFile, "Crop", "X", pedited, crop.x, pedited->crop.x); @@ -10447,6 +10490,7 @@ bool ProcParams::operator ==(const ProcParams& other) const && fattal == other.fattal && defringe == other.defringe && sh == other.sh + && toneEqualizer == other.toneEqualizer && crop == other.crop && coarse == other.coarse && rotate == other.rotate diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 04229867b..5a86b40a0 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -827,6 +827,22 @@ struct SHParams { bool operator !=(const SHParams& other) const; }; +/** + * Tone equalizer parameters. + */ +struct ToneEqualizerParams { + bool enabled; + std::array bands; + int regularization; + bool show_colormap; + double pivot; + + ToneEqualizerParams(); + + bool operator ==(const ToneEqualizerParams &other) const; + bool operator !=(const ToneEqualizerParams &other) const; +}; + /** * Parameters of the cropping */ @@ -2547,6 +2563,7 @@ public: EPDParams epd; ///< Edge Preserving Decomposition parameters FattalToneMappingParams fattal; ///< Fattal02 tone mapping SHParams sh; ///< Shadow/highlight enhancement parameters + ToneEqualizerParams toneEqualizer; ///< Tone equalizer parameters CropParams crop; ///< Crop parameters CoarseTransformParams coarse; ///< Coarse transformation (90, 180, 270 deg rotation, h/v flipping) parameters CommonTransformParams commonTrans; ///< Common transformation parameters (autofill) diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 7976bdc7a..1d56f2638 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -159,6 +159,7 @@ set(NONCLISOURCEFILES thumbimageupdater.cc thumbnail.cc tonecurve.cc + toneequalizer.cc toolbar.cc toolpanel.cc toolpanelcoord.cc diff --git a/rtgui/adjuster.cc b/rtgui/adjuster.cc index a2f96cac3..3fe3d61eb 100644 --- a/rtgui/adjuster.cc +++ b/rtgui/adjuster.cc @@ -51,6 +51,7 @@ Adjuster::Adjuster( grid(nullptr), label(nullptr), imageIcon1(imgIcon1), + imageIcon2(imgIcon2), automatic(nullptr), adjusterListener(nullptr), spinChange(options.adjusterMinDelay, options.adjusterMaxDelay), @@ -76,8 +77,8 @@ Adjuster::Adjuster( setExpandAlignProperties(imageIcon1, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); } - if (imgIcon2) { - setExpandAlignProperties(imgIcon2, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + if (imageIcon2) { + setExpandAlignProperties(imageIcon2, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); } set_column_spacing(0); @@ -120,9 +121,9 @@ Adjuster::Adjuster( attach_next_to(*imageIcon1, *slider, Gtk::POS_LEFT, 1, 1); } - if (imgIcon2) { - attach_next_to(*imgIcon2, *slider, Gtk::POS_RIGHT, 1, 1); - attach_next_to(*spin, *imgIcon2, Gtk::POS_RIGHT, 1, 1); + if (imageIcon2) { + attach_next_to(*imageIcon2, *slider, Gtk::POS_RIGHT, 1, 1); + attach_next_to(*spin, *imageIcon2, Gtk::POS_RIGHT, 1, 1); } else { attach_next_to(*spin, *slider, Gtk::POS_RIGHT, 1, 1); } @@ -140,9 +141,9 @@ Adjuster::Adjuster( grid->attach_next_to(*imageIcon1, *slider, Gtk::POS_LEFT, 1, 1); } - if (imgIcon2) { - grid->attach_next_to(*imgIcon2, Gtk::POS_RIGHT, 1, 1); - grid->attach_next_to(*reset, *imgIcon2, Gtk::POS_RIGHT, 1, 1); + if (imageIcon2) { + grid->attach_next_to(*imageIcon2, Gtk::POS_RIGHT, 1, 1); + grid->attach_next_to(*reset, *imageIcon2, Gtk::POS_RIGHT, 1, 1); } else { grid->attach_next_to(*reset, *slider, Gtk::POS_RIGHT, 1, 1); } @@ -683,3 +684,13 @@ void Adjuster::setDelay(unsigned int min_delay_ms, unsigned int max_delay_ms) spinChange.setDelay(min_delay_ms, max_delay_ms); sliderChange.setDelay(min_delay_ms, max_delay_ms); } + +void Adjuster::showIcons(bool yes) +{ + if (imageIcon1) { + imageIcon1->set_visible(yes); + } + if (imageIcon2) { + imageIcon2->set_visible(yes); + } +} diff --git a/rtgui/adjuster.h b/rtgui/adjuster.h index abafbd730..76b46b094 100644 --- a/rtgui/adjuster.h +++ b/rtgui/adjuster.h @@ -41,6 +41,7 @@ protected: Gtk::Grid* grid; Gtk::Label* label; Gtk::Image *imageIcon1; + Gtk::Image *imageIcon2; MyHScale* slider; MySpinButton* spin; Gtk::Button* reset; @@ -133,4 +134,5 @@ public: void trimValue (int &val) const; void setLogScale(double base, double pivot, bool anchorMiddle = false); void setDelay(unsigned int min_delay_ms, unsigned int max_delay_ms = 0); + void showIcons(bool yes); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 529d57da6..ff48a58b1 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -317,6 +317,11 @@ void ParamsEdited::set(bool v) sh.stonalwidth = v; sh.radius = v; sh.lab = v; + toneEqualizer.enabled = v; + toneEqualizer.bands = v; + toneEqualizer.regularization = v; + toneEqualizer.show_colormap = v; + toneEqualizer.pivot = v; crop.enabled = v; crop.x = v; crop.y = v; @@ -1031,6 +1036,11 @@ void ParamsEdited::initFrom(const std::vector& crop.ratio = crop.ratio && p.crop.ratio == other.crop.ratio; crop.orientation = crop.orientation && p.crop.orientation == other.crop.orientation; crop.guide = crop.guide && p.crop.guide == other.crop.guide; + toneEqualizer.enabled = toneEqualizer.enabled && p.toneEqualizer.enabled == other.toneEqualizer.enabled; + toneEqualizer.bands = toneEqualizer.bands && p.toneEqualizer.bands == other.toneEqualizer.bands; + toneEqualizer.regularization = toneEqualizer.regularization && p.toneEqualizer.regularization == other.toneEqualizer.regularization; + toneEqualizer.show_colormap = toneEqualizer.show_colormap && p.toneEqualizer.show_colormap == other.toneEqualizer.show_colormap; + toneEqualizer.pivot = toneEqualizer.pivot && p.toneEqualizer.pivot == other.toneEqualizer.pivot; coarse.rotate = coarse.rotate && p.coarse.rotate == other.coarse.rotate; coarse.hflip = coarse.hflip && p.coarse.hflip == other.coarse.hflip; coarse.vflip = coarse.vflip && p.coarse.vflip == other.coarse.vflip; @@ -3194,6 +3204,26 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.sh.lab = mods.sh.lab; } + if (toneEqualizer.enabled) { + toEdit.toneEqualizer.enabled = mods.toneEqualizer.enabled; + } + + if (toneEqualizer.bands) { + toEdit.toneEqualizer.bands = mods.toneEqualizer.bands; + } + + if (toneEqualizer.regularization) { + toEdit.toneEqualizer.regularization = mods.toneEqualizer.regularization; + } + + if (toneEqualizer.show_colormap) { + toEdit.toneEqualizer.show_colormap = mods.toneEqualizer.show_colormap; + } + + if (toneEqualizer.pivot) { + toEdit.toneEqualizer.pivot = mods.toneEqualizer.pivot; + } + if (crop.enabled) { toEdit.crop.enabled = mods.crop.enabled; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 94abed470..d70336a54 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -358,6 +358,14 @@ struct SHParamsEdited { bool lab; }; +struct ToneEqualizerParamsEdited { + bool enabled; + bool bands; + bool regularization; + bool show_colormap; + bool pivot; +}; + struct CropParamsEdited { bool enabled; bool x; @@ -1545,6 +1553,7 @@ struct ParamsEdited { FattalToneMappingParamsEdited fattal; ImpulseDenoiseParamsEdited impulseDenoise; SHParamsEdited sh; + ToneEqualizerParamsEdited toneEqualizer; CropParamsEdited crop; CoarseTransformParamsEdited coarse; CommonTransformParamsEdited commonTrans; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index b3c49dfd7..08cf23f72 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -219,6 +219,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren wb = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_WHITEBALANCE"))); exposure = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EXPOSURE"))); sh = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SHADOWSHIGHLIGHTS"))); + toneEqualizer = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_TONE_EQUALIZER"))); epd = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EPD"))); fattal = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_TM_FATTAL"))); pcvignette = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PCVIGNETTE"))); @@ -331,6 +332,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[0]->pack_start (*wb, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*exposure, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*sh, Gtk::PACK_SHRINK, 2); + vboxes[0]->pack_start (*toneEqualizer, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*epd, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*fattal, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*pcvignette, Gtk::PACK_SHRINK, 2); @@ -496,6 +498,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren wbConn = wb->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); exposureConn = exposure->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); shConn = sh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); + toneEqualizerConn = toneEqualizer->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); epdConn = epd->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); fattalConn = fattal->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); pcvignetteConn = pcvignette->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); @@ -701,6 +704,7 @@ void PartialPasteDlg::basicToggled () ConnectionBlocker wbBlocker(wbConn); ConnectionBlocker exposureBlocker(exposureConn); ConnectionBlocker shBlocker(shConn); + ConnectionBlocker toneEqualizerBlocker(toneEqualizerConn); ConnectionBlocker epdBlocker(epdConn); ConnectionBlocker fattalBlocker(fattalConn); ConnectionBlocker pcvignetteBlocker(pcvignetteConn); @@ -712,6 +716,7 @@ void PartialPasteDlg::basicToggled () wb->set_active (basic->get_active ()); exposure->set_active (basic->get_active ()); sh->set_active (basic->get_active ()); + toneEqualizer->set_active (basic->get_active ()); epd->set_active (basic->get_active ()); fattal->set_active (basic->get_active ()); pcvignette->set_active (basic->get_active ()); @@ -889,6 +894,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.sh = falsePE.sh; } + if (!toneEqualizer->get_active ()) { + filterPE.toneEqualizer = falsePE.toneEqualizer; + } + if (!epd->get_active ()) { filterPE.epd = falsePE.epd; } diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index 19e1eb462..fc45bd5e4 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -133,6 +133,7 @@ public: Gtk::CheckButton* exposure; Gtk::CheckButton* localcontrast; Gtk::CheckButton* sh; + Gtk::CheckButton* toneEqualizer; Gtk::CheckButton* epd; Gtk::CheckButton* fattal; Gtk::CheckButton* retinex; @@ -225,6 +226,7 @@ public: sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, advancedConn; sigc::connection locallabConn; sigc::connection wbConn, exposureConn, localcontrastConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn; + sigc::connection toneEqualizerConn; sigc::connection spotConn, sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn, dehazeConn; sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn, chmixerbwConn, colortoningConn, filmSimulationConn, softlightConn; sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn; diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index cc8e9ad81..01aba228f 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -462,6 +462,7 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh || pparams->epd != pp.epd || pparams->fattal != pp.fattal || pparams->sh != pp.sh + || pparams->toneEqualizer != pp.toneEqualizer || pparams->crop != pp.crop || pparams->coarse != pp.coarse || pparams->commonTrans != pp.commonTrans diff --git a/rtgui/toneequalizer.cc b/rtgui/toneequalizer.cc new file mode 100644 index 000000000..366376ea4 --- /dev/null +++ b/rtgui/toneequalizer.cc @@ -0,0 +1,169 @@ +/* + * Adapted from ART. + * + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 . + */ +#include "eventmapper.h" +#include "toneequalizer.h" +#include "rtimage.h" + +using namespace rtengine; +using namespace rtengine::procparams; + + +ToneEqualizer::ToneEqualizer(): FoldableToolPanel(this, "toneequalizer", M("TP_TONE_EQUALIZER_LABEL"), false, true) +{ + auto m = ProcEventMapper::getInstance(); + EvEnabled = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_ENABLED"); + EvBands = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_BANDS"); + EvRegularization = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_REGULARIZATION"); + EvColormap = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_SHOW_COLOR_MAP"); + EvPivot = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_PIVOT"); + + std::array images = { + "purple", + "blue", + "gray", + "yellow", + "red" + }; + for (size_t i = 0; i < bands.size(); ++i) { + bands[i] = Gtk::manage(new Adjuster(M("TP_TONE_EQUALIZER_BAND_" + std::to_string(i)), -100, 100, 1, 0, Gtk::manage(new RTImage(Glib::ustring("circle-") + images[i] + "-small.png")))); + bands[i]->setAdjusterListener(this); + pack_start(*bands[i]); + bands[i]->showIcons(false); + } + + pivot = Gtk::manage(new Adjuster(M("TP_TONE_EQUALIZER_PIVOT"), -12, 12, 0.05, 0)); + pivot->setLogScale(64, 0, true); + pivot->setAdjusterListener(this); + pack_start(*pivot); + + pack_start(*Gtk::manage(new Gtk::HSeparator())); + regularization = Gtk::manage(new Adjuster(M("TP_TONE_EQUALIZER_DETAIL"), -5, 5, 1, 5)); + regularization->setAdjusterListener(this); + pack_start(*regularization); + + show_colormap = Gtk::manage(new Gtk::CheckButton(M("TP_TONE_EQUALIZER_SHOW_COLOR_MAP"))); + pack_start(*show_colormap); + show_colormap->signal_toggled().connect(sigc::mem_fun(this, &ToneEqualizer::colormapToggled)); + + show_all_children (); +} + + +void ToneEqualizer::read(const ProcParams *pp, const ParamsEdited* pedited) +{ + disableListener(); + + setEnabled(pp->toneEqualizer.enabled); + + for (size_t i = 0; i < bands.size(); ++i) { + bands[i]->setValue(pp->toneEqualizer.bands[i]); + bands[i]->showIcons(pp->toneEqualizer.show_colormap); + } + regularization->setValue(pp->toneEqualizer.regularization); + + pivot->setValue(pp->toneEqualizer.pivot); + show_colormap->set_active(pp->toneEqualizer.show_colormap); + + enableListener(); +} + + +void ToneEqualizer::write(ProcParams *pp, ParamsEdited* pedited) +{ + for (size_t i = 0; i < bands.size(); ++i) { + pp->toneEqualizer.bands[i] = bands[i]->getValue(); + } + pp->toneEqualizer.enabled = getEnabled(); + pp->toneEqualizer.regularization = regularization->getValue(); + pp->toneEqualizer.show_colormap = show_colormap->get_active(); + pp->toneEqualizer.pivot = pivot->getValue(); +} + + +void ToneEqualizer::setDefaults(const ProcParams *defParams, const ParamsEdited* pedited) +{ + for (size_t i = 0; i < bands.size(); ++i) { + bands[i]->setDefault(defParams->toneEqualizer.bands[i]); + } + regularization->setDefault(defParams->toneEqualizer.regularization); + + pivot->setDefault(defParams->toneEqualizer.pivot); + inital_params = defParams->toneEqualizer; +} + + +void ToneEqualizer::adjusterChanged(Adjuster *a, double newval) +{ + if (listener && getEnabled()) { + if (a == regularization) { + listener->panelChanged(EvRegularization, Glib::ustring::format(a->getValue())); + } else if (a == pivot) { + listener->panelChanged(EvPivot, Glib::ustring::format(a->getValue())); + } else { + Glib::ustring s; + for (size_t i = 0; i < bands.size(); ++i) { + s += Glib::ustring::format((int)bands[i]->getValue()) + " "; + } + listener->panelChanged(EvBands, s); + } + } +} + + +void ToneEqualizer::adjusterAutoToggled(Adjuster *a) +{ +} + + +void ToneEqualizer::enabledChanged() +{ + if (listener) { + if (get_inconsistent()) { + listener->panelChanged(EvEnabled, M("GENERAL_UNCHANGED")); + } else if (getEnabled()) { + listener->panelChanged(EvEnabled, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(EvEnabled, M("GENERAL_DISABLED")); + } + } +} + + +void ToneEqualizer::colormapToggled() +{ + for (size_t i = 0; i < bands.size(); ++i) { + bands[i]->showIcons(show_colormap->get_active()); + } + if (listener && getEnabled()) { + listener->panelChanged(EvColormap, show_colormap->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + + +void ToneEqualizer::trimValues(rtengine::procparams::ProcParams *pp) +{ + for (size_t i = 0; i < bands.size(); ++i) { + bands[i]->trimValue(pp->toneEqualizer.bands[i]); + } + regularization->trimValue(pp->toneEqualizer.regularization); + pivot->trimValue(pp->toneEqualizer.pivot); +} + diff --git a/rtgui/toneequalizer.h b/rtgui/toneequalizer.h new file mode 100644 index 000000000..f4fed79af --- /dev/null +++ b/rtgui/toneequalizer.h @@ -0,0 +1,56 @@ +/* -*- C++ -*- + * + * Adapted from ART. + * + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * 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 +#include "adjuster.h" +#include "toolpanel.h" + +class ToneEqualizer: public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { +public: + ToneEqualizer(); + + void read(const rtengine::procparams::ProcParams *pp, const ParamsEdited* pedited = nullptr) override; + void write(rtengine::procparams::ProcParams *pp, ParamsEdited* pedited = nullptr) override; + void setDefaults(const rtengine::procparams::ProcParams *defParams, const ParamsEdited* pedited = nullptr) override; + void adjusterChanged(Adjuster *a, double newval) override; + void adjusterAutoToggled(Adjuster *a) override; + void enabledChanged() override; + + void trimValues(rtengine::procparams::ProcParams *pp) override; + +private: + void colormapToggled(); + + std::array bands; + Adjuster *regularization; + Adjuster *pivot; + Gtk::CheckButton *show_colormap; + + rtengine::ProcEvent EvEnabled; + rtengine::ProcEvent EvBands; + rtengine::ProcEvent EvRegularization; + rtengine::ProcEvent EvColormap; + rtengine::ProcEvent EvPivot; + + rtengine::procparams::ToneEqualizerParams inital_params; +}; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 2c506710f..b61b059f6 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -47,6 +47,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit coarse = Gtk::manage (new CoarsePanel ()); toneCurve = Gtk::manage (new ToneCurve ()); shadowshighlights = Gtk::manage (new ShadowsHighlights ()); + toneEqualizer = Gtk::manage (new ToneEqualizer ()); impulsedenoise = Gtk::manage (new ImpulseDenoise ()); defringe = Gtk::manage (new Defringe ()); spot = Gtk::manage (new Spot ()); @@ -118,6 +119,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit addfavoritePanel (colorPanel, chmixer); addfavoritePanel (colorPanel, blackwhite); addfavoritePanel (exposurePanel, shadowshighlights); + addfavoritePanel (exposurePanel, toneEqualizer); addfavoritePanel (detailsPanel, spot); addfavoritePanel (detailsPanel, sharpening); addfavoritePanel (detailsPanel, localContrast); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 13686d6e3..3f7afacc6 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -78,6 +78,7 @@ #include "softlight.h" #include "spot.h" #include "tonecurve.h" +#include "toneequalizer.h" #include "toolbar.h" #include "toolpanel.h" #include "vibrance.h" @@ -133,6 +134,7 @@ protected: Crop* crop; ToneCurve* toneCurve; ShadowsHighlights* shadowshighlights; + ToneEqualizer* toneEqualizer; LocalContrast *localContrast; Spot* spot; Defringe* defringe; From 3e2337bfae4ae74e1c1286d916a4f8eb7d6b2e61 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 12 Jun 2022 16:57:40 -0700 Subject: [PATCH 02/14] Add tone equalizer to batch editor --- rtdata/languages/default | 1 + rtengine/procparams.cc | 4 +- rtengine/procparams.h | 1 + rtgui/addsetids.h | 3 ++ rtgui/adjuster.cc | 2 + rtgui/batchtoolpanelcoord.cc | 4 ++ rtgui/paramsedited.cc | 25 +++++++++--- rtgui/paramsedited.h | 3 +- rtgui/preferences.cc | 6 +++ rtgui/toneequalizer.cc | 79 +++++++++++++++++++++++++++++++++--- rtgui/toneequalizer.h | 8 +++- 11 files changed, 119 insertions(+), 17 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 6dd32ef7b..3ec76b494 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -3848,6 +3848,7 @@ TP_TONE_EQUALIZER_BAND_1;Shadows TP_TONE_EQUALIZER_BAND_2;Midtones TP_TONE_EQUALIZER_BAND_3;Highlights TP_TONE_EQUALIZER_BAND_4;Whites +TP_TONE_EQUALIZER_BANDS;Bands TP_TONE_EQUALIZER_DETAIL;Regularization TP_TONE_EQUALIZER_LABEL;Tone Equalizer TP_TONE_EQUALIZER_PIVOT;Pivot (Ev) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 555af6879..edc7d7980 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -6270,7 +6270,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo // Tone equalizer saveToKeyfile(!pedited || pedited->toneEqualizer.enabled, "ToneEqualizer", "Enabled", toneEqualizer.enabled, keyFile); for (size_t i = 0; i < toneEqualizer.bands.size(); ++i) { - saveToKeyfile(!pedited || pedited->toneEqualizer.bands, "ToneEqualizer", "Band" + std::to_string(i), toneEqualizer.bands[i], keyFile); + saveToKeyfile(!pedited || pedited->toneEqualizer.bands[i], "ToneEqualizer", "Band" + std::to_string(i), toneEqualizer.bands[i], keyFile); } saveToKeyfile(!pedited || pedited->toneEqualizer.regularization, "ToneEqualizer", "Regularization", toneEqualizer.regularization, keyFile); saveToKeyfile(!pedited || pedited->toneEqualizer.pivot, "ToneEqualizer", "Pivot", toneEqualizer.pivot, keyFile); @@ -8263,7 +8263,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("ToneEqualizer")) { assignFromKeyfile(keyFile, "ToneEqualizer", "Enabled", pedited, toneEqualizer.enabled, pedited->toneEqualizer.enabled); for (size_t i = 0; i < toneEqualizer.bands.size(); ++i) { - assignFromKeyfile(keyFile, "ToneEqualizer", "Band" + std::to_string(i), pedited, toneEqualizer.bands[i], pedited->toneEqualizer.bands); + assignFromKeyfile(keyFile, "ToneEqualizer", "Band" + std::to_string(i), pedited, toneEqualizer.bands[i], pedited->toneEqualizer.bands[i]); } assignFromKeyfile(keyFile, "ToneEqualizer", "Regularization", pedited, toneEqualizer.regularization, pedited->toneEqualizer.regularization); assignFromKeyfile(keyFile, "ToneEqualizer", "Pivot", pedited, toneEqualizer.pivot, pedited->toneEqualizer.pivot); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 5a86b40a0..ddee7cbf3 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -18,6 +18,7 @@ */ #pragma once +#include #include #include #include diff --git a/rtgui/addsetids.h b/rtgui/addsetids.h index 6f68c6ae7..8a2ae0466 100644 --- a/rtgui/addsetids.h +++ b/rtgui/addsetids.h @@ -10,6 +10,9 @@ enum { ADDSET_SH_HIGHLIGHTS, ADDSET_SH_SHADOWS, ADDSET_SH_LOCALCONTRAST, // not used anymore + ADDSET_TONE_EQUALIZER_BANDS, + ADDSET_TONE_EQUALIZER_PIVOT, + ADDSET_TONE_EQUALIZER_REGULARIZATION, ADDSET_LC_BRIGHTNESS, ADDSET_LC_CONTRAST, ADDSET_SHARP_AMOUNT, diff --git a/rtgui/adjuster.cc b/rtgui/adjuster.cc index 3fe3d61eb..c9382832d 100644 --- a/rtgui/adjuster.cc +++ b/rtgui/adjuster.cc @@ -689,8 +689,10 @@ void Adjuster::showIcons(bool yes) { if (imageIcon1) { imageIcon1->set_visible(yes); + imageIcon1->set_no_show_all(!yes); } if (imageIcon2) { imageIcon2->set_visible(yes); + imageIcon2->set_no_show_all(!yes); } } diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 9e74ddb90..82f47b619 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -219,6 +219,7 @@ void BatchToolPanelCoordinator::initSession () chmixer->setAdjusterBehavior (options.baBehav[ADDSET_CHMIXER] ); blackwhite->setAdjusterBehavior (options.baBehav[ADDSET_BLACKWHITE_HUES], options.baBehav[ADDSET_BLACKWHITE_GAMMA]); shadowshighlights->setAdjusterBehavior (options.baBehav[ADDSET_SH_HIGHLIGHTS], options.baBehav[ADDSET_SH_SHADOWS]); + toneEqualizer->setAdjusterBehavior(options.baBehav[ADDSET_TONE_EQUALIZER_BANDS], options.baBehav[ADDSET_TONE_EQUALIZER_REGULARIZATION], options.baBehav[ADDSET_TONE_EQUALIZER_PIVOT]); dirpyrequalizer->setAdjusterBehavior (options.baBehav[ADDSET_DIRPYREQ], options.baBehav[ADDSET_DIRPYREQ_THRESHOLD], options.baBehav[ADDSET_DIRPYREQ_SKINPROTECT]); wavelet->setAdjusterBehavior (options.baBehav[ADDSET_WA], options.baBehav[ADDSET_WA_THRESHOLD], options.baBehav[ADDSET_WA_THRESHOLD2], options.baBehav[ADDSET_WA_THRES], options.baBehav[ADDSET_WA_CHRO], options.baBehav[ADDSET_WA_CHROMA], options.baBehav[ADDSET_WA_CONTRAST], options.baBehav[ADDSET_WA_SKINPROTECT], options.baBehav[ADDSET_WA_RESCHRO], options.baBehav[ADDSET_WA_TMRS], options.baBehav[ADDSET_WA_EDGS], options.baBehav[ADDSET_WA_SCALE], options.baBehav[ADDSET_WA_RESCON], options.baBehav[ADDSET_WA_RESCONH], options.baBehav[ADDSET_WA_THRR], options.baBehav[ADDSET_WA_THRRH], options.baBehav[ADDSET_WA_RADIUS], options.baBehav[ADDSET_WA_SKYPROTECT], options.baBehav[ADDSET_WA_EDGRAD], options.baBehav[ADDSET_WA_EDGVAL], options.baBehav[ADDSET_WA_STRENGTH], options.baBehav[ADDSET_WA_GAMMA], options.baBehav[ADDSET_WA_EDGEDETECT], options.baBehav[ADDSET_WA_EDGEDETECTTHR], options.baBehav[ADDSET_WA_EDGEDETECTTHR2]); dirpyrdenoise->setAdjusterBehavior (options.baBehav[ADDSET_DIRPYRDN_LUMA], options.baBehav[ADDSET_DIRPYRDN_LUMDET], options.baBehav[ADDSET_DIRPYRDN_CHROMA], options.baBehav[ADDSET_DIRPYRDN_CHROMARED], options.baBehav[ADDSET_DIRPYRDN_CHROMABLUE], options.baBehav[ADDSET_DIRPYRDN_GAMMA], options.baBehav[ADDSET_DIRPYRDN_PASSES]); @@ -242,6 +243,9 @@ void BatchToolPanelCoordinator::initSession () if (options.baBehav[ADDSET_TC_SATURATION]) { pparams.toneCurve.saturation = 0;} if (options.baBehav[ADDSET_SH_HIGHLIGHTS]) { pparams.sh.highlights = 0; } if (options.baBehav[ADDSET_SH_SHADOWS]) { pparams.sh.shadows = 0; } + if (options.baBehav[ADDSET_TONE_EQUALIZER_BANDS]) { pparams.toneEqualizer.bands = {}; } + if (options.baBehav[ADDSET_TONE_EQUALIZER_PIVOT]) { pparams.toneEqualizer.pivot = 0; } + if (options.baBehav[ADDSET_TONE_EQUALIZER_REGULARIZATION]) { pparams.toneEqualizer.regularization = 0; } if (options.baBehav[ADDSET_LC_BRIGHTNESS]) { pparams.labCurve.brightness = 0; } if (options.baBehav[ADDSET_LC_CONTRAST]) { pparams.labCurve.contrast = 0; } if (options.baBehav[ADDSET_LC_CHROMATICITY]) { pparams.labCurve.chromaticity = 0; } diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index ff48a58b1..598e15673 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -318,7 +318,7 @@ void ParamsEdited::set(bool v) sh.radius = v; sh.lab = v; toneEqualizer.enabled = v; - toneEqualizer.bands = v; + toneEqualizer.bands.fill(v); toneEqualizer.regularization = v; toneEqualizer.show_colormap = v; toneEqualizer.pivot = v; @@ -1037,7 +1037,9 @@ void ParamsEdited::initFrom(const std::vector& crop.orientation = crop.orientation && p.crop.orientation == other.crop.orientation; crop.guide = crop.guide && p.crop.guide == other.crop.guide; toneEqualizer.enabled = toneEqualizer.enabled && p.toneEqualizer.enabled == other.toneEqualizer.enabled; - toneEqualizer.bands = toneEqualizer.bands && p.toneEqualizer.bands == other.toneEqualizer.bands; + for (size_t i = 0; i < toneEqualizer.bands.size(); ++i) { + toneEqualizer.bands[i] = toneEqualizer.bands[i] && p.toneEqualizer.bands[i] == other.toneEqualizer.bands[i]; + } toneEqualizer.regularization = toneEqualizer.regularization && p.toneEqualizer.regularization == other.toneEqualizer.regularization; toneEqualizer.show_colormap = toneEqualizer.show_colormap && p.toneEqualizer.show_colormap == other.toneEqualizer.show_colormap; toneEqualizer.pivot = toneEqualizer.pivot && p.toneEqualizer.pivot == other.toneEqualizer.pivot; @@ -3208,12 +3210,20 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.toneEqualizer.enabled = mods.toneEqualizer.enabled; } - if (toneEqualizer.bands) { - toEdit.toneEqualizer.bands = mods.toneEqualizer.bands; + for (size_t i = 0; i < toneEqualizer.bands.size(); ++i) { + if (toneEqualizer.bands[i]) { + toEdit.toneEqualizer.bands[i] = + dontforceSet && options.baBehav[ADDSET_TONE_EQUALIZER_BANDS] + ? toEdit.toneEqualizer.bands[i] + mods.toneEqualizer.bands[i] + : mods.toneEqualizer.bands[i]; + } } if (toneEqualizer.regularization) { - toEdit.toneEqualizer.regularization = mods.toneEqualizer.regularization; + toEdit.toneEqualizer.regularization = + dontforceSet && options.baBehav[ADDSET_TONE_EQUALIZER_REGULARIZATION] + ? toEdit.toneEqualizer.regularization + mods.toneEqualizer.regularization + : mods.toneEqualizer.regularization; } if (toneEqualizer.show_colormap) { @@ -3221,7 +3231,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng } if (toneEqualizer.pivot) { - toEdit.toneEqualizer.pivot = mods.toneEqualizer.pivot; + toEdit.toneEqualizer.pivot = + dontforceSet && options.baBehav[ADDSET_TONE_EQUALIZER_PIVOT] + ? toEdit.toneEqualizer.pivot + mods.toneEqualizer.pivot + : mods.toneEqualizer.pivot; } if (crop.enabled) { diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index d70336a54..f34eba69b 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -18,6 +18,7 @@ */ #pragma once +#include #include namespace rtengine @@ -360,7 +361,7 @@ struct SHParamsEdited { struct ToneEqualizerParamsEdited { bool enabled; - bool bands; + std::array bands; bool regularization; bool show_colormap; bool pivot; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index c6c2eb61b..2df816b44 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -227,6 +227,12 @@ Gtk::Widget* Preferences::getBatchProcPanel() appendBehavList(mi, M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), ADDSET_SH_HIGHLIGHTS, false); appendBehavList(mi, M("TP_SHADOWSHLIGHTS_SHADOWS"), ADDSET_SH_SHADOWS, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_TONE_EQUALIZER_LABEL")); + appendBehavList(mi, M("TP_TONE_EQUALIZER_BANDS"), ADDSET_TONE_EQUALIZER_BANDS, false); + appendBehavList(mi, M("TP_TONE_EQUALIZER_PIVOT"), ADDSET_TONE_EQUALIZER_PIVOT, false); + appendBehavList(mi, M("TP_TONE_EQUALIZER_DETAIL"), ADDSET_TONE_EQUALIZER_REGULARIZATION, false); + mi = behModel->append(); mi->set_value(behavColumns.label, M("TP_LABCURVE_LABEL")); appendBehavList(mi, M("TP_LABCURVE_BRIGHTNESS"), ADDSET_LC_BRIGHTNESS, false); diff --git a/rtgui/toneequalizer.cc b/rtgui/toneequalizer.cc index 366376ea4..27d35d514 100644 --- a/rtgui/toneequalizer.cc +++ b/rtgui/toneequalizer.cc @@ -59,9 +59,9 @@ ToneEqualizer::ToneEqualizer(): FoldableToolPanel(this, "toneequalizer", M("TP_T regularization->setAdjusterListener(this); pack_start(*regularization); - show_colormap = Gtk::manage(new Gtk::CheckButton(M("TP_TONE_EQUALIZER_SHOW_COLOR_MAP"))); + show_colormap = Gtk::manage(new CheckBox(M("TP_TONE_EQUALIZER_SHOW_COLOR_MAP"), multiImage)); pack_start(*show_colormap); - show_colormap->signal_toggled().connect(sigc::mem_fun(this, &ToneEqualizer::colormapToggled)); + show_colormap->setCheckBoxListener(this); show_all_children (); } @@ -71,6 +71,16 @@ void ToneEqualizer::read(const ProcParams *pp, const ParamsEdited* pedited) { disableListener(); + if (pedited) { + set_inconsistent(multiImage && !pedited->toneEqualizer.enabled); + for (size_t i = 0; i < bands.size(); ++i) { + bands[i]->setEditedState(pedited->toneEqualizer.bands[i] ? Edited : UnEdited); + } + regularization->setEditedState(pedited->toneEqualizer.regularization ? Edited : UnEdited); + pivot->setEditedState(pedited->toneEqualizer.pivot ? Edited : UnEdited); + show_colormap->setEdited(pedited->toneEqualizer.show_colormap ? Edited : UnEdited); + } + setEnabled(pp->toneEqualizer.enabled); for (size_t i = 0; i < bands.size(); ++i) { @@ -80,7 +90,7 @@ void ToneEqualizer::read(const ProcParams *pp, const ParamsEdited* pedited) regularization->setValue(pp->toneEqualizer.regularization); pivot->setValue(pp->toneEqualizer.pivot); - show_colormap->set_active(pp->toneEqualizer.show_colormap); + show_colormap->setValue(pp->toneEqualizer.show_colormap); enableListener(); } @@ -93,8 +103,19 @@ void ToneEqualizer::write(ProcParams *pp, ParamsEdited* pedited) } pp->toneEqualizer.enabled = getEnabled(); pp->toneEqualizer.regularization = regularization->getValue(); - pp->toneEqualizer.show_colormap = show_colormap->get_active(); + pp->toneEqualizer.show_colormap = show_colormap->getLastActive(); pp->toneEqualizer.pivot = pivot->getValue(); + + if (pedited) { + auto &edited = pedited->toneEqualizer; + edited.enabled = !get_inconsistent(); + for (size_t i = 0; i < bands.size(); ++i) { + edited.bands[i] = bands[i]->getEditedState(); + } + edited.regularization = regularization->getEditedState(); + edited.pivot = pivot->getEditedState(); + edited.show_colormap = show_colormap->getEdited(); + } } @@ -107,6 +128,21 @@ void ToneEqualizer::setDefaults(const ProcParams *defParams, const ParamsEdited* pivot->setDefault(defParams->toneEqualizer.pivot); inital_params = defParams->toneEqualizer; + + if (pedited) { + auto &edited = pedited->toneEqualizer; + for (size_t i = 0; i < bands.size(); ++i) { + bands[i]->setDefaultEditedState(edited.bands[i] ? Edited : UnEdited); + } + regularization->setDefaultEditedState(edited.regularization ? Edited : UnEdited); + pivot->setDefaultEditedState(edited.pivot ? Edited : UnEdited); + } else { + for (auto band : bands) { + band->setDefaultEditedState(Irrelevant); + } + regularization->setDefaultEditedState(Irrelevant); + pivot->setDefaultEditedState(Irrelevant); + } } @@ -147,13 +183,44 @@ void ToneEqualizer::enabledChanged() } +void ToneEqualizer::setBatchMode(bool batchMode) +{ + ToolPanel::setBatchMode(batchMode); + if (batchMode) { + for (auto band : bands) { + band->showEditedCB(); + } + regularization->showEditedCB(); + pivot->showEditedCB(); + } +} + + +void ToneEqualizer::setAdjusterBehavior(bool bands_add, bool regularization_add, bool pivot_add) +{ + for (auto band : bands) { + band->setAddMode(bands_add); + } + regularization->setAddMode(regularization_add); + pivot->setAddMode(pivot_add); +} + + +void ToneEqualizer::checkBoxToggled(CheckBox *c, CheckValue newval) +{ + if (c == show_colormap) { + colormapToggled(); + } +} + + void ToneEqualizer::colormapToggled() { for (size_t i = 0; i < bands.size(); ++i) { - bands[i]->showIcons(show_colormap->get_active()); + bands[i]->showIcons(show_colormap->getLastActive()); } if (listener && getEnabled()) { - listener->panelChanged(EvColormap, show_colormap->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + listener->panelChanged(EvColormap, show_colormap->getLastActive() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } diff --git a/rtgui/toneequalizer.h b/rtgui/toneequalizer.h index f4fed79af..657167f05 100644 --- a/rtgui/toneequalizer.h +++ b/rtgui/toneequalizer.h @@ -23,9 +23,10 @@ #include #include "adjuster.h" +#include "checkbox.h" #include "toolpanel.h" -class ToneEqualizer: public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { +class ToneEqualizer: public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public CheckBoxListener { public: ToneEqualizer(); @@ -35,6 +36,9 @@ public: void adjusterChanged(Adjuster *a, double newval) override; void adjusterAutoToggled(Adjuster *a) override; void enabledChanged() override; + void setBatchMode(bool batchMode) override; + void setAdjusterBehavior(bool bands_add, bool regularization_add, bool pivot_add); + void checkBoxToggled(CheckBox* c, CheckValue newval) override; void trimValues(rtengine::procparams::ProcParams *pp) override; @@ -44,7 +48,7 @@ private: std::array bands; Adjuster *regularization; Adjuster *pivot; - Gtk::CheckButton *show_colormap; + CheckBox *show_colormap; rtengine::ProcEvent EvEnabled; rtengine::ProcEvent EvBands; From c4ea272d6580a7dc50cfda7bd1d4260c8f2af11c Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 26 Jun 2022 15:14:05 -0700 Subject: [PATCH 03/14] Fix tone equalizer causing double LA application Change the tone equalizer event refresh type to force correct computation of local of local adjustments of local adjustments. Idea from from https://github.com/Beep6581/RawTherapee/issues/6069#issuecomment-765263602. --- rtgui/toneequalizer.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rtgui/toneequalizer.cc b/rtgui/toneequalizer.cc index 27d35d514..fd60d4936 100644 --- a/rtgui/toneequalizer.cc +++ b/rtgui/toneequalizer.cc @@ -29,11 +29,11 @@ using namespace rtengine::procparams; ToneEqualizer::ToneEqualizer(): FoldableToolPanel(this, "toneequalizer", M("TP_TONE_EQUALIZER_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); - EvEnabled = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_ENABLED"); - EvBands = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_BANDS"); - EvRegularization = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_REGULARIZATION"); - EvColormap = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_SHOW_COLOR_MAP"); - EvPivot = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_PIVOT"); + EvEnabled = m->newEvent(AUTOEXP, "HISTORY_MSG_TONE_EQUALIZER_ENABLED"); + EvBands = m->newEvent(AUTOEXP, "HISTORY_MSG_TONE_EQUALIZER_BANDS"); + EvRegularization = m->newEvent(AUTOEXP, "HISTORY_MSG_TONE_EQUALIZER_REGULARIZATION"); + EvColormap = m->newEvent(AUTOEXP, "HISTORY_MSG_TONE_EQUALIZER_SHOW_COLOR_MAP"); + EvPivot = m->newEvent(AUTOEXP, "HISTORY_MSG_TONE_EQUALIZER_PIVOT"); std::array images = { "purple", From a877ac4878cba816e1e378244775d2ea7321412e Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 26 Jun 2022 16:06:34 -0700 Subject: [PATCH 04/14] Add pivot to local adjustments tone equalizer --- rtdata/languages/default | 2 ++ rtengine/improcfun.h | 4 +-- rtengine/iplocallab.cc | 22 +++++------- rtengine/iptoneequalizer.cc | 67 ++++++++++++++++++++----------------- rtengine/procparams.cc | 4 +++ rtengine/procparams.h | 1 + rtgui/locallabtools.cc | 18 +++++++++- rtgui/locallabtools.h | 3 ++ rtgui/paramsedited.cc | 7 ++++ rtgui/paramsedited.h | 1 + 10 files changed, 82 insertions(+), 47 deletions(-) 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; From efc350228ee943a5c1c48c4c8c868ddf1bb81ac3 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 26 Jun 2022 18:37:28 -0700 Subject: [PATCH 05/14] Fix tone equalizer colormap brightness Don't apply pivot to the colormap itself. --- rtengine/iptoneequalizer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/iptoneequalizer.cc b/rtengine/iptoneequalizer.cc index a661d6b41..481d14114 100644 --- a/rtengine/iptoneequalizer.cc +++ b/rtengine/iptoneequalizer.cc @@ -358,7 +358,7 @@ void ImProcFunctions::toneEqualizer( ::toneEqualizer(R, G, B, params, workingProfile, scale, multiThread); - rgb->multiply(1.f/gain, multiThread); + rgb->multiply(params.show_colormap ? 65535.f : 1.f/gain, multiThread); } void ImProcFunctions::toneEqualizer(Imagefloat *rgb) From 38d85581df13108ae8647cb58eca3260bb14da08 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Thu, 30 Jun 2022 21:19:30 -0700 Subject: [PATCH 06/14] Fix tone equalizer darkening of extreme luminances Extend the extreme bands' contributions all the way to -infinity and +infinity EVs. --- rtengine/iptoneequalizer.cc | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/rtengine/iptoneequalizer.cc b/rtengine/iptoneequalizer.cc index 481d14114..7fb6c791f 100644 --- a/rtengine/iptoneequalizer.cc +++ b/rtengine/iptoneequalizer.cc @@ -15,13 +15,13 @@ const std::vector> colormap = { {0.5f, 0.f, 0.5f}, {0.5f, 0.f, 0.5f}, {0.5f, 0.f, 0.5f}, - {0.5f, 0.f, 0.5f}, {0.5f, 0.f, 0.5f}, // blacks {0.f, 0.f, 1.f}, // shadows {0.5f, 0.5f, 0.5f}, // midtones {1.f, 1.f, 0.f}, // highlights {1.f, 0.f, 0.f}, // whites {1.f, 0.f, 0.f}, + {1.f, 0.f, 0.f}, {1.f, 0.f, 0.f} }; @@ -73,8 +73,8 @@ void toneEqualizer( // Build the luma channels: band-pass filters with gaussian windows of // std 2 EV, spaced by 2 EV const float centers[12] = { - -18.0f, -16.0f, -14.0f, -12.0f, -10.0f, -8.0f, -6.0f, - -4.0f, -2.0f, 0.0f, 2.0f, 4.0f + -16.0f, -14.0f, -12.0f, -10.0f, -8.0f, -6.0f, + -4.0f, -2.0f, 0.0f, 2.0f, 4.0f, 6.0f }; const auto conv = [&](int v, float lo, float hi) -> float { @@ -82,7 +82,6 @@ void toneEqualizer( return exp2(float(v) / 100.f * f); }; const float factors[12] = { - conv(params.bands[0], 2.f, 3.f), // -18 EV conv(params.bands[0], 2.f, 3.f), // -16 EV conv(params.bands[0], 2.f, 3.f), // -14 EV conv(params.bands[0], 2.f, 3.f), // -12 EV @@ -93,7 +92,8 @@ void toneEqualizer( conv(params.bands[3], 3.f, 2.f), // -2 EV conv(params.bands[4], 3.f, 2.f), // 0 EV conv(params.bands[4], 3.f, 2.f), // 2 EV - conv(params.bands[4], 3.f, 2.f) // 4 EV + conv(params.bands[4], 3.f, 2.f), // 4 EV + conv(params.bands[4], 3.f, 2.f) // 6 EV }; rtengine::TMatrix ws = rtengine::ICCStore::getInstance()->workingSpaceMatrix(workingProfile); @@ -149,10 +149,13 @@ void toneEqualizer( w_sum += gauss(centers[i], 0.f); } + constexpr float luma_lo = -14.f; + constexpr float luma_hi = 4.f; + const auto process_pixel = [&](float y) -> float { // convert to log space - const float luma = rtengine::max(log2(rtengine::max(y, 0.f)), -18.0f); + const float luma = rtengine::LIM(log2(rtengine::max(y, 0.f)), luma_lo, luma_hi); // build the correction as the sum of the contribution of each // luminance channel to current pixel @@ -191,7 +194,7 @@ void toneEqualizer( std::array ret = { 0.f, 0.f, 0.f }; // convert to log space - const float luma = rtengine::max(log2(rtengine::max(y, 0.f)), -18.0f); + const float luma = rtengine::LIM(log2(rtengine::max(y, 0.f)), luma_lo, luma_hi); // build the correction as the sum of the contribution of each // luminance channel to current pixel @@ -227,12 +230,13 @@ void toneEqualizer( vfloat zerov = F2V(0.f); vfloat vw_sum = F2V(w_sum); - const vfloat noisev = F2V(-18.f); + const vfloat vluma_lo = F2V(luma_lo); + const vfloat vluma_hi = F2V(luma_hi); const vfloat xlog2v = F2V(xlogf(2.f)); const auto vprocess_pixel = [&](vfloat y) -> vfloat { - const vfloat luma = vmaxf(xlogf(vmaxf(y, zerov)) / xlog2v, noisev); + const vfloat luma = vminf(vmaxf(xlogf(vmaxf(y, zerov)) / xlog2v, vluma_lo), vluma_hi); vfloat correction = zerov; From a13c8a5a474aad3140c997dac0d011bda9147f98 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Thu, 30 Jun 2022 21:58:10 -0700 Subject: [PATCH 07/14] Make default tone eq. regularization consistent Use 0 for the initial and reset value, which is the same as the details in the local adjustments version. --- rtengine/procparams.cc | 2 +- rtgui/toneequalizer.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 52d6be8dd..361ee847c 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -1789,7 +1789,7 @@ bool SHParams::operator !=(const SHParams& other) const ToneEqualizerParams::ToneEqualizerParams() : enabled(false), bands{0, 0, 0, 0, 0}, - regularization(4), + regularization(0), show_colormap(false), pivot(0) { diff --git a/rtgui/toneequalizer.cc b/rtgui/toneequalizer.cc index fd60d4936..de748c2b7 100644 --- a/rtgui/toneequalizer.cc +++ b/rtgui/toneequalizer.cc @@ -55,7 +55,7 @@ ToneEqualizer::ToneEqualizer(): FoldableToolPanel(this, "toneequalizer", M("TP_T pack_start(*pivot); pack_start(*Gtk::manage(new Gtk::HSeparator())); - regularization = Gtk::manage(new Adjuster(M("TP_TONE_EQUALIZER_DETAIL"), -5, 5, 1, 5)); + regularization = Gtk::manage(new Adjuster(M("TP_TONE_EQUALIZER_DETAIL"), -5, 5, 1, 0)); regularization->setAdjusterListener(this); pack_start(*regularization); From 12ef477a6d6e150d513161b634661fdb688764f3 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 6 Feb 2023 21:44:57 -0800 Subject: [PATCH 08/14] Fix merge issues Adapt tone equalizer to favorites tab changes. --- rtgui/toneequalizer.cc | 3 ++- rtgui/toneequalizer.h | 2 ++ rtgui/toollocationpref.cc | 2 ++ rtgui/toolpanelcoord.cc | 7 +++++++ rtgui/toolpanelcoord.h | 1 + 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/rtgui/toneequalizer.cc b/rtgui/toneequalizer.cc index de748c2b7..d524bdc05 100644 --- a/rtgui/toneequalizer.cc +++ b/rtgui/toneequalizer.cc @@ -25,8 +25,9 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring ToneEqualizer::TOOL_NAME = "toneequalizer"; -ToneEqualizer::ToneEqualizer(): FoldableToolPanel(this, "toneequalizer", M("TP_TONE_EQUALIZER_LABEL"), false, true) +ToneEqualizer::ToneEqualizer(): FoldableToolPanel(this, TOOL_NAME, M("TP_TONE_EQUALIZER_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); EvEnabled = m->newEvent(AUTOEXP, "HISTORY_MSG_TONE_EQUALIZER_ENABLED"); diff --git a/rtgui/toneequalizer.h b/rtgui/toneequalizer.h index 657167f05..88a275799 100644 --- a/rtgui/toneequalizer.h +++ b/rtgui/toneequalizer.h @@ -28,6 +28,8 @@ class ToneEqualizer: public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public CheckBoxListener { public: + static const Glib::ustring TOOL_NAME; + ToneEqualizer(); void read(const rtengine::procparams::ProcParams *pp, const ParamsEdited* pedited = nullptr) override; diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index cf25dbc34..a2e2c9480 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -70,6 +70,8 @@ Glib::ustring getToolTitleKey(Tool tool) return "TP_EXPOSURE_LABEL"; case Tool::SHADOWS_HIGHLIGHTS: return "TP_SHADOWSHLIGHTS_LABEL"; + case Tool::TONE_EQUALIZER: + return "TP_TONE_EQUALIZER_LABEL"; case Tool::IMPULSE_DENOISE: return "TP_IMPULSEDENOISE_LABEL"; case Tool::DEFRINGE_TOOL: diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 0a8a510c7..e9b0ce5cc 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -44,6 +44,9 @@ const std::vector EXPOSURE_PANEL_TOOLS = { { .id = Tool::SHADOWS_HIGHLIGHTS, }, + { + .id = Tool::TONE_EQUALIZER, + }, { .id = Tool::EPD, }, @@ -562,6 +565,8 @@ std::string ToolPanelCoordinator::getToolName(Tool tool) return ToneCurve::TOOL_NAME; case Tool::SHADOWS_HIGHLIGHTS: return ShadowsHighlights::TOOL_NAME; + case Tool::TONE_EQUALIZER: + return ToneEqualizer::TOOL_NAME; case Tool::IMPULSE_DENOISE: return ImpulseDenoise::TOOL_NAME; case Tool::DEFRINGE_TOOL: @@ -1908,6 +1913,8 @@ FoldableToolPanel *ToolPanelCoordinator::getFoldableToolPanel(Tool tool) const return toneCurve; case Tool::SHADOWS_HIGHLIGHTS: return shadowshighlights; + case Tool::TONE_EQUALIZER: + return toneEqualizer; case Tool::IMPULSE_DENOISE: return impulsedenoise; case Tool::DEFRINGE_TOOL: diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index e7338c90b..bc1e1a2d3 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -247,6 +247,7 @@ public: enum class Tool { TONE_CURVE, SHADOWS_HIGHLIGHTS, + TONE_EQUALIZER, IMPULSE_DENOISE, DEFRINGE_TOOL, SPOT, From 9893e02aab0f38ec96abebc1d8d5e94b825eaef3 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 15 Apr 2023 16:53:58 -0700 Subject: [PATCH 09/14] Move tone equalizer after exposure Place it between the shadows curve (black and shadow compression) and DCP tone curve and look table. Moving it after exposure makes it possible to easily adjust the exposure to the ball-park range before applying the tone equalizer. Keeping it before the tone curves allows it to affect the image before clipping occurs. --- rtengine/improcfun.cc | 134 +++++++++++++++++++++++++++++------------- 1 file changed, 92 insertions(+), 42 deletions(-) diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index b417f00ce..19a1907da 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -1979,7 +1979,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer stop.reset(new StopWatch("rgb processing")); } - Imagefloat *tmpImage = nullptr; + const bool split_tiled_parts_1_2 = params->toneEqualizer.enabled; + + std::unique_ptr tmpImage; Imagefloat* editImgFloat = nullptr; PlanarWhateverData* editWhatever = nullptr; @@ -2139,6 +2141,7 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer const float comp = (max(0.0, expcomp) + 1.0) * hlcompr / 100.0; const float shoulder = ((65536.f / max(1.0f, exp_scale)) * (hlcomprthresh / 200.f)) + 0.1f; const float hlrange = 65536.f - shoulder; + const int tone_curve_black = params->toneCurve.black; const bool isProPhoto = (params->icm.workingProfile == "ProPhoto"); // extracting data from 'params' to avoid cache flush (to be confirmed) ToneCurveMode curveMode = params->toneCurve.curveMode; @@ -2247,8 +2250,8 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer } bool hasgammabw = gammabwr != 1.f || gammabwg != 1.f || gammabwb != 1.f; - if (hasColorToning || blackwhite || (params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled)) { - tmpImage = new Imagefloat(working->getWidth(), working->getHeight()); + if (hasColorToning || blackwhite || (params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled) || split_tiled_parts_1_2) { + tmpImage.reset(new Imagefloat(working->getWidth(), working->getHeight())); } // For tonecurve histogram @@ -2263,15 +2266,53 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer // For tonecurve histogram const float lumimulf[3] = {static_cast(lumimul[0]), static_cast(lumimul[1]), static_cast(lumimul[2])}; - std::unique_ptr workimg_copy; - if (params->toneEqualizer.enabled) { - working = working->copy(); - workimg_copy.reset(working); - toneEqualizer(working); - } - #define TS 112 + const auto tiled_part_1 = + [working, + mixchannels, + &hltonecurve, &shtonecurve, + chMixRR, chMixRG, chMixRB, + chMixGR, chMixGG, chMixGB, + chMixBR, chMixBG, chMixBB, + exp_scale, comp, hlrange, tone_curve_black]( + int istart, int jstart, int tH, int tW, + float *rtemp, float *gtemp, float *btemp) { + + for (int i = istart, ti = 0; i < tH; i++, ti++) { + for (int j = jstart, tj = 0; j < tW; j++, tj++) { + rtemp[ti * TS + tj] = working->r(i, j); + gtemp[ti * TS + tj] = working->g(i, j); + btemp[ti * TS + tj] = working->b(i, j); + } + } + + if (mixchannels) { + for (int i = istart, ti = 0; i < tH; i++, ti++) { + for (int j = jstart, tj = 0; j < tW; j++, tj++) { + float r = rtemp[ti * TS + tj]; + float g = gtemp[ti * TS + tj]; + float b = btemp[ti * TS + tj]; + + // if (i==100 & j==100) printf("rgbProc input R= %f G= %f B= %f \n",r,g,b); + float rmix = (r * chMixRR + g * chMixRG + b * chMixRB) / 100.f; + float gmix = (r * chMixGR + g * chMixGG + b * chMixGB) / 100.f; + float bmix = (r * chMixBR + g * chMixBG + b * chMixBB) / 100.f; + + rtemp[ti * TS + tj] = rmix; + gtemp[ti * TS + tj] = gmix; + btemp[ti * TS + tj] = bmix; + } + } + } + + highlightToneCurve(hltonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS, exp_scale, comp, hlrange); + + if (tone_curve_black != 0) { + shadowToneCurve(shtonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS); + } + }; + #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif @@ -2322,6 +2363,41 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer histToneCurveThr.clear(); } + if (split_tiled_parts_1_2) { + +#ifdef _OPENMP + #pragma omp for schedule(dynamic, chunkSize) collapse(2) +#endif + + for (int ii = 0; ii < working->getHeight(); ii += TS) { + for (int jj = 0; jj < working->getWidth(); jj += TS) { + istart = ii; + jstart = jj; + tH = min(ii + TS, working->getHeight()); + tW = min(jj + TS, working->getWidth()); + + + tiled_part_1(istart, jstart, tH, tW, rtemp, gtemp, btemp); + + // Copy tile to image. + for (int i = istart, ti = 0; i < tH; i++, ti++) { + for (int j = jstart, tj = 0; j < tW; j++, tj++) { + tmpImage->r(i, j) = rtemp[ti * TS + tj]; + tmpImage->g(i, j) = gtemp[ti * TS + tj]; + tmpImage->b(i, j) = btemp[ti * TS + tj]; + } + } + } + } + } + +#ifdef _OPENMP + #pragma omp single +#endif + if (params->toneEqualizer.enabled) { + toneEqualizer(tmpImage.get()); + } + #ifdef _OPENMP #pragma omp for schedule(dynamic, chunkSize) collapse(2) #endif @@ -2333,38 +2409,16 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer tH = min(ii + TS, working->getHeight()); tW = min(jj + TS, working->getWidth()); - - for (int i = istart, ti = 0; i < tH; i++, ti++) { - for (int j = jstart, tj = 0; j < tW; j++, tj++) { - rtemp[ti * TS + tj] = working->r(i, j); - gtemp[ti * TS + tj] = working->g(i, j); - btemp[ti * TS + tj] = working->b(i, j); - } - } - - if (mixchannels) { + if (split_tiled_parts_1_2) { for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - float r = rtemp[ti * TS + tj]; - float g = gtemp[ti * TS + tj]; - float b = btemp[ti * TS + tj]; - - //if (i==100 & j==100) printf("rgbProc input R= %f G= %f B= %f \n",r,g,b); - float rmix = (r * chMixRR + g * chMixRG + b * chMixRB) / 100.f; - float gmix = (r * chMixGR + g * chMixGG + b * chMixGB) / 100.f; - float bmix = (r * chMixBR + g * chMixBG + b * chMixBB) / 100.f; - - rtemp[ti * TS + tj] = rmix; - gtemp[ti * TS + tj] = gmix; - btemp[ti * TS + tj] = bmix; + rtemp[ti * TS + tj] = tmpImage->r(i, j); + gtemp[ti * TS + tj] = tmpImage->g(i, j); + btemp[ti * TS + tj] = tmpImage->b(i, j); } } - } - - highlightToneCurve(hltonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS, exp_scale, comp, hlrange); - - if (params->toneCurve.black != 0.0) { - shadowToneCurve(shtonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS); + } else { + tiled_part_1(istart, jstart, tH, tW, rtemp, gtemp, btemp); } if (dcpProf) { @@ -3515,10 +3569,6 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer } - if (tmpImage) { - delete tmpImage; - } - if (hCurveEnabled) { delete hCurve; } From 3ea40d893e2645fa518642ed0c2fdd5eb26b5e34 Mon Sep 17 00:00:00 2001 From: Simon Segerblom Rex Date: Wed, 5 Apr 2023 17:42:14 +0200 Subject: [PATCH 10/14] dcraw.cc: Fix bug for tiff_ifd.new_sub_file_type This was regressed by bd118a4a40cd67f6d2e48db5655bd11d3aac0ff8. --- rtengine/dcraw.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 7a2a5b4d5..8f57800f9 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -6812,17 +6812,17 @@ guess_cfa_pc: linear_table (len); break; case 50713: /* BlackLevelRepeatDim */ - if (tiff_ifd[ifd].new_sub_file_type != 0) continue; + if (tiff_ifd[ifd].new_sub_file_type != 0) break; cblack[4] = get2(); cblack[5] = get2(); if (cblack[4] * cblack[5] > sizeof cblack / sizeof *cblack - 6) cblack[4] = cblack[5] = 1; break; case 61450: - if (tiff_ifd[ifd].new_sub_file_type != 0) continue; + if (tiff_ifd[ifd].new_sub_file_type != 0) break; cblack[4] = cblack[5] = MIN(sqrt(len),64); case 50714: /* BlackLevel */ - if (tiff_ifd[ifd].new_sub_file_type != 0) continue; + if (tiff_ifd[ifd].new_sub_file_type != 0) break; RT_blacklevel_from_constant = ThreeValBool::F; //----------------------------------------------------------------------------- // taken from LibRaw. From bcf9b86dcfc18a15f3f863407f613c9f4f75775e Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 13 May 2023 17:36:22 -0700 Subject: [PATCH 11/14] Add Sony ZV-1 color matrix and black level --- rtengine/camconst.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 936a413e7..393438918 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -3139,6 +3139,12 @@ Camera constants: "dcraw_matrix": [ 6344, -1612, -462, -4863, 12477, 2681, -865, 1786, 6899 ] // DNG }, + { // Quality C + "make_model": "Sony ZV-1", + "dcraw_matrix": [ 8280, -2987, -703, -3531, 11645, 2133, -550, 1542, 5312 ], // DNG v15.2 + "ranges": { "black": 800 } + }, + { // Quality C, No proper color data, beta samples, frame set to official jpeg, "make_model": [ "XIAOYI M1", "YI TECHNOLOGY M1" ], "dcraw_matrix": [ 7158,-1911,-606,-3603,10669,2530,-659,1236,5530 ], // XIAO YI DNG D65 From 68ae17a64082cb520c7ef3a2fc546acd7f9f6a17 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 14 May 2023 12:14:33 -0700 Subject: [PATCH 12/14] Add PDAF pattern for Sony ZV-1 --- rtengine/camconst.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 393438918..352dc26e1 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -3139,10 +3139,13 @@ Camera constants: "dcraw_matrix": [ 6344, -1612, -462, -4863, 12477, 2681, -865, 1786, 6899 ] // DNG }, - { // Quality C + { // Quality A "make_model": "Sony ZV-1", "dcraw_matrix": [ 8280, -2987, -703, -3531, 11645, 2133, -550, 1542, 5312 ], // DNG v15.2 - "ranges": { "black": 800 } + "ranges": { "black": 800 }, // White level from EXIF. + "raw_crop": [ 0, 0, 5496, 3672 ], + "pdaf_pattern": [0, 24, 48, 72, 88, 120], + "pdaf_offset": 17 }, { // Quality C, No proper color data, beta samples, frame set to official jpeg, From a1bbc93538b1a1a8737702b6c79a203fc346e77a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Figui=C3=A8re?= Date: Sun, 21 May 2023 18:25:42 -0400 Subject: [PATCH 13/14] Fix missing explicit include (#6704) * Fix missing explicit include - Also avoid rtgui include * Fix more missing explicit include --- rtengine/alpha.h | 2 +- rtengine/dcrop.cc | 3 +++ rtengine/iccstore.cc | 1 + rtengine/init.cc | 3 ++- rtengine/profilestore.cc | 3 +++ rtengine/profilestore.h | 1 + rtgui/editcallbacks.h | 2 ++ rtgui/options.cc | 4 ++++ 8 files changed, 17 insertions(+), 2 deletions(-) diff --git a/rtengine/alpha.h b/rtengine/alpha.h index 1fe2a7a7c..314dac642 100644 --- a/rtengine/alpha.h +++ b/rtengine/alpha.h @@ -19,7 +19,7 @@ #ifndef _ALPHA_H_ #define _ALPHA_H_ -#include +#include #include #define CHECK_BOUNDS 0 diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 8ddaa5f75..a6a1f1f50 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -18,6 +18,9 @@ * along with RawTherapee. If not, see . */ +#include +#include + #include "cieimage.h" #include "color.h" #include "curves.h" diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 2f443522c..e44243fd3 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ #include +#include #include #include diff --git a/rtengine/init.cc b/rtengine/init.cc index 4ec3f0ec5..0c1bd4f6b 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -17,7 +17,8 @@ * along with RawTherapee. If not, see . */ #include -#include "../rtgui/profilestorecombobox.h" +#include +#include #include "color.h" #include "rtengine.h" #include "iccstore.h" diff --git a/rtengine/profilestore.cc b/rtengine/profilestore.cc index f83ddd385..5cc039187 100644 --- a/rtengine/profilestore.cc +++ b/rtengine/profilestore.cc @@ -17,6 +17,9 @@ * along with RawTherapee. If not, see . */ +#include +#include + #include #include diff --git a/rtengine/profilestore.h b/rtengine/profilestore.h index e8e48c17f..d65c01751 100644 --- a/rtengine/profilestore.h +++ b/rtengine/profilestore.h @@ -18,6 +18,7 @@ */ #pragma once +#include #include #include diff --git a/rtgui/editcallbacks.h b/rtgui/editcallbacks.h index 134ea6477..61d392de5 100644 --- a/rtgui/editcallbacks.h +++ b/rtgui/editcallbacks.h @@ -18,6 +18,8 @@ */ #pragma once +#include + #include "editid.h" #include "cursormanager.h" #include "../rtengine/coord.h" diff --git a/rtgui/options.cc b/rtgui/options.cc index d6c3f7d25..e89fcd647 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -19,7 +19,11 @@ #include "options.h" #include #include +#include +#include #include +#include +#include #include #include #include "multilangmgr.h" From be2d5ce11face17acb3c9f0ab6e9b56ff13d4dae Mon Sep 17 00:00:00 2001 From: Desmis Date: Mon, 5 Jun 2023 06:40:57 +0200 Subject: [PATCH 14/14] Local adjustments - denoise improvments (#6705) * Init improvment LA denoise * First display luma chroma residual noise * Clean code denoise iplocallab.cc * Change windows.yml with old version january 2023 * Clean code - change calculation denoise - GUI * Improve labels tooltip denoise * Clean code * Change tooltip * Set auto denoise - main - chroma auto to 50% when LA denoise is used * Change GUI denoise with expanders * Change labels * Change reference remianing noise in percentage * Change tooltip and labels * Change values in preview remaining noise * Clean comment code - chnage tooltips * Change windows.yml and appimage.yml publish_pre_dev labels * Update windows.yml * Restore windows.yml * Restore windows.yml and clean code * Revert change Noise Reduction link with Local denoise * Revert all changes on Noise-reduction linked with Local adjustments --- .github/workflows/appimage.yml | 2 +- .github/workflows/windows.yml | 2 +- rtdata/languages/default | 14 +- rtengine/FTblockDN.cc | 13 +- rtengine/dcrop.cc | 61 +++-- rtengine/improccoordinator.cc | 14 +- rtengine/improccoordinator.h | 1 + rtengine/improcfun.h | 8 +- rtengine/iplocallab.cc | 471 +++++++++++++-------------------- rtengine/rtengine.h | 12 + rtengine/simpleprocess.cc | 11 +- rtgui/locallab.cc | 35 +++ rtgui/locallab.h | 7 + rtgui/locallabtools.cc | 128 +++++++-- rtgui/locallabtools.h | 13 +- 15 files changed, 445 insertions(+), 347 deletions(-) diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 9ad9a6cbd..6b286b68b 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -11,7 +11,7 @@ on: - dev workflow_dispatch: env: - publish_pre_dev_labels: '[]' + publish_pre_dev_labels: '["Beep6581:ladenoise_improv"]' jobs: build: runs-on: ubuntu-20.04 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 4ab10212c..e01e4bd75 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -11,7 +11,7 @@ on: - dev workflow_dispatch: env: - publish_pre_dev_labels: '[]' + publish_pre_dev_labels: '["Beep6581:ladenoise_improv"]' jobs: build: runs-on: windows-2022 diff --git a/rtdata/languages/default b/rtdata/languages/default index 45471bb5c..4c99d113b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2839,13 +2839,15 @@ TP_LOCALLAB_DENOIMASK;Denoise chroma mask TP_LOCALLAB_DENOIMASK_TOOLTIP;For all tools, allows you to control the chromatic noise level of the mask.\nUseful for better control of chrominance and to avoid artifacts when using the LC(h) curve. TP_LOCALLAB_DENOIQUA_TOOLTIP;Conservative mode preserves low frequency detail. Aggressive mode removes low frequency detail.\nConservative and Aggressive modes use wavelets and DCT and can be used in conjunction with 'Non-local Means – Luminance'. TP_LOCALLAB_DENOITHR_TOOLTIP;Adjusts edge detection to help reduce noise in uniform, low-contrast areas. +TP_LOCALLAB_DENOIWAVCH;Wavelets: Chrominance +TP_LOCALLAB_DENOIWAVLUM;Wavelets: Luminance TP_LOCALLAB_DENOI_EXP;Denoise TP_LOCALLAB_DENOI_TOOLTIP;This module can be used for noise reduction either on its own (at the end of the processing pipeline) or in addition to the Noise Reduction module in the Detail tab (which works at the beginning of the pipeline).\n Scope allows you to differentiate the action based on color (ΔE).\nMinimum RT-spot size: 128x128. TP_LOCALLAB_DEPTH;Depth TP_LOCALLAB_DETAIL;Local contrast TP_LOCALLAB_DETAILFRA;Edge detection - DCT TP_LOCALLAB_DETAILSH;Details -TP_LOCALLAB_DETAILTHR;Luma-chro detail threshold +TP_LOCALLAB_DETAILTHR;Lum/chrom detail threshold TP_LOCALLAB_DIVGR;Gamma TP_LOCALLAB_DUPLSPOTNAME;Copy TP_LOCALLAB_EDGFRA;Edge sharpness @@ -3110,7 +3112,7 @@ TP_LOCALLAB_MASKLCTHRLOW;Dark area luminance threshold TP_LOCALLAB_MASKLCTHRLOW2;Dark area luma threshold TP_LOCALLAB_MASKLCTHRMID;Gray area luma denoise TP_LOCALLAB_MASKLCTHRMIDCH;Gray area chroma denoise -TP_LOCALLAB_MASKLC_TOOLTIP;This allows you to target the denoise based on the image luminance information contained in the L(L) or LC(H) mask (Mask and Modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n 'Dark area luminance threshold'. If 'Reinforce denoise in dark and light areas' > 1 the denoise is progressively increased from 0% at the threshold setting to 100% at the maximum black value (determined by mask).\n 'Light area luminance threshold'. The denoise is progressively decreased from 100% at the threshold setting to 0% at the maximum white value (determined by mask).\n In the area between the two thresholds, the denoise settings are not affected by the mask. +TP_LOCALLAB_MASKLC_TOOLTIP;Used by wavelet luminance.\nThis allows you to target the denoise based on the image luminance information contained in the L(L) or LC(H) mask (Mask and Modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n 'Dark area luminance threshold'. If 'Reinforce denoise in dark and light areas' > 1 the denoise is progressively increased from 0% at the threshold setting to 100% at the maximum black value (determined by mask).\n 'Light area luminance threshold'. The denoise is progressively decreased from 100% at the threshold setting to 0% at the maximum white value (determined by mask).\n In the area between the two thresholds, the denoise settings are not affected by the mask. TP_LOCALLAB_MASKLNOISELOW;Reinforce dark/light areas TP_LOCALLAB_MASKLOWTHRESCB_TOOLTIP;Dark-tone limit below which the CBDL parameters (Luminance only) will be restored progressively to their original values prior to being modified by the CBDL settings.\n You can use certain tools in 'Mask and modifications' to change the gray levels: 'Smooth radius', Gamma and Slope, 'Contrast curve'.\n Use a 'lockable color picker' on the mask to see which areas will be affected. Make sure you set 'Background color mask' = 0 in Settings. TP_LOCALLAB_MASKLOWTHRESC_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the Color and Light settings.\n You can use certain tools in 'Mask and modifications' to change the gray levels: 'Structure mask', 'blur mask', 'Smooth radius', Gamma and Slope, 'Contrast curve', 'Local contrast' (wavelets).\n Use a 'lockable color picker' on the mask to see which areas will be affected. Make sure you set 'Background color mask' = 0 in Settings. @@ -3169,6 +3171,12 @@ TP_LOCALLAB_MERTHR;Difference TP_LOCALLAB_MERTWE;Exclusion TP_LOCALLAB_MERTWO;Subtract TP_LOCALLAB_METHOD_TOOLTIP;'Enhanced + chroma denoise' significantly increases processing times.\nBut reduce artifacts. +TP_LOCALLAB_LCLABELS;Residual noise levels +TP_LOCALLAB_LCLABELS_TOOLTIP;Displays the mean and high-end noise values for the area shown in the Preview Panel (at 100% zoom). The noise values are grouped by wavelet levels 0,1,2,3 and 4,5,6.\nThe displayed values are indicative only and are designed to assist with denoise adjustments. They should not be interpreted as absolute noise levels.\n\n 300: Very noisy\n 100-300: Noisy\n 50-100: Moderatly noisy\n < 50: Low noise\n\nThey allow you to see:\n*The impact of Noise Reduction in the main-menu Detail tab.\n*The influence of Non-local Means, Wavelets and DCT on the luminance noise.\n*The influence of Wavelets and DCT on the chroma noise.\n*The influence of Capture Sharpening and Demosaicing. +TP_LOCALLAB_LUMLABEL;Luma levels 0123: Mean=%1 High=%2 +TP_LOCALLAB_LUM46LABEL;Luma levels 456: Mean=%1 High=%2 +TP_LOCALLAB_CHROLABEL;Chroma levels 0123: Mean=%1 High=%2 +TP_LOCALLAB_CHRO46LABEL;Chroma levels 456: Mean=%1 High=%2 TP_LOCALLAB_MLABEL;Restored data Min=%1 Max=%2 TP_LOCALLAB_MLABEL_TOOLTIP;The values should be close to Min=0 Max=32768 (log mode) but other values are possible.You can adjust 'Clip restored data (gain)' and 'Offset' to normalize.\nRecovers image data without blending. TP_LOCALLAB_MODE_EXPERT;Advanced @@ -3185,7 +3193,7 @@ TP_LOCALLAB_NLDENOISENLPAT_TOOLTIP;Use this slider to adapt the amount of denois TP_LOCALLAB_NLDENOISENLRAD_TOOLTIP;Higher values increase denoise at the expense of processing time. TP_LOCALLAB_NLDENOISE_TOOLTIP;'Detail recovery' acts on a Laplacian transform to target uniform areas rather than areas with detail. TP_LOCALLAB_NLDET;Detail recovery -TP_LOCALLAB_NLFRA;Non-local Means - Luminance +TP_LOCALLAB_NLFRA;Non-local Means: Luminance TP_LOCALLAB_NLFRAME_TOOLTIP;Non-local means denoising takes a mean of all pixels in the image, weighted by how similar they are to the target pixel.\nReduces loss of detail compared with local mean algorithms.\nOnly luminance noise is taken into account. Chrominance noise is best processed using wavelets and Fourier transforms (DCT).\nCan be used in conjunction with 'Luminance denoise by level' or on its own. TP_LOCALLAB_NLGAM;Gamma TP_LOCALLAB_NLLUM;Strength diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 400dea05b..7477c5d08 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -1203,7 +1203,7 @@ BENCHFUN if (!memoryAllocationFailed) { if (kall == 0) { - Noise_residualAB(*adecomp, chresid, chmaxresid, denoiseMethodRgb); + Noise_residualAB(*adecomp, chresid, chmaxresid, denoiseMethodRgb, 0, levwav); chresidtemp = chresid; chmaxresidtemp = chmaxresid; } @@ -1240,12 +1240,13 @@ BENCHFUN if (!memoryAllocationFailed) { if (kall == 0) { - Noise_residualAB(*bdecomp, chresid, chmaxresid, denoiseMethodRgb); + Noise_residualAB(*bdecomp, chresid, chmaxresid, denoiseMethodRgb, 0, levwav); chresid += chresidtemp; chmaxresid += chmaxresidtemp; chresid = sqrt(chresid / (6 * (levwav))); highresi = chresid + 0.66f * (sqrt(chmaxresid) - chresid); //evaluate sigma nresi = chresid; + printf("Nresi=%f Highresi=%f lev=%i\n", (double) nresi, (double) highresi, levwav); } bdecomp->reconstruct(labdn->b[0]); @@ -2158,16 +2159,18 @@ float ImProcFunctions::MadRgb(const float * DataList, const int datalen) -void ImProcFunctions::Noise_residualAB(const wavelet_decomposition &WaveletCoeffs_ab, float &chresid, float &chmaxresid, bool denoiseMethodRgb) +void ImProcFunctions::Noise_residualAB(const wavelet_decomposition &WaveletCoeffs_ab, float &chresid, float &chmaxresid, bool denoiseMethodRgb, int beg, int end) { float resid = 0.f; float maxresid = 0.f; - +// int maxlev = WaveletCoeffs_ab.maxlevel(); + // end = maxlev; #ifdef _OPENMP #pragma omp parallel for schedule(dynamic) collapse(2) reduction(+:resid) reduction(max:maxresid) num_threads(denoiseNestedLevels) if (denoiseNestedLevels>1) #endif - for (int lvl = 0; lvl < WaveletCoeffs_ab.maxlevel(); ++lvl) { + // for (int lvl = 0; lvl < WaveletCoeffs_ab.maxlevel(); ++lvl) { + for (int lvl = beg; lvl < end; ++lvl) { // compute median absolute deviation (MAD) of detail coefficients as robust noise estimator for (int dir = 1; dir < 4; ++dir) { const int Wlvl_ab = WaveletCoeffs_ab.level_W(lvl); diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index a6a1f1f50..bce6f2291 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -600,7 +600,6 @@ void Crop::update(int todo) params.dirpyrDenoise.redchro = maxr; params.dirpyrDenoise.bluechro = maxb; parent->denoiseInfoStore.valid = true; - if (parent->adnListener) { parent->adnListener->chromaChanged(params.dirpyrDenoise.chroma, params.dirpyrDenoise.redchro, params.dirpyrDenoise.bluechro); } @@ -848,7 +847,7 @@ void Crop::update(int todo) if ((todo & (M_AUTOEXP | M_RGBCURVE)) && params.locallab.enabled && !params.locallab.spots.empty()) { - + //I made a little change here. Rather than have luminanceCurve (and others) use in/out lab images, we can do more if we copy right here. parent->ipf.rgb2lab(*baseCrop, *laboCrop, params.icm.workingProfile); @@ -945,16 +944,7 @@ void Crop::update(int todo) auto& locwavCurveden = parent->locwavCurveden; auto& lmasklocal_curve2 = parent->lmasklocal_curve; auto& loclmasCurve_wav = parent->loclmasCurve_wav; -// const int sizespot = (int)params.locallab.spots.size(); -/* float *huerefp = nullptr; - huerefp = new float[sizespot]; - float *chromarefp = nullptr; - chromarefp = new float[sizespot]; - float *lumarefp = nullptr; - lumarefp = new float[sizespot]; - float *fabrefp = nullptr; - fabrefp = new float[sizespot]; -*/ + for (int sp = 0; sp < (int)params.locallab.spots.size(); sp++) { locRETgainCurve.Set(params.locallab.spots.at(sp).localTgaincurve); locRETtransCurve.Set(params.locallab.spots.at(sp).localTtranscurve); @@ -1048,6 +1038,7 @@ void Crop::update(int todo) if (black < 0. && params.locallab.spots.at(sp).expMethod == "pde" ) { black *= 1.5; } + std::vector localldenoiselc; double cont = params.locallab.spots.at(sp).contrast; double huere, chromare, lumare, huerefblu, chromarefblu, lumarefblu, sobelre; @@ -1063,6 +1054,7 @@ void Crop::update(int todo) float stdtme = parent->stdtms[sp]; float meanretie = parent->meanretis[sp]; float stdretie = parent->stdretis[sp]; + float fab = 1.f; float minCD; float maxCD; @@ -1073,7 +1065,14 @@ void Crop::update(int todo) float Tmin; float Tmax; int lastsav; - + float highresi = 0.f; + float nresi = 0.f; + float highresi46 =0.f; + float nresi46 = 0.f; + float Lhighresi = 0.f; + float Lnresi = 0.f; + float Lhighresi46 = 0.f; + float Lnresi46 = 0.f; /* huerefp[sp] = huere; chromarefp[sp] = chromare; lumarefp[sp] = lumare; @@ -1142,9 +1141,20 @@ void Crop::update(int todo) huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, lastsav, parent->previewDeltaE, parent->locallColorMask, parent->locallColorMaskinv, parent->locallExpMask, parent->locallExpMaskinv, parent->locallSHMask, parent->locallSHMaskinv, parent->locallvibMask, parent->localllcMask, parent->locallsharMask, parent->locallcbMask, parent->locallretiMask, parent->locallsoftMask, parent->localltmMask, parent->locallblMask, parent->localllogMask, parent->locall_Mask, parent->locallcieMask, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, - meantme, stdtme, meanretie, stdretie, fab); - // fabrefp[sp] = fab; - + meantme, stdtme, meanretie, stdretie, fab, + highresi, nresi, highresi46, nresi46, Lhighresi, Lnresi, Lhighresi46, Lnresi46); + + LocallabListener::locallabDenoiseLC denoiselc; + denoiselc.highres = highresi; + denoiselc.nres = nresi; + denoiselc.highres46 = highresi46; + denoiselc.nres46 = nresi46; + denoiselc.Lhighres = Lhighresi; + denoiselc.Lnres = Lnresi; + denoiselc.Lhighres46 = Lhighresi46; + denoiselc.Lnres46 = Lnresi46; + localldenoiselc.push_back(denoiselc); + if (parent->previewDeltaE || parent->locallColorMask == 5 || parent->locallvibMask == 4 || parent->locallExpMask == 5 || parent->locallSHMask == 4 || parent->localllcMask == 4 || parent->localltmMask == 4 || parent->localllogMask == 4 || parent->locallsoftMask == 6 || parent->localllcMask == 4 || parent->locallcieMask == 4) { params.blackwhite.enabled = false; params.colorToning.enabled = false; @@ -1174,6 +1184,20 @@ void Crop::update(int todo) } */ + denoiselc.highres = highresi; + denoiselc.nres = nresi; + denoiselc.highres46 = highresi46; + denoiselc.nres46 = nresi46; + denoiselc.Lhighres = Lhighresi; + denoiselc.Lnres = Lnresi; + denoiselc.Lhighres46 = Lhighresi46; + denoiselc.Lnres46 = Lnresi46; + localldenoiselc.push_back(denoiselc); + + + if (parent->locallListener) { + parent->locallListener->denChanged(localldenoiselc, params.locallab.selspot); + } } else { parent->ipf.Lab_Local(1, sp, (float**)shbuffer, labnCrop, labnCrop, reservCrop.get(), savenormtmCrop.get(), savenormretiCrop.get(), lastorigCrop.get(), fw, fh, cropx / skip, cropy / skip, skips(parent->fw, skip), skips(parent->fh, skip), skip, locRETgainCurve, locRETtransCurve, @@ -1229,8 +1253,11 @@ void Crop::update(int todo) LHutili, HHutili, CHutili, HHutilijz, CHutilijz, LHutilijz, cclocalcurve2, localcutili, rgblocalcurve2, localrgbutili, localexutili, exlocalcurve2, hltonecurveloc2, shtonecurveloc2, tonecurveloc2, lightCurveloc2, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, lastsav, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, - meantme, stdtme, meanretie, stdretie, fab); + meantme, stdtme, meanretie, stdretie, fab, + highresi, nresi, highresi46, nresi46, Lhighresi, Lnresi, Lhighresi46, Lnresi46); } + + if (sp + 1u < params.locallab.spots.size()) { // do not copy for last spot as it is not needed anymore lastorigCrop->CopyFrom(labnCrop); diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 664029a5e..2ab6383bf 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1169,7 +1169,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) float stdtm = stdtms[sp] = stdtme; float meanreti = meanretis[sp] = meanretie; float stdreti = stdretis[sp] = stdretie; - huerefp[sp] = huer; chromarefp[sp] = chromar; lumarefp[sp] = lumar; @@ -1203,6 +1202,15 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) float Tmax; int lastsav; + float highresi = 0.f; + float nresi = 0.f; + float highresi46 =0.f; + float nresi46 = 0.f; + float Lhighresi = 0.f; + float Lnresi = 0.f; + float Lhighresi46 = 0.f; + float Lnresi46 = 0.f; + ipf.Lab_Local(3, sp, (float**)shbuffer, nprevl, nprevl, reserv.get(), savenormtm.get(), savenormreti.get(), lastorigimp.get(), fw, fh, 0, 0, pW, pH, scale, locRETgainCurve, locRETtransCurve, lllocalcurve, locallutili, cllocalcurve, localclutili, @@ -1256,7 +1264,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) LHutili, HHutili, CHutili, HHutilijz, CHutilijz, LHutilijz, cclocalcurve, localcutili, rgblocalcurve, localrgbutili, localexutili, exlocalcurve, hltonecurveloc, shtonecurveloc, tonecurveloc, lightCurveloc, huerblu, chromarblu, lumarblu, huer, chromar, lumar, sobeler, lastsav, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, - meantm, stdtm, meanreti, stdreti, fab); + meantm, stdtm, meanreti, stdreti, fab, + highresi, nresi, highresi46, nresi46, Lhighresi, Lnresi, Lhighresi46, Lnresi46); fabrefp[sp] = fab; @@ -1296,7 +1305,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) retiMinMax.Tmin = Tmin; retiMinMax.Tmax = Tmax; locallretiminmax.push_back(retiMinMax); - // Recalculate references after if (params->locallab.spots.at(sp).spotMethod == "exc") { ipf.calc_ref(sp, reserv.get(), reserv.get(), 0, 0, pW, pH, scale, huerefblu, chromarefblu, lumarefblu, huer, chromar, lumar, sobeler, avg, locwavCurveden, locwavdenutili); diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 92cdd91c7..50c14ef9e 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -365,6 +365,7 @@ protected: std::vector stdtms; std::vector meanretis; std::vector stdretis; + bool lastspotdup; bool previewDeltaE; int locallColorMask; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 36c571291..8b05a7bb4 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -360,7 +360,8 @@ enum class BlurType { double& huerefblur, double &chromarefblur, double& lumarefblur, double &hueref, double &chromaref, double &lumaref, double &sobelref, int &lastsav, bool prevDeltaE, int llColorMask, int llColorMaskinv, int llExpMask, int llExpMaskinv, int llSHMask, int llSHMaskinv, int llvibMask, int lllcMask, int llsharMask, int llcbMask, int llretiMask, int llsoftMask, int lltmMask, int llblMask, int lllogMask, int ll_Mask, int llcieMask, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, - float& meantm, float& stdtm, float& meanreti, float& stdreti, float &fab); + float& meantm, float& stdtm, float& meanreti, float& stdreti, float &fab, + float &highresi, float &nresi, float &highresi46, float &nresi46, float &Lhighresi, float &Lnresi, float &Lhighresi46, float &Lnresi46); void addGaNoise(LabImage *lab, LabImage *dst, const float mean, const float variance, const int sk); void BlurNoise_Localold(int call, const struct local_params& lp, LabImage* original, LabImage* transformed, const LabImage* const tmp1, int cx, int cy); @@ -399,7 +400,8 @@ enum class BlurType { void DeNoise_Local(int call, const struct local_params& lp, LabImage* originalmask, int levred, float hueref, float lumaref, float chromaref, LabImage* original, LabImage* transformed, const LabImage &tmp1, int cx, int cy, int sk); void DeNoise_Local2(const struct local_params& lp, LabImage* originalmask, int levred, float hueref, float lumaref, float chromaref, LabImage* original, LabImage* transformed, const LabImage &tmp1, int cx, int cy, int sk); - void DeNoise(int call, float * slidL, float * slida, float * slidb, int aut, bool noiscfactiv, const struct local_params& lp, LabImage* originalmaskbl, LabImage * bufmaskblurbl, int levred, float huerefblur, float lumarefblur, float chromarefblur, LabImage* original, LabImage* transformed, int cx, int cy, int sk, const LocwavCurve& locwavCurvehue, bool locwavhueutili); + void DeNoise(int call, int aut, bool noiscfactiv, const struct local_params& lp, LabImage* originalmaskbl, LabImage * bufmaskblurbl, int levred, float huerefblur, float lumarefblur, float chromarefblur, LabImage* original, LabImage* transformed, + int cx, int cy, int sk, const LocwavCurve& locwavCurvehue, bool locwavhueutili, float& highresi, float& nresi, float& highresi46, float& nresi46, float& Lhighresi, float& Lnresi, float& Lhighresi46, float& Lnresi46); void fftw_denoise(int sk, int GW, int GH, int max_numblox_W, int min_numblox_W, float **tmp1, array2D *Lin, int numThreads, const struct local_params & lp, int chrom); @@ -462,7 +464,7 @@ enum class BlurType { void ShrinkAll_info(const float* const* WavCoeffs_a, const float* const* WavCoeffs_b, int W_ab, int H_ab, float **noisevarlum, float **noisevarchrom, float **noisevarhue, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float &maxblueaut, float &minredaut, float &minblueaut, int schoice, int lvl, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, float &maxchred, float &maxchblue, float &minchred, float &minchblue, int &nb, float &chau, float &chred, float &chblue, bool denoiseMethodRgb); - void Noise_residualAB(const wavelet_decomposition &WaveletCoeffs_ab, float &chresid, float &chmaxresid, bool denoiseMethodRgb); + void Noise_residualAB(const wavelet_decomposition &WaveletCoeffs_ab, float &chresid, float &chmaxresid, bool denoiseMethodRgb, int beg, int end); void calcautodn_info(float &chaut, float &delta, int Nb, int levaut, float maxmax, float lumema, float chromina, int mode, int lissage, float redyel, float skinc, float nsknc); float Mad(const float * DataList, int datalen); float MadRgb(const float * DataList, int datalen); diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index b9e82cc5d..adc762710 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -10872,7 +10872,8 @@ void ImProcFunctions::fftw_denoise(int sk, int GW, int GH, int max_numblox_W, in } -void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * slidb, int aut, bool noiscfactiv, const struct local_params & lp, LabImage * originalmaskbl, LabImage * bufmaskblurbl, int levred, float huerefblur, float lumarefblur, float chromarefblur, LabImage * original, LabImage * transformed, int cx, int cy, int sk, const LocwavCurve& locwavCurvehue, bool locwavhueutili) +void ImProcFunctions::DeNoise(int call, int aut, bool noiscfactiv, const struct local_params & lp, LabImage * originalmaskbl, LabImage * bufmaskblurbl, int levred, float huerefblur, float lumarefblur, float chromarefblur, LabImage * original, LabImage * transformed, + int cx, int cy, int sk, const LocwavCurve& locwavCurvehue, bool locwavhueutili, float& highresi, float& nresi, float& highresi46, float& nresi46, float& Lhighresi, float& Lnresi, float& Lhighresi46, float& Lnresi46) { BENCHFUN //local denoise @@ -10943,7 +10944,6 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl } } - // if (call == 1 && GW >= mDEN && GH >= mDEN) { if (call == 1 && ((GW >= mDEN && GH >= mDEN && isnois) || lp.quamet == 2)) { @@ -10965,6 +10965,9 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl tmp1.a[ir][jr] = original->a[ir][jr]; tmp1.b[ir][jr] = original->b[ir][jr]; } + if(lp.nlstr > 0) { + NLMeans(tmp1.L, lp.nlstr, lp.nldet, lp.nlpat, lp.nlrad, lp.nlgam, GW, GH, float (sk), multiThread); + } float gamma = lp.noisegam; rtengine::GammaValues g_a; //gamma parameters @@ -11003,14 +11006,13 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl if (!Ldecomp.memory_allocation_failed()) { #ifdef _OPENMP - #pragma omp parallel for schedule(dynamic) collapse(2) if (multiThread) + // #pragma omp parallel for schedule(dynamic) collapse(2) if (multiThread) #endif for (int lvl = 0; lvl < levred; lvl++) { for (int dir = 1; dir < 4; dir++) { int Wlvl_L = Ldecomp.level_W(lvl); int Hlvl_L = Ldecomp.level_H(lvl); const float* const* WavCoeffs_L = Ldecomp.level_coeffs(lvl); - madL[lvl][dir - 1] = SQR(Mad(WavCoeffs_L[dir], Wlvl_L * Hlvl_L)); } } @@ -11019,67 +11021,36 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl float mxsl = 0.f; // float mxsfl = 0.f; - if (aut == 0) { - if (levred == 7) { - edge = 2; - vari[0] = 0.8f * SQR((lp.noiself0 / 125.f) * (1.f + lp.noiself0 / 25.f)); - vari[1] = 0.8f * SQR((lp.noiself / 125.f) * (1.f + lp.noiself / 25.f)); - vari[2] = 0.8f * SQR((lp.noiself2 / 125.f) * (1.f + lp.noiself2 / 25.f)); + edge = 2; + vari[0] = 0.8f * SQR((lp.noiself0 / 125.f) * (1.f + lp.noiself0 / 25.f)); + vari[1] = 0.8f * SQR((lp.noiself / 125.f) * (1.f + lp.noiself / 25.f)); + vari[2] = 0.8f * SQR((lp.noiself2 / 125.f) * (1.f + lp.noiself2 / 25.f)); - vari[3] = 0.8f * SQR((lp.noiselc / 125.f) * (1.f + lp.noiselc / 25.f)); - vari[4] = 0.8f * SQR((lp.noiselc4 / 125.f) * (1.f + lp.noiselc4 / 25.f)); - vari[5] = 0.8f * SQR((lp.noiselc5 / 125.f) * (1.f + lp.noiselc5 / 25.f)); - vari[6] = 0.8f * SQR((lp.noiselc6 / 125.f) * (1.f + lp.noiselc6 / 25.f)); - } else if (levred == 4) { - edge = 3; - vari[0] = 0.8f * SQR((lp.noiself0 / 125.f) * (1.f + lp.noiself0 / 25.f)); - vari[1] = 0.8f * SQR((lp.noiself / 125.f) * (1.f + lp.noiself / 25.f)); - vari[2] = 0.8f * SQR((lp.noiselc / 125.f) * (1.f + lp.noiselc / 25.f)); - vari[3] = 0.8f * SQR((lp.noiselc / 125.f) * (1.f + lp.noiselc / 25.f)); - - } - } else if (aut == 1 || aut == 2) { - edge = 2; - vari[0] = SQR(slidL[0]); - vari[1] = SQR(slidL[1]); - vari[2] = SQR(slidL[2]); - vari[3] = SQR(slidL[3]); - vari[4] = SQR(slidL[4]); - vari[5] = SQR(slidL[5]); - vari[6] = SQR(slidL[6]); - float mxslid34 = rtengine::max(slidL[3], slidL[4]); - float mxslid56 = rtengine::max(slidL[5], slidL[6]); - mxsl = rtengine::max(mxslid34, mxslid56); - - } + vari[3] = 0.8f * SQR((lp.noiselc / 125.f) * (1.f + lp.noiselc / 25.f)); + vari[4] = 1.f * SQR((lp.noiselc4 / 125.f) * (1.f + lp.noiselc4 / 25.f)); + vari[5] = 1.5f * SQR((lp.noiselc5 / 125.f) * (1.f + lp.noiselc5 / 25.f)); + vari[6] = 2.5f * SQR((lp.noiselc6 / 125.f) * (1.f + lp.noiselc6 / 25.f)); { float kr3 = 0.f; - if (aut == 0 || aut == 1) { - if ((lp.noiselc < 30.f && aut == 0) || (mxsl < 30.f && aut == 1)) { + if (lp.noiselc < 30.f) { kr3 = 0.f; - } else if ((lp.noiselc < 50.f && aut == 0) || (mxsl < 50.f && aut == 1)) { + } else if (lp.noiselc < 50.f) { kr3 = 0.5f; - } else if ((lp.noiselc < 70.f && aut == 0) || (mxsl < 70.f && aut == 1)) { + } else if (lp.noiselc < 70.f) { kr3 = 0.7f; } else { kr3 = 1.f; } - } else if (aut == 2) { - kr3 = 1.f; - } vari[0] = rtengine::max(0.000001f, vari[0]); vari[1] = rtengine::max(0.000001f, vari[1]); vari[2] = rtengine::max(0.000001f, vari[2]); vari[3] = rtengine::max(0.000001f, kr3 * vari[3]); - - if (levred == 7) { - vari[4] = rtengine::max(0.000001f, vari[4]); - vari[5] = rtengine::max(0.000001f, vari[5]); - vari[6] = rtengine::max(0.000001f, vari[6]); - } + vari[4] = rtengine::max(0.000001f, vari[4]); + vari[5] = rtengine::max(0.000001f, vari[5]); + vari[6] = rtengine::max(0.000001f, vari[6]); float* noisevarlum = new float[GH * GW]; float* noisevarhue = new float[GH * GW]; @@ -11218,75 +11189,25 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl } if (!adecomp.memory_allocation_failed() && !bdecomp.memory_allocation_failed()) { - float maxcfine = 0.f; float maxccoarse = 0.f; - if (aut == 0) { - if (levred == 7) { - edge = 2; - variC[0] = SQR(noisecfr); - variC[1] = SQR(noisecfr); - variC[2] = SQR(noisecfr); + edge = 2; + variC[0] = SQR(noisecfr); + variC[1] = SQR(noisecfr); + variC[2] = SQR(noisecfr); + variC[3] = SQR(1.2f * noisecfr); + variC[4] = SQR(noisecfr); + variC[5] = SQR(1.2f * noiseccr); + variC[6] = SQR(1.5f * noiseccr); - variC[3] = SQR(noisecfr); - variC[4] = SQR(noisecfr); - variC[5] = SQR(noiseccr); - variC[6] = SQR(noiseccr); + variCb[0] = SQR(noisecfb); + variCb[1] = SQR(noisecfb); + variCb[2] = SQR(noisecfb); + variCb[3] = SQR(noisecfb); + variCb[4] = SQR(noisecfb); + variCb[5] = SQR(1.2f * noiseccb); + variCb[6] = SQR(1.5f * noiseccb); - variCb[0] = SQR(noisecfb); - variCb[1] = SQR(noisecfb); - variCb[2] = SQR(noisecfb); - - variCb[3] = SQR(noisecfb); - variCb[4] = SQR(noisecfb); - variCb[5] = SQR(noiseccb); - variCb[6] = SQR(noiseccb); - - } else if (levred == 4) { - edge = 3; - variC[0] = SQR(lp.noisecf / 10.f); - variC[1] = SQR(lp.noisecf / 10.f); - variC[2] = SQR(lp.noisecf / 10.f); - variC[3] = SQR(lp.noisecf / 10.f); - - variCb[0] = SQR(lp.noisecf / 10.f); - variCb[1] = SQR(lp.noisecf / 10.f); - variCb[2] = SQR(lp.noisecf / 10.f); - variCb[3] = SQR(lp.noisecf / 10.f); - - } - } else if (aut == 1 || aut == 2) { - edge = 2; - variC[0] = SQR(slida[0]); - variC[1] = SQR(slida[1]); - variC[2] = SQR(slida[2]); - variC[3] = SQR(slida[3]); - variC[4] = SQR(slida[4]); - variC[5] = SQR(slida[5]); - variC[6] = SQR(slida[6]); - float maxc01 = rtengine::max(slida[0], slida[1]); - float maxc23 = rtengine::max(slida[2], slida[3]); - float max03 = rtengine::max(maxc01, maxc23); - float maxrf = rtengine::max(max03, slida[4]); - float maxrc = rtengine::max(slida[5], slida[6]); - - variCb[0] = SQR(slidb[0]); - variCb[1] = SQR(slidb[1]); - variCb[2] = SQR(slidb[2]); - variCb[3] = SQR(slidb[3]); - variCb[4] = SQR(slidb[4]); - variCb[5] = SQR(slidb[5]); - variCb[6] = SQR(slidb[6]); - float maxb01 = rtengine::max(slidb[0], slidb[1]); - float maxb23 = rtengine::max(slidb[2], slidb[3]); - float maxb03 = rtengine::max(maxb01, maxb23); - float maxbf = rtengine::max(maxb03, slidb[4]); - maxcfine = rtengine::max(maxrf, maxbf); - - float maxbc = rtengine::max(slidb[5], slidb[6]); - maxccoarse = rtengine::max(maxrc, maxbc); - - } { float minic = 0.000001f; @@ -11299,52 +11220,51 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl float k2 = 0.f; float k3 = 0.f; - if (aut == 0 || aut == 1) { - if ((lp.noisecf < 0.2f && aut == 0) || (maxcfine < 0.2f && aut == 1)) { + if (lp.noisecf < 0.2f) { k1 = 0.05f; k2 = 0.f; k3 = 0.f; - } else if ((lp.noisecf < 0.3f && aut == 0) || (maxcfine < 0.3f && aut == 1)) { + } else if (lp.noisecf < 0.3f) { k1 = 0.1f; k2 = 0.0f; k3 = 0.f; - } else if ((lp.noisecf < 0.5f && aut == 0) || (maxcfine < 0.5f && aut == 1)) { + } else if (lp.noisecf < 0.5f) { k1 = 0.2f; k2 = 0.1f; k3 = 0.f; - } else if ((lp.noisecf < 0.8f && aut == 0) || (maxcfine < 0.8f && aut == 1)) { + } else if (lp.noisecf < 0.8f) { k1 = 0.3f; k2 = 0.25f; k3 = 0.f; - } else if ((lp.noisecf < 1.f && aut == 0) || (maxcfine < 1.f && aut == 1)) { + } else if (lp.noisecf < 1.f) { k1 = 0.4f; k2 = 0.25f; k3 = 0.1f; - } else if ((lp.noisecf < 2.f && aut == 0) || (maxcfine < 2.f && aut == 1)) { + } else if (lp.noisecf < 2.f) { k1 = 0.5f; k2 = 0.3f; k3 = 0.15f; - } else if ((lp.noisecf < 3.f && aut == 0) || (maxcfine < 3.f && aut == 1)) { + } else if (lp.noisecf < 3.f) { k1 = 0.6f; k2 = 0.45f; k3 = 0.3f; - } else if ((lp.noisecf < 4.f && aut == 0) || (maxcfine < 4.f && aut == 1)) { + } else if (lp.noisecf < 4.f) { k1 = 0.7f; k2 = 0.5f; k3 = 0.4f; - } else if ((lp.noisecf < 5.f && aut == 0) || (maxcfine < 5.f && aut == 1)) { + } else if (lp.noisecf < 5.f) { k1 = 0.8f; k2 = 0.6f; k3 = 0.5f; - } else if ((lp.noisecf < 6.f && aut == 0) || (maxcfine < 10.f && aut == 1)) { + } else if (lp.noisecf < 6.f) { k1 = 0.85f; k2 = 0.7f; k3 = 0.6f; - } else if ((lp.noisecf < 8.f && aut == 0) || (maxcfine < 20.f && aut == 1)) { + } else if (lp.noisecf < 8.f) { k1 = 0.9f; k2 = 0.8f; k3 = 0.7f; - } else if ((lp.noisecf < 10.f && aut == 0) || (maxcfine < 50.f && aut == 1)) { + } else if (lp.noisecf < 10.f) { k1 = 1.f; k2 = 1.f; k3 = 0.9f; @@ -11352,14 +11272,8 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl } else { k1 = 1.f; k2 = 1.f; - k3 = 1.f; + k3 = 1.5f; } - } else if (aut == 2) { - k1 = 1.f; - k2 = 1.f; - k3 = 1.f; - } - variC[0] = rtengine::max(minic, variC[0]); variC[1] = rtengine::max(minic, k1 * variC[1]); @@ -11371,27 +11285,26 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl variCb[2] = rtengine::max(minic, k2 * variCb[2]); variCb[3] = rtengine::max(minic, k3 * variCb[3]); - if (levred == 7) { float k4 = 0.f; float k5 = 0.f; float k6 = 0.f; - if ((lp.noisecc < 0.2f && aut == 0) || (maxccoarse < 0.2f && aut == 1)) { + if (lp.noisecc < 0.2f) { k4 = 0.1f; k5 = 0.02f; - } else if ((lp.noisecc < 0.5f && aut == 0) || (maxccoarse < 0.5f && aut == 1)) { + } else if (lp.noisecc < 0.5f) { k4 = 0.15f; k5 = 0.05f; - } else if ((lp.noisecc < 1.f && aut == 0) || (maxccoarse < 1.f && aut == 1)) { + } else if (lp.noisecc < 1.f) { k4 = 0.15f; k5 = 0.1f; - } else if ((lp.noisecc < 3.f && aut == 0) || (maxccoarse < 3.f && aut == 1)) { + } else if (lp.noisecc < 3.f) { k4 = 0.3f; k5 = 0.15f; - } else if ((lp.noisecc < 4.f && aut == 0) || (maxccoarse < 5.f && aut == 1)) { + } else if (lp.noisecc < 4.f) { k4 = 0.6f; k5 = 0.4f; - } else if ((lp.noisecc < 6.f && aut == 0) || (maxccoarse < 6.f && aut == 1)) { + } else if (lp.noisecc < 6.f) { k4 = 0.8f; k5 = 0.6f; } else { @@ -11404,11 +11317,11 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl variCb[4] = rtengine::max(0.000001f, k4 * variCb[4]); variCb[5] = rtengine::max(0.000001f, k5 * variCb[5]); - if ((lp.noisecc < 4.f && aut == 0) || (maxccoarse < 4.f && aut == 1)) { + if (lp.noisecc < 4.f) { k6 = 0.f; - } else if ((lp.noisecc < 5.f && aut == 0) || (maxccoarse < 5.f && aut == 1)) { + } else if (lp.noisecc < 5.f) { k6 = 0.4f; - } else if ((lp.noisecc < 6.f && aut == 0) || (maxccoarse < 6.f && aut == 1)) { + } else if (lp.noisecc < 6.f) { k6 = 0.7f; } else { k6 = 1.f; @@ -11417,7 +11330,6 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl variC[6] = rtengine::max(0.00001f, k6 * variC[6]); variCb[6] = rtengine::max(0.00001f, k6 * variCb[6]); - } float* noisevarchrom = new float[GH * GW]; //noisevarchrom in function chroma @@ -11425,7 +11337,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl float nvch = 0.6f;//high value float nvcl = 0.1f;//low value - if ((lp.noisecf > 100.f && aut == 0) || (maxcfine > 100.f && (aut == 1 || aut == 2))) { + if (lp.noisecf > 100.f) { nvch = 0.8f; nvcl = 0.4f; } @@ -11534,7 +11446,6 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl } } - if(gamma > 1.f) { #ifdef _OPENMP # pragma omp parallel for schedule(dynamic,16) if (multiThread) @@ -11552,10 +11463,6 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl } } - if(lp.nlstr > 0) { - NLMeans(tmp1.L, lp.nlstr, lp.nldet, lp.nlpat, lp.nlrad, lp.nlgam, GW, GH, float (sk), multiThread); - } - if(lp.smasktyp != 0) { if(lp.enablMask && lp.recothrd != 1.f) { LabImage tmp3(GW, GH); @@ -11634,7 +11541,82 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl masklum.free(); masklumch.free(); } - DeNoise_Local(call, lp, originalmaskbl, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, tmp1, cx, cy, sk); + +// re read wavelet decomposition to calaculate noise residual + float chresid = 0.f; + float chresidtemp = 0.f; + float chmaxresid = 0.f; + float chmaxresidtemp = 0.f; + float chresid46 = 0.f; + float chresidtemp46 = 0.f; + float chmaxresid46 = 0.f; + float chmaxresidtemp46 = 0.f; + float Lresid = 0.f; + float Lmaxresid = 0.f; + float Lresid46 = 0.f; + float Lmaxresid46 = 0.f; + + +//calculate and display residual noise luma and chroma +// various coefficient from 1 to 5 - tries to take into account the difference between calculate Noise and percepted noise + wavelet_decomposition Ldecompinf(tmp1.L[0], tmp1.W, tmp1.H, levwavL, 1, skip, numThreads, lp.daubLen); + wavelet_decomposition adecompinf(tmp1.a[0], tmp1.W, tmp1.H, levwavL, 1, skip, numThreads, lp.daubLen); + wavelet_decomposition bdecompinf(tmp1.b[0], tmp1.W, tmp1.H, levwavL, 1, skip, numThreads, lp.daubLen); + + Noise_residualAB(adecompinf, chresid, chmaxresid, false, 0, 3); + chresidtemp = chresid; + chmaxresidtemp = chmaxresid; + Noise_residualAB(bdecompinf, chresid, chmaxresid, false, 0, 3); + chresid += chresidtemp; + chmaxresid += chmaxresidtemp; + int nbmaddir = 4; + chresid = sqrt(chresid / ( 3 * nbmaddir * 2)); + highresi = chresid + 0.5f * (sqrt(chmaxresid) - chresid); //evaluate sigma + nresi = chresid; + highresi /= 1.4f;//arbitrary coefficient + nresi /= 1.4f; + + // printf("nresi03=%f highresi=%f \n", (double) nresi, (double) highresi); + + + Noise_residualAB(adecompinf, chresid46, chmaxresid46, false, 4, 6); + nbmaddir = 3; + chresidtemp46 = chresid46; + chmaxresidtemp46 = chmaxresid46; + Noise_residualAB(bdecompinf, chresid46, chmaxresid46, false, 4, 6); + chresid46 += chresidtemp46; + chmaxresid46 += chmaxresidtemp46; + chresid46 = sqrt(chresid46 / ( 3 * nbmaddir * 2)); + highresi46 = chresid46 + 0.5f * (sqrt(chmaxresid46) - chresid46); //evaluate sigma + nresi46 = chresid46; + highresi46 /= 2.f;//arbitrary coefficient + nresi46 /= 2.f; + + // printf("nresi46=%f highresi=%f \n", (double) nresi46, (double) highresi46); + + + Noise_residualAB(Ldecompinf, Lresid, Lmaxresid, false, 0, 3); + nbmaddir = 4; + Lresid = sqrt(Lresid / (3 * nbmaddir)); + Lhighresi = Lresid + 0.5f * (sqrt(Lmaxresid) - Lresid); //evaluate sigma + Lnresi = Lresid; + Lnresi /= 2.f;//arbitrary coefficient + Lhighresi /= 2.f; + // printf("Lresi03=%f Lhighresi=%f levwavL=%i\n", (double) Lnresi, (double) Lhighresi, levwavL); + + Noise_residualAB(Ldecompinf, Lresid46, Lmaxresid46, false, 4, 6); + nbmaddir = 3; + Lresid46 = sqrt(Lresid46 / (3 * nbmaddir)); + Lhighresi46 = Lresid46 + 0.5f * (sqrt(Lmaxresid46) - Lresid46); //evaluate sigma + Lnresi46 = Lresid46; + Lhighresi46 /= 5.f;//arbitrary coefficient + Lnresi46 /= 5.f; + // printf("Lresi46=%f Lhighresi=%f levwavL=%i\n", (double) Lnresi46, (double) Lhighresi46, levwavL); + +// end calculate + + DeNoise_Local(call, lp, originalmaskbl, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, tmp1, cx, cy, sk); + } else { DeNoise_Local(call, lp, original, levred, huerefblur, lumarefblur, chromarefblur, original, transformed, tmp1, cx, cy, sk); } @@ -11731,69 +11713,40 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl float vari[levred]; float mxsl = 0.f; - // float mxsfl = 0.f; - if (aut == 0) { - if (levred == 7) { + { edge = 2; vari[0] = 0.8f * SQR((lp.noiself0 / 125.f) * (1.f + lp.noiself0 / 25.f)); vari[1] = 0.8f * SQR((lp.noiself / 125.f) * (1.f + lp.noiself / 25.f)); vari[2] = 0.8f * SQR((lp.noiself2 / 125.f) * (1.f + lp.noiself2 / 25.f)); - vari[3] = 0.8f * SQR((lp.noiselc / 125.f) * (1.f + lp.noiselc / 25.f)); - vari[4] = 0.8f * SQR((lp.noiselc4 / 125.f) * (1.f + lp.noiselc4 / 25.f)); - vari[5] = 0.8f * SQR((lp.noiselc5 / 125.f) * (1.f + lp.noiselc5 / 25.f)); - vari[6] = 0.8f * SQR((lp.noiselc6 / 125.f) * (1.f + lp.noiselc6 / 25.f)); - } else if (levred == 4) { - edge = 3; - vari[0] = 0.8f * SQR((lp.noiself0 / 125.f) * (1.f + lp.noiself0 / 25.f)); - vari[1] = 0.8f * SQR((lp.noiself / 125.f) * (1.f + lp.noiself / 25.f)); - vari[2] = 0.8f * SQR((lp.noiselc / 125.f) * (1.f + lp.noiselc / 25.f)); - vari[3] = 0.8f * SQR((lp.noiselc / 125.f) * (1.f + lp.noiselc / 25.f)); - - } - } else if (aut == 1 || aut == 2) { - edge = 2; - vari[0] = SQR(slidL[0]); - vari[1] = SQR(slidL[1]); - vari[2] = SQR(slidL[2]); - vari[3] = SQR(slidL[3]); - vari[4] = SQR(slidL[4]); - vari[5] = SQR(slidL[5]); - vari[6] = SQR(slidL[6]); - float mxslid34 = rtengine::max(slidL[3], slidL[4]); - float mxslid56 = rtengine::max(slidL[5], slidL[6]); - mxsl = rtengine::max(mxslid34, mxslid56); - - } + vari[4] = 1.f * SQR((lp.noiselc4 / 125.f) * (1.f + lp.noiselc4 / 25.f)); + vari[5] = 1.5f * SQR((lp.noiselc5 / 125.f) * (1.f + lp.noiselc5 / 25.f)); + vari[6] = 2.5f * SQR((lp.noiselc6 / 125.f) * (1.f + lp.noiselc6 / 25.f)); + } { float kr3 = 0.f; - if (aut == 0 || aut == 1) { - if ((lp.noiselc < 30.f && aut == 0) || (mxsl < 30.f && aut == 1)) { + { + if (lp.noiselc < 30.f) { kr3 = 0.f; - } else if ((lp.noiselc < 50.f && aut == 0) || (mxsl < 50.f && aut == 1)) { + } else if (lp.noiselc < 50.f) { kr3 = 0.5f; - } else if ((lp.noiselc < 70.f && aut == 0) || (mxsl < 70.f && aut == 1)) { + } else if (lp.noiselc < 70.f) { kr3 = 0.7f; } else { kr3 = 1.f; } - } else if (aut == 2) { - kr3 = 1.f; - } + } vari[0] = rtengine::max(0.000001f, vari[0]); vari[1] = rtengine::max(0.000001f, vari[1]); vari[2] = rtengine::max(0.000001f, vari[2]); vari[3] = rtengine::max(0.000001f, kr3 * vari[3]); - - if (levred == 7) { - vari[4] = rtengine::max(0.000001f, vari[4]); - vari[5] = rtengine::max(0.000001f, vari[5]); - vari[6] = rtengine::max(0.000001f, vari[6]); - } + vari[4] = rtengine::max(0.000001f, vari[4]); + vari[5] = rtengine::max(0.000001f, vari[5]); + vari[6] = rtengine::max(0.000001f, vari[6]); // float* noisevarlum = nullptr; // we need a dummy to pass it to WaveletDenoiseAllL float* noisevarlum = new float[bfh * bfw]; @@ -11930,77 +11883,28 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl if (!adecomp.memory_allocation_failed() && !bdecomp.memory_allocation_failed()) { - float maxcfine = 0.f; float maxccoarse = 0.f; - if (aut == 0) { - if (levred == 7) { + { edge = 2; variC[0] = SQR(noisecfr); variC[1] = SQR(noisecfr); variC[2] = SQR(noisecfr); - - variC[3] = SQR(noisecfr); + variC[3] = SQR(1.2f * noisecfr); variC[4] = SQR(noisecfr); - variC[5] = SQR(noiseccr); - variC[6] = SQR(noiseccr); + variC[5] = SQR(1.2f * noiseccr); + variC[6] = SQR(1.5f * noiseccr); variCb[0] = SQR(noisecfb); variCb[1] = SQR(noisecfb); variCb[2] = SQR(noisecfb); - variCb[3] = SQR(noisecfb); variCb[4] = SQR(noisecfb); - variCb[5] = SQR(noiseccb); - variCb[6] = SQR(noiseccb); + variCb[5] = SQR(1.2f * noiseccb); + variCb[6] = SQR(1.5f * noiseccb); - } else if (levred == 4) { - edge = 3; - variC[0] = SQR(lp.noisecf / 10.f); - variC[1] = SQR(lp.noisecf / 10.f); - variC[2] = SQR(lp.noisecf / 10.f); - variC[3] = SQR(lp.noisecf / 10.f); - - variCb[0] = SQR(lp.noisecf / 10.f); - variCb[1] = SQR(lp.noisecf / 10.f); - variCb[2] = SQR(lp.noisecf / 10.f); - variCb[3] = SQR(lp.noisecf / 10.f); - - - } - } else if (aut == 1 || aut == 2) { - edge = 2; - variC[0] = SQR(slida[0]); - variC[1] = SQR(slida[1]); - variC[2] = SQR(slida[2]); - variC[3] = SQR(slida[3]); - variC[4] = SQR(slida[4]); - variC[5] = SQR(slida[5]); - variC[6] = SQR(slida[6]); - float maxc01 = rtengine::max(slida[0], slida[1]); - float maxc23 = rtengine::max(slida[2], slida[3]); - float max03 = rtengine::max(maxc01, maxc23); - float maxrf = rtengine::max(max03, slida[4]); - float maxrc = rtengine::max(slida[5], slida[6]); - - variCb[0] = SQR(slidb[0]); - variCb[1] = SQR(slidb[1]); - variCb[2] = SQR(slidb[2]); - variCb[3] = SQR(slidb[3]); - variCb[4] = SQR(slidb[4]); - variCb[5] = SQR(slidb[5]); - variCb[6] = SQR(slidb[6]); - float maxb01 = rtengine::max(slidb[0], slidb[1]); - float maxb23 = rtengine::max(slidb[2], slidb[3]); - float maxb03 = rtengine::max(maxb01, maxb23); - float maxbf = rtengine::max(maxb03, slidb[4]); - maxcfine = rtengine::max(maxrf, maxbf); - - float maxbc = rtengine::max(slidb[5], slidb[6]); - maxccoarse = rtengine::max(maxrc, maxbc); - - } + } { float minic = 0.000001f; @@ -12013,52 +11917,51 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl float k2 = 0.f; float k3 = 0.f; - if (aut == 0 || aut == 1) { - if ((lp.noisecf < 0.2f && aut == 0) || (maxcfine < 0.2f && aut == 1)) { + if (lp.noisecf < 0.2f) { k1 = 0.05f; k2 = 0.f; k3 = 0.f; - } else if ((lp.noisecf < 0.3f && aut == 0) || (maxcfine < 0.3f && aut == 1)) { + } else if (lp.noisecf < 0.3f) { k1 = 0.1f; k2 = 0.0f; k3 = 0.f; - } else if ((lp.noisecf < 0.5f && aut == 0) || (maxcfine < 0.5f && aut == 1)) { + } else if (lp.noisecf < 0.5f) { k1 = 0.2f; k2 = 0.1f; k3 = 0.f; - } else if ((lp.noisecf < 0.8f && aut == 0) || (maxcfine < 0.8f && aut == 1)) { + } else if (lp.noisecf < 0.8f) { k1 = 0.3f; k2 = 0.25f; k3 = 0.f; - } else if ((lp.noisecf < 1.f && aut == 0) || (maxcfine < 1.f && aut == 1)) { + } else if (lp.noisecf < 1.f) { k1 = 0.4f; k2 = 0.25f; k3 = 0.1f; - } else if ((lp.noisecf < 2.f && aut == 0) || (maxcfine < 2.f && aut == 1)) { + } else if (lp.noisecf < 2.f) { k1 = 0.5f; k2 = 0.3f; k3 = 0.15f; - } else if ((lp.noisecf < 3.f && aut == 0) || (maxcfine < 3.f && aut == 1)) { + } else if (lp.noisecf < 3.f) { k1 = 0.6f; k2 = 0.45f; k3 = 0.3f; - } else if ((lp.noisecf < 4.f && aut == 0) || (maxcfine < 4.f && aut == 1)) { + } else if (lp.noisecf < 4.f) { k1 = 0.7f; k2 = 0.5f; k3 = 0.4f; - } else if ((lp.noisecf < 5.f && aut == 0) || (maxcfine < 5.f && aut == 1)) { + } else if (lp.noisecf < 5.f) { k1 = 0.8f; k2 = 0.6f; k3 = 0.5f; - } else if ((lp.noisecf < 6.f && aut == 0) || (maxcfine < 10.f && aut == 1)) { + } else if (lp.noisecf < 6.f) { k1 = 0.85f; k2 = 0.7f; k3 = 0.6f; - } else if ((lp.noisecf < 8.f && aut == 0) || (maxcfine < 20.f && aut == 1)) { + } else if (lp.noisecf < 8.f) { k1 = 0.9f; k2 = 0.8f; k3 = 0.7f; - } else if ((lp.noisecf < 10.f && aut == 0) || (maxcfine < 50.f && aut == 1)) { + } else if (lp.noisecf < 10.f) { k1 = 1.f; k2 = 1.f; k3 = 0.9f; @@ -12066,13 +11969,8 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl } else { k1 = 1.f; k2 = 1.f; - k3 = 1.f; + k3 = 1.5f; } - } else if (aut == 2) { - k1 = 1.f; - k2 = 1.f; - k3 = 1.f; - } variC[0] = rtengine::max(minic, variC[0]); variC[1] = rtengine::max(minic, k1 * variC[1]); @@ -12084,27 +11982,27 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl variCb[2] = rtengine::max(minic, k2 * variCb[2]); variCb[3] = rtengine::max(minic, k3 * variCb[3]); - if (levred == 7) { + { float k4 = 0.f; float k5 = 0.f; float k6 = 0.f; - if ((lp.noisecc < 0.2f && aut == 0) || (maxccoarse < 0.2f && aut == 1)) { + if (lp.noisecc < 0.2f) { k4 = 0.1f; k5 = 0.02f; - } else if ((lp.noisecc < 0.5f && aut == 0) || (maxccoarse < 0.5f && aut == 1)) { + } else if (lp.noisecc < 0.5f) { k4 = 0.15f; k5 = 0.05f; - } else if ((lp.noisecc < 1.f && aut == 0) || (maxccoarse < 1.f && aut == 1)) { + } else if (lp.noisecc < 1.f) { k4 = 0.15f; k5 = 0.1f; - } else if ((lp.noisecc < 3.f && aut == 0) || (maxccoarse < 3.f && aut == 1)) { + } else if (lp.noisecc < 3.f) { k4 = 0.3f; k5 = 0.15f; - } else if ((lp.noisecc < 4.f && aut == 0) || (maxccoarse < 5.f && aut == 1)) { + } else if (lp.noisecc < 4.f) { k4 = 0.6f; k5 = 0.4f; - } else if ((lp.noisecc < 6.f && aut == 0) || (maxccoarse < 6.f && aut == 1)) { + } else if (lp.noisecc < 6.f) { k4 = 0.8f; k5 = 0.6f; } else { @@ -12118,11 +12016,11 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl variCb[4] = rtengine::max(0.000001f, k4 * variCb[4]); variCb[5] = rtengine::max(0.000001f, k5 * variCb[5]); - if ((lp.noisecc < 4.f && aut == 0) || (maxccoarse < 4.f && aut == 1)) { + if (lp.noisecc < 4.f) { k6 = 0.f; - } else if ((lp.noisecc < 5.f && aut == 0) || (maxccoarse < 5.f && aut == 1)) { + } else if (lp.noisecc < 5.f) { k6 = 0.4f; - } else if ((lp.noisecc < 6.f && aut == 0) || (maxccoarse < 6.f && aut == 1)) { + } else if (lp.noisecc < 6.f) { k6 = 0.7f; } else { k6 = 1.f; @@ -12137,7 +12035,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl float nvch = 0.6f;//high value float nvcl = 0.1f;//low value - if ((lp.noisecf > 30.f && aut == 0) || (maxcfine > 100.f && (aut == 1 || aut == 2))) { + if (lp.noisecf > 30.f) { nvch = 0.8f; nvcl = 0.4f; } @@ -12377,6 +12275,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl } } } + } } @@ -13363,7 +13262,9 @@ void ImProcFunctions::Lab_Local( double& huerefblur, double& chromarefblur, double& lumarefblur, double& hueref, double& chromaref, double& lumaref, double& sobelref, int &lastsav, bool prevDeltaE, int llColorMask, int llColorMaskinv, int llExpMask, int llExpMaskinv, int llSHMask, int llSHMaskinv, int llvibMask, int lllcMask, int llsharMask, int llcbMask, int llretiMask, int llsoftMask, int lltmMask, int llblMask, int lllogMask, int ll_Mask, int llcieMask, float& minCD, float& maxCD, float& mini, float& maxi, float& Tmean, float& Tsigma, float& Tmin, float& Tmax, - float& meantm, float& stdtm, float& meanreti, float& stdreti, float &fab + float& meantm, float& stdtm, float& meanreti, float& stdreti, float &fab, + float& highresi, float& nresi, float& highresi46, float& nresi46, float& Lhighresi, float& Lnresi, float& Lhighresi46, float& Lnresi46 + ) { //general call of others functions : important return hueref, chromaref, lumaref @@ -14410,12 +14311,9 @@ void ImProcFunctions::Lab_Local( //local denoise if (lp.activspot && lp.denoiena && (lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.wavcurvedenoi ||lp.nlstr > 0 || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f )) {//disable denoise if not used - float slidL[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; - float slida[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; - float slidb[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; constexpr int aut = 0; - DeNoise(call, slidL, slida, slidb, aut, noiscfactiv, lp, originalmaskbl.get(), bufmaskblurbl.get(), levred, huerefblur, lumarefblur, chromarefblur, original, transformed, cx, cy, sk, locwavCurvehue, locwavhueutili); - + DeNoise(call, aut, noiscfactiv, lp, originalmaskbl.get(), bufmaskblurbl.get(), levred, huerefblur, lumarefblur, chromarefblur, original, transformed, cx, cy, sk, locwavCurvehue, locwavhueutili, + highresi, nresi, highresi46, nresi46, Lhighresi, Lnresi, Lhighresi46, Lnresi46); if (lp.recur) { original->CopyFrom(transformed, multiThread); float avge; @@ -19275,6 +19173,7 @@ void ImProcFunctions::Lab_Local( calc_ref(sp, original, transformed, 0, 0, original->W, original->H, sk, huerefblur, chromarefblur, lumarefblur, hueref, chromaref, lumaref, sobelref, avge, locwavCurveden, locwavdenutili); } } + } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index f86950457..1d7994ace 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -438,9 +438,21 @@ public: double Tmax; }; + struct locallabDenoiseLC { + double highres; + double nres; + double highres46; + double nres46; + double Lhighres; + double Lnres; + double Lhighres46; + double Lnres46; + }; + virtual ~LocallabListener() = default; // virtual void refChanged(const std::vector &ref, int selspot) = 0; virtual void minmaxChanged(const std::vector &minmax, int selspot) = 0; + virtual void denChanged(const std::vector &denlc, int selspot) = 0; virtual void logencodChanged(const float blackev, const float whiteev, const float sourceg, const float sourceab, const float targetg, const bool autocomput, const bool autocie, const float jz1) = 0; virtual void refChanged2(float *huerefp, float *chromarefp, float *lumarefp, float *fabrefp, int selspot) = 0; }; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 78dd84042..96cd68d43 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1175,6 +1175,14 @@ private: float Tsigma; float Tmin; float Tmax; + float highresi = 0.f; + float nresi = 0.f; + float highresi46 =0.f; + float nresi46 = 0.f; + float Lhighresi = 0.f; + float Lnresi = 0.f; + float Lhighresi46 = 0.f; + float Lnresi46 = 0.f; // No Locallab mask is shown in exported picture ipf.Lab_Local(2, sp, shbuffer, labView, labView, reservView.get(), savenormtmView.get(), savenormretiView.get(), lastorigView.get(), fw, fh, 0, 0, fw, fh, 1, locRETgainCurve, locRETtransCurve, @@ -1229,7 +1237,8 @@ private: LHutili, HHutili, CHutili, HHutilijz, CHutilijz, LHutilijz, cclocalcurve, localcutili, rgblocalcurve, localrgbutili, localexutili, exlocalcurve, hltonecurveloc, shtonecurveloc, tonecurveloc, lightCurveloc, huerefblu, chromarefblu, lumarefblu, huere, chromare, lumare, sobelre, lastsav, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, - meantme, stdtme, meanretie, stdretie, fab + meantme, stdtme, meanretie, stdretie, fab, + highresi, nresi, highresi46, nresi46, Lhighresi, Lnresi, Lhighresi46, Lnresi46 ); if (sp + 1u < params.locallab.spots.size()) { diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index 8e8e999d3..e7725a005 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -703,6 +703,19 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited expreti.updateMinMax(cdma, cdmin, mini, maxi, Tmean, Tsigma, Tmin, Tmax); } + // Update Locallab Denoise tool lum/chro + if (pp->locallab.selspot < (int) denoiselc.size()) { + const double highres = denoiselc.at(pp->locallab.selspot).highres; + const double nres = denoiselc.at(pp->locallab.selspot).nres; + const double highres46 = denoiselc.at(pp->locallab.selspot).highres46; + const double nres46 = denoiselc.at(pp->locallab.selspot).nres46; + const double Lhighres = denoiselc.at(pp->locallab.selspot).Lhighres; + const double Lnres = denoiselc.at(pp->locallab.selspot).Lnres; + const double Lhighres46 = denoiselc.at(pp->locallab.selspot).Lhighres46; + const double Lnres46 = denoiselc.at(pp->locallab.selspot).Lnres46; + + expblur.updatedenlc(highres, nres, highres46, nres46, Lhighres, Lnres, Lhighres46, Lnres46); + } // Update default values according to selected spot setDefaults(pp, pedited); @@ -1094,6 +1107,28 @@ void Locallab::minmaxChanged(const std::vector &minmax, int } } +void Locallab::denChanged(const std::vector &denlc, int selspot) +{ + // Saving transmitted min/max data + denoiselc = denlc; + + //Update Locallab Denoise tool lum chro + if (selspot < (int) denoiselc.size()) { + const double highres = denoiselc.at(selspot).highres; + const double nres = denoiselc.at(selspot).nres; + const double highres46 = denoiselc.at(selspot).highres46; + const double nres46 = denoiselc.at(selspot).nres46; + const double Lhighres = denoiselc.at(selspot).Lhighres; + const double Lnres = denoiselc.at(selspot).Lnres; + const double Lhighres46 = denoiselc.at(selspot).Lhighres46; + const double Lnres46 = denoiselc.at(selspot).Lnres46; + + expblur.updatedenlc(highres, nres, highres46, nres46, Lhighres, Lnres, Lhighres46, Lnres46); + } + +} + + void Locallab::logencodChanged(const float blackev, const float whiteev, const float sourceg, const float sourceab, const float targetg, const bool autocomput, const bool autocie, const float jz1) { // Update Locallab Log Encoding and Ciecam accordingly diff --git a/rtgui/locallab.h b/rtgui/locallab.h index b0030bbe6..e39f213cc 100644 --- a/rtgui/locallab.h +++ b/rtgui/locallab.h @@ -123,6 +123,9 @@ private: // Locallab tools mask background management data std::vector retiMinMax; + // Locallab tools mask background management data + std::vector denoiselc; + // Locallab tools mask background management data std::vector maskBackRef; @@ -145,6 +148,10 @@ public: // Locallab Retinex tool min/man management function void minmaxChanged(const std::vector &minmax, int selspot) override; + //Locallab denoise + // Locallab Retinex tool min/man management function + void denChanged(const std::vector &denlc, int selspot) override; + // Locallab Log Encoding autocompute function void logencodChanged(const float blackev, const float whiteev, const float sourceg, const float sourceab, const float targetg, const bool autocomput, const bool autocie, const float jz1) override; diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index c59dd233a..2ebac1630 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -6477,8 +6477,17 @@ LocallabBlur::LocallabBlur(): activlum(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ACTIV")))), expdenoise(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_DENOI_EXP")))), quamethod(Gtk::manage(new MyComboBoxText())), + expdenoisenl(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_NLFRA")))), + expdenoiselum(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_DENOIWAVLUM")))), + expdenoisech(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_DENOIWAVCH")))), LocalcurveEditorwavden(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVDEN"))), wavshapeden(static_cast(LocalcurveEditorwavden->addCurve(CT_Flat, "", nullptr, false, false))), + // lCLabels(Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_LCLABELS")))), + lCLabels(Gtk::manage(new Gtk::Label("-----------------"))), + lumLabels(Gtk::manage(new Gtk::Label("---"))), + lum46Labels(Gtk::manage(new Gtk::Label("---"))), + chroLabels(Gtk::manage(new Gtk::Label("---"))), + chro46Labels(Gtk::manage(new Gtk::Label("---"))), expdenoise1(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_DENOI1_EXP")))), maskusable(Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_MASKUSABLE")))), maskunusable(Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_MASKUNUSABLE")))), @@ -6514,7 +6523,7 @@ LocallabBlur::LocallabBlur(): decayd(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKDDECAY"), 0.5, 4., 0.1, 2.))), invmaskd(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVMASK")))), invmask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVMASK")))), - nlFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_NLFRA")))), + prevFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LCLABELS")))), nlstr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NLLUM"), 0, 100, 1, 0))), nldet(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NLDET"), 0, 100, 1, 50))), nlpat(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NLPAT"), 1, 5, 1, 2))), @@ -6640,12 +6649,23 @@ LocallabBlur::LocallabBlur(): Gtk::Label* const quaLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_DENQUA") + ":")); quaHBox->pack_start(*quaLabel, Gtk::PACK_SHRINK, 4); quaHBox->pack_start(*quamethod); + setExpandAlignProperties(expdenoisenl, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + setExpandAlignProperties(expdenoiselum, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + setExpandAlignProperties(expdenoisech, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); LocalcurveEditorwavden->setCurveListener(this); wavshapeden->setIdentityValue(0.); wavshapeden->setResetCurve(FlatCurveType(defSpot.locwavcurveden.at(0)), defSpot.locwavcurveden); + setExpandAlignProperties(lCLabels, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + setExpandAlignProperties(lumLabels, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + setExpandAlignProperties(lum46Labels, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + + setExpandAlignProperties(chroLabels, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + setExpandAlignProperties(chro46Labels, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + + LocalcurveEditorwavden->curveListComplete(); setExpandAlignProperties(expdenoise1, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); @@ -6701,7 +6721,7 @@ LocallabBlur::LocallabBlur(): decayd->setAdjusterListener(this); bilateral->setAdjusterListener(this); - nlFrame->set_label_align(0.025, 0.5); + prevFrame->set_label_align(0.025, 0.5); nlstr->setAdjusterListener(this); nldet->setAdjusterListener(this); @@ -6838,15 +6858,39 @@ LocallabBlur::LocallabBlur(): Gtk::Frame* const wavFrame = Gtk::manage(new Gtk::Frame()); ToolParamBlock* const wavBox = Gtk::manage(new ToolParamBlock()); wavBox->pack_start(*quaHBox); - wavBox->pack_start(*LocalcurveEditorwavden, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + wavBox->pack_start(*sensiden); + wavBox->pack_start(*reparden); + ToolParamBlock* const prevBox = Gtk::manage(new ToolParamBlock()); + prevBox->pack_start(*lumLabels); + prevBox->pack_start(*lum46Labels); + prevBox->pack_start(*lCLabels); + prevBox->pack_start(*chroLabels); + prevBox->pack_start(*chro46Labels); + prevFrame->add(*prevBox); + wavBox->pack_start(*prevFrame); + + ToolParamBlock* const nlbox = Gtk::manage(new ToolParamBlock()); + nlbox->pack_start(*nlstr); + nlbox->pack_start(*nldet); + nlbox->pack_start(*nlgam); + nlbox->pack_start(*nlpat); + nlbox->pack_start(*nlrad); + expdenoisenl->add(*nlbox); + + wavBox->pack_start(*expdenoisenl); + + // wavBox->pack_start(*noiselumf0); // wavBox->pack_start(*noiselumf); // wavBox->pack_start(*noiselumf2); // wavBox->pack_start(*noiselumc);//unused here, but used for normalize_mean_dt - wavBox->pack_start(*noiselumdetail); - wavBox->pack_start(*noiselequal); - wavBox->pack_start(*noisegam); - wavBox->pack_start(*LocalcurveEditorwavhue, Gtk::PACK_SHRINK, 4); + ToolParamBlock* const wchBox = Gtk::manage(new ToolParamBlock()); + + wchBox->pack_start(*LocalcurveEditorwavden, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + wchBox->pack_start(*noiselumdetail); + wchBox->pack_start(*noiselequal); + wchBox->pack_start(*noisegam); + wchBox->pack_start(*LocalcurveEditorwavhue, Gtk::PACK_SHRINK, 4); ToolParamBlock* const wavBox1 = Gtk::manage(new ToolParamBlock()); wavBox1->pack_start(*maskusable, Gtk::PACK_SHRINK, 0); wavBox1->pack_start(*maskunusable, Gtk::PACK_SHRINK, 0); @@ -6854,28 +6898,24 @@ LocallabBlur::LocallabBlur(): wavBox1->pack_start(*levelthrlow, Gtk::PACK_SHRINK, 0); wavBox1->pack_start(*levelthr, Gtk::PACK_SHRINK, 0); expdenoise1->add(*wavBox1, false); - wavBox->pack_start(*expdenoise1); + wchBox->pack_start(*expdenoise1); + expdenoiselum->add(*wchBox); + wavBox->pack_start(*expdenoiselum); + ToolParamBlock* const chBox = Gtk::manage(new ToolParamBlock()); + + chBox->pack_start(*noisechrof); + chBox->pack_start(*noisechroc); + chBox->pack_start(*noisechrodetail); + chBox->pack_start(*adjblur); + expdenoisech->add(*chBox); + wavBox->pack_start(*expdenoisech); + ToolParamBlock* const detailBox = Gtk::manage(new ToolParamBlock()); detailBox->pack_start(*detailthr); detailBox->pack_start(*usemask, Gtk::PACK_SHRINK, 0); detailFrame->add(*detailBox); wavBox->pack_start(*detailFrame); - denoisebox->pack_start(*sensiden); - denoisebox->pack_start(*reparden); - - ToolParamBlock* const nlbox = Gtk::manage(new ToolParamBlock()); - nlbox->pack_start(*nlstr); - nlbox->pack_start(*nldet); - nlbox->pack_start(*nlgam); - nlbox->pack_start(*nlpat); - nlbox->pack_start(*nlrad); - nlFrame->add(*nlbox); - wavBox->pack_start(*nlFrame); - - wavBox->pack_start(*noisechrof); - wavBox->pack_start(*noisechroc); - wavBox->pack_start(*noisechrodetail); - wavBox->pack_start(*adjblur); + wavFrame->add(*wavBox); denoisebox->pack_start(*wavFrame); @@ -6978,6 +7018,7 @@ void LocallabBlur::updateAdviceTooltips(const bool showTooltips) expdenoise1->set_tooltip_markup(M("TP_LOCALLAB_MASKLC_TOOLTIP")); expdenoise2->set_tooltip_markup(M("TP_LOCALLAB_MASKGF_TOOLTIP")); expdenoise3->set_tooltip_markup(M("TP_LOCALLAB_MASKDE_TOOLTIP")); + expdenoisenl->set_tooltip_markup(M("TP_LOCALLAB_NLFRAME_TOOLTIP")); invmask->set_tooltip_text(M("TP_LOCALLAB_MASKDEINV_TOOLTIP")); invmaskd->set_tooltip_text(M("TP_LOCALLAB_MASKDEINV_TOOLTIP")); LocalcurveEditorwavden->setTooltip(M("TP_LOCALLAB_WASDEN_TOOLTIP")); @@ -6990,7 +7031,7 @@ void LocallabBlur::updateAdviceTooltips(const bool showTooltips) detailthr->set_tooltip_text(M("TP_LOCALLAB_DENOITHR_TOOLTIP")); adjblur->set_tooltip_text(M("TP_LOCALLAB_DENOIEQUALCHRO_TOOLTIP")); bilateral->set_tooltip_text(M("TP_LOCALLAB_DENOIBILAT_TOOLTIP")); - nlFrame->set_tooltip_text(M("TP_LOCALLAB_NLFRAME_TOOLTIP")); + prevFrame->set_tooltip_text(M("TP_LOCALLAB_LCLABELS_TOOLTIP")); nlstr->set_tooltip_text(M("TP_LOCALLAB_NLDENOISE_TOOLTIP")); nldet->set_tooltip_text(M("TP_LOCALLAB_NLDENOISE_TOOLTIP")); nlpat->set_tooltip_text(M("TP_LOCALLAB_NLDENOISENLPAT_TOOLTIP")); @@ -7025,6 +7066,7 @@ void LocallabBlur::updateAdviceTooltips(const bool showTooltips) higthresd->set_tooltip_text(M("TP_LOCALLAB_MASKHIGTHRESD_TOOLTIP")); higthres->set_tooltip_text(M("TP_LOCALLAB_MASKHIGTHRES_TOOLTIP")); decayd->set_tooltip_text(M("TP_LOCALLAB_MASKDECAY_TOOLTIP")); + lCLabels->set_tooltip_text(M("TP_LOCALLAB_LCLABELS_TOOLTIP")); } else { expblnoise->set_tooltip_markup(""); @@ -7057,7 +7099,7 @@ void LocallabBlur::updateAdviceTooltips(const bool showTooltips) detailthr->set_tooltip_text(""); adjblur->set_tooltip_text(""); bilateral->set_tooltip_text(""); - nlFrame->set_tooltip_text(""); + prevFrame->set_tooltip_text(""); nlstr->set_tooltip_text(""); nldet->set_tooltip_text(""); nlpat->set_tooltip_text(""); @@ -7094,6 +7136,8 @@ void LocallabBlur::updateAdviceTooltips(const bool showTooltips) higthres->set_tooltip_text(""); // midthresd->set_tooltip_text(""); decayd->set_tooltip_text(""); + lCLabels->set_tooltip_text(""); + expdenoisenl->set_tooltip_markup(""); } } @@ -7138,7 +7182,36 @@ void LocallabBlur::neutral_pressed () } +void LocallabBlur::updatedenlc(const double highres, const double nres, const double highres46, const double nres46, const double Lhighres, const double Lnres, const double Lhighres46, const double Lnres46) +{ + idle_register.add( + [this, highres, nres, highres46, nres46, Lhighres, Lnres, Lhighres46, Lnres46]() -> bool { + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + lumLabels->set_text( + Glib::ustring::compose(M("TP_LOCALLAB_LUMLABEL"), + Glib::ustring::format(std::fixed, std::setprecision(0), Lnres), + Glib::ustring::format(std::fixed, std::setprecision(0), Lhighres)) + ); + lum46Labels->set_text( + Glib::ustring::compose(M("TP_LOCALLAB_LUM46LABEL"), + Glib::ustring::format(std::fixed, std::setprecision(0), Lnres46 ), + Glib::ustring::format(std::fixed, std::setprecision(0), Lhighres46)) + ); + chroLabels->set_text( + Glib::ustring::compose(M("TP_LOCALLAB_CHROLABEL"), + Glib::ustring::format(std::fixed, std::setprecision(0), nres), + Glib::ustring::format(std::fixed, std::setprecision(0), highres)) + ); + chro46Labels->set_text( + Glib::ustring::compose(M("TP_LOCALLAB_CHRO46LABEL"), + Glib::ustring::format(std::fixed, std::setprecision(0), nres46), + Glib::ustring::format(std::fixed, std::setprecision(0), highres46)) + ); + return false; + } + ); +} void LocallabBlur::setDefaultExpanderVisibility() { expblnoise->set_expanded(false); @@ -7147,6 +7220,9 @@ void LocallabBlur::setDefaultExpanderVisibility() expdenoise2->set_expanded(false); expdenoise3->set_expanded(false); expmaskbl->set_expanded(false); + expdenoisenl->set_expanded(false); + expdenoiselum->set_expanded(false); + expdenoisech->set_expanded(false); } void LocallabBlur::disableListener() diff --git a/rtgui/locallabtools.h b/rtgui/locallabtools.h index c4e54ca61..ced248ae1 100644 --- a/rtgui/locallabtools.h +++ b/rtgui/locallabtools.h @@ -707,8 +707,17 @@ private: Gtk::CheckButton* const activlum; MyExpander* const expdenoise; MyComboBoxText* const quamethod; + MyExpander* const expdenoisenl; + MyExpander* const expdenoiselum; + MyExpander* const expdenoisech; CurveEditorGroup* const LocalcurveEditorwavden; FlatCurveEditor* const wavshapeden; + Gtk::Label* const lCLabels; + Gtk::Label* const lumLabels; + Gtk::Label* const lum46Labels; + Gtk::Label* const chroLabels; + Gtk::Label* const chro46Labels; + MyExpander* const expdenoise1; Gtk::Label* const maskusable; Gtk::Label* const maskunusable; @@ -746,7 +755,7 @@ private: Gtk::CheckButton* const invmaskd; Gtk::CheckButton* const invmask; - Gtk::Frame* const nlFrame; + Gtk::Frame* const prevFrame; Adjuster* const nlstr; Adjuster* const nldet; Adjuster* const nlpat; @@ -788,6 +797,8 @@ private: public: LocallabBlur(); ~LocallabBlur(); + void updatedenlc(const double highres, const double nres, const double highres46, const double nres46, const double Lhighres, const double Lnres, const double Lhighres46, const double Lnres46); + bool isMaskViewActive() override; void resetMaskView() override;