diff --git a/rtdata/languages/default b/rtdata/languages/default index 1469281db..e78002452 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -974,7 +974,7 @@ HISTORY_MSG_730;Local - Blur method HISTORY_MSG_731;Local - median method HISTORY_MSG_732;Local - median iterations HISTORY_MSG_733;Local - soft radius -HISTORY_MSG_734;Local - threshold +HISTORY_MSG_734;Local - detail HISTORY_MSG_738;Local - Local contrast Merge L HISTORY_MSG_739;Local - Local contrast Soft radius HISTORY_MSG_740;Local - Local contrast Merge C @@ -1003,6 +1003,7 @@ HISTORY_MSG_762;Local - cbdl Laplacian mask HISTORY_MSG_763;Local - Blur Laplacian mask HISTORY_MSG_764;Local - Solve PDE Laplacian mask HISTORY_MSG_765;Local - deNoise Detail threshold +HISTORY_MSG_766;Local - Blur Fast Fourier HISTORY_MSG_CLAMPOOG;Clip out-of-gamut colors HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction HISTORY_MSG_COLORTONING_LABREGION_AB;CT - Color correction @@ -2083,7 +2084,7 @@ TP_LOCALLAB_BLUMETHOD_TOOLTIP;To blur the background and isolate the foreground: TP_LOCALLAB_BLMED;Median TP_LOCALLAB_BLGUID;Guided Filter Luminance TP_LOCALLAB_GUIDBL;Soft radius -TP_LOCALLAB_EPSBL;Threshold +TP_LOCALLAB_EPSBL;Detail TP_LOCALLAB_SCALERETI;Scale TP_LOCALLAB_BLMETHOD_TOOLTIP;Normal - direct blur and noise with all settings.\nInverse - Inverse blur and noise without scope and whithout enhanced algorithm.\nSymmetric - inverse blur and noise with all settings. Be careful some results may be curious TP_LOCALLAB_BLUFR;Smooth - Blur & Noise diff --git a/rtengine/guidedfilter.cc b/rtengine/guidedfilter.cc index 159e89504..594b918da 100644 --- a/rtengine/guidedfilter.cc +++ b/rtengine/guidedfilter.cc @@ -3,7 +3,6 @@ * This file is part of RawTherapee. * * Copyright (c) 2018 Alberto Griggio - * Optimized 2019 Ingo Weyrich * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,10 +15,10 @@ * 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 . -*/ + * along with RawTherapee. If not, see . + */ -/* +/** * This is a Fast Guided Filter implementation, derived directly from the * pseudo-code of the paper: * @@ -27,16 +26,33 @@ * by Kaiming He, Jian Sun * * available at https://arxiv.org/abs/1505.00996 -*/ + */ #include "guidedfilter.h" #include "boxblur.h" +#include "sleef.c" #include "rescale.h" #include "imagefloat.h" -#define BENCHMARK -#include "StopWatch.h" + namespace rtengine { +#if 0 +# define DEBUG_DUMP(arr) \ + do { \ + Imagefloat im(arr.width(), arr.height()); \ + const char *out = "/tmp/" #arr ".tif"; \ + for (int y = 0; y < im.getHeight(); ++y) { \ + for (int x = 0; x < im.getWidth(); ++x) { \ + im.r(y, x) = im.g(y, x) = im.b(y, x) = arr[y][x] * 65535.f; \ + } \ + } \ + im.saveTIFF(out, 16); \ + } while (false) +#else +# define DEBUG_DUMP(arr) +#endif + + namespace { int calculate_subsampling(int w, int h, int r) @@ -63,10 +79,18 @@ int calculate_subsampling(int w, int h, int r) void guidedFilter(const array2D &guide, const array2D &src, array2D &dst, int r, float epsilon, bool multithread, int subsampling) { - enum Op {MUL, DIVEPSILON, SUBMUL}; + + const int W = src.width(); + const int H = src.height(); + + if (subsampling <= 0) { + subsampling = calculate_subsampling(W, H, r); + } + + enum Op { MUL, DIVEPSILON, ADD, SUB, ADDMUL, SUBMUL }; const auto apply = - [multithread, epsilon](Op op, array2D &res, const array2D &a, const array2D &b, const array2D &c=array2D()) -> void + [=](Op op, array2D &res, const array2D &a, const array2D &b, const array2D &c=array2D()) -> void { const int w = res.width(); const int h = res.height(); @@ -76,31 +100,54 @@ void guidedFilter(const array2D &guide, const array2D &src, array2 #endif for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { + float r; + float aa = a[y][x]; + float bb = b[y][x]; switch (op) { - case MUL: - res[y][x] = a[y][x] * b[y][x]; - break; - case DIVEPSILON: - res[y][x] = a[y][x] / (b[y][x] + epsilon); // note: the value of epsilon intentionally has an impact on the result. It is not only to avoid divisions by zero - break; - case SUBMUL: - res[y][x] = c[y][x] - (a[y][x] * b[y][x]); - break; - default: - assert(false); - res[y][x] = 0; - break; + case MUL: + r = aa * bb; + break; + case DIVEPSILON: + r = aa / (bb + epsilon); + break; + case ADD: + r = aa + bb; + break; + case SUB: + r = aa - bb; + break; + case ADDMUL: + r = aa * bb + c[y][x]; + break; + case SUBMUL: + r = c[y][x] - (aa * bb); + break; + default: + assert(false); + r = 0; + break; } + res[y][x] = r; } } }; + // use the terminology of the paper (Algorithm 2) + const array2D &I = guide; + const array2D &p = src; + array2D &q = dst; + const auto f_subsample = - [multithread](array2D &d, const array2D &s) -> void + [=](array2D &d, const array2D &s) -> void { rescaleBilinear(s, d, multithread); }; + // const auto f_upsample = f_subsample; + + const size_t w = W / subsampling; + const size_t h = H / subsampling; + const auto f_mean = [multithread](array2D &d, array2D &s, int rad) -> void { @@ -108,77 +155,103 @@ void guidedFilter(const array2D &guide, const array2D &src, array2 boxblur(s, d, rad, s.width(), s.height(), multithread); }; - const int W = src.width(); - const int H = src.height(); - - if (subsampling <= 0) { - subsampling = calculate_subsampling(W, H, r); - } - - const size_t w = W / subsampling; - const size_t h = H / subsampling; - const float r1 = float(r) / subsampling; - array2D I1(w, h); array2D p1(w, h); - f_subsample(I1, guide); + f_subsample(I1, I); + f_subsample(p1, p); - if (&guide == &src) { - f_mean(p1, I1, r1); + DEBUG_DUMP(I); + DEBUG_DUMP(p); + DEBUG_DUMP(I1); + DEBUG_DUMP(p1); - apply(MUL, I1, I1, I1); // I1 = I1 * I1 + float r1 = float(r) / subsampling; - f_mean(I1, I1, r1); + array2D meanI(w, h); + f_mean(meanI, I1, r1); + DEBUG_DUMP(meanI); - apply(SUBMUL, I1, p1, p1, I1); // I1 = I1 - p1 * p1 - apply(DIVEPSILON, I1, I1, I1); // I1 = I1 / (I1 + epsilon) - apply(SUBMUL, p1, I1, p1, p1); // p1 = p1 - I1 * p1 + array2D meanp(w, h); + f_mean(meanp, p1, r1); + DEBUG_DUMP(meanp); - } else { - f_subsample(p1, src); + array2D &corrIp = p1; + apply(MUL, corrIp, I1, p1); + f_mean(corrIp, corrIp, r1); + DEBUG_DUMP(corrIp); - array2D meanI(w, h); - f_mean(meanI, I1, r1); + array2D &corrI = I1; + apply(MUL, corrI, I1, I1); + f_mean(corrI, corrI, r1); + DEBUG_DUMP(corrI); - array2D meanp(w, h); - f_mean(meanp, p1, r1); + array2D &varI = corrI; + apply(SUBMUL, varI, meanI, meanI, corrI); + DEBUG_DUMP(varI); - apply(MUL, p1, I1, p1); + array2D &covIp = corrIp; + apply(SUBMUL, covIp, meanI, meanp, corrIp); + DEBUG_DUMP(covIp); - f_mean(p1, p1, r1); + array2D &a = varI; + apply(DIVEPSILON, a, covIp, varI); + DEBUG_DUMP(a); - apply(MUL, I1, I1, I1); + array2D &b = covIp; + apply(SUBMUL, b, a, meanI, meanp); + DEBUG_DUMP(b); - f_mean(I1, I1, r1); + array2D &meana = a; + f_mean(meana, a, r1); + DEBUG_DUMP(meana); - apply(SUBMUL, I1, meanI, meanI, I1); - apply(SUBMUL, p1, meanI, meanp, p1); - apply(DIVEPSILON, I1, p1, I1); - apply(SUBMUL, p1, I1, meanI, meanp); - } + array2D &meanb = b; + f_mean(meanb, b, r1); + DEBUG_DUMP(meanb); - f_mean(I1, I1, r1); - f_mean(p1, p1, r1); - - const int Ws = I1.width(); - const int Hs = I1.height(); - const int Wd = dst.width(); - const int Hd = dst.height(); - - const float col_scale = static_cast(Ws) / static_cast(Wd); - const float row_scale = static_cast(Hs) / static_cast(Hd); + // speedup by heckflosse67 + const int Ws = meana.width(); + const int Hs = meana.height(); + const int Wd = q.width(); + const int Hd = q.height(); + const float col_scale = float(Ws) / float(Wd); + const float row_scale = float(Hs) / float(Hd); #ifdef _OPENMP - #pragma omp parallel for if (multithread) +# pragma omp parallel for if (multithread) #endif - for (int y = 0; y < Hd; ++y) { - const float ymrs = y * row_scale; + float ymrs = y * row_scale; for (int x = 0; x < Wd; ++x) { - dst[y][x] = getBilinearValue(I1, x * col_scale, ymrs) * guide[y][x] + getBilinearValue(p1, x * col_scale, ymrs); + q[y][x] = getBilinearValue(meana, x * col_scale, ymrs) * I[y][x] + getBilinearValue(meanb, x * col_scale, ymrs); } } } + +void guidedFilterLog(float base, array2D &chan, int r, float eps, bool multithread, int subsampling) +{ +#ifdef _OPENMP +# pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < chan.height(); ++y) { + for (int x = 0; x < chan.width(); ++x) { + chan[y][x] = xlin2log(max(chan[y][x], 0.f), base); + } + } + + guidedFilter(chan, chan, chan, r, eps, multithread, subsampling); + +#ifdef _OPENMP +# pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < chan.height(); ++y) { + for (int x = 0; x < chan.width(); ++x) { + chan[y][x] = xlog2lin(max(chan[y][x], 0.f), base); + } + } +} + + } // namespace rtengine diff --git a/rtengine/guidedfilter.h b/rtengine/guidedfilter.h index af8ed0901..543bce34e 100644 --- a/rtengine/guidedfilter.h +++ b/rtengine/guidedfilter.h @@ -15,7 +15,7 @@ * 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 . + * along with RawTherapee. If not, see . */ #pragma once @@ -26,4 +26,6 @@ namespace rtengine { void guidedFilter(const array2D &guide, const array2D &src, array2D &dst, int r, float epsilon, bool multithread, int subsampling=0); +void guidedFilterLog(float base, array2D &chan, int r, float eps, bool multithread, int subsampling=0); + } // namespace rtengine diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 2bea8a263..14d51c600 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -772,7 +772,7 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall lp.slomabl = slomaskbl; lp.it = itera; lp.guidb = guidbl; - lp.epsb = 0.01f * epsbl; + lp.epsb = epsbl; lp.struexp = structexpo; lp.blurexp = blurexpo; lp.blurcol = blurcolor; @@ -6656,7 +6656,7 @@ void ImProcFunctions::DeNoise(int call, int del, float * slidL, float * slida, f } if (!adecomp.memoryAllocationFailed && aut == 0) { - if ((lp.noisecf >= 0.01f || lp.noisecc >= 0.01f) && levred == 7 && lp.noisechrodetail != 100.f) { + if ((lp.noisecf >= 0.001f || lp.noisecc >= 0.001f) && levred == 7 && lp.noisechrodetail != 100.f) { fftw_denoise(bfw, bfh, max_numblox_W, min_numblox_W, bufwv.a, Ain, numThreads, lp, 1); } } @@ -6679,7 +6679,7 @@ void ImProcFunctions::DeNoise(int call, int del, float * slidL, float * slida, f } if (!bdecomp.memoryAllocationFailed && aut == 0) { - if ((lp.noisecf >= 0.01f || lp.noisecc >= 0.01f) && levred == 7 && lp.noisechrodetail != 100.f) { + if ((lp.noisecf >= 0.001f || lp.noisecc >= 0.001f) && levred == 7 && lp.noisechrodetail != 100.f) { fftw_denoise(bfw, bfh, max_numblox_W, min_numblox_W, bufwv.b, Bin, numThreads, lp, 1); } } @@ -7023,7 +7023,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o } - if (((radius >= 1.5 * GAUSS_SKIP && lp.rad > 1.) || lp.stren > 0.1 || lp.blmet == 1 || lp.guidb > 1 || lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) && lp.blurena) { // radius < GAUSS_SKIP means no gauss, just copy of original image + if (((radius >= 1.5 * GAUSS_SKIP && lp.rad > 1.) || lp.stren > 0.1 || lp.blmet == 1 || lp.guidb > 0 || lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) && lp.blurena) { // radius < GAUSS_SKIP means no gauss, just copy of original image std::unique_ptr tmp1; std::unique_ptr tmp2; const int ystart = std::max(static_cast(lp.yc - lp.lyT) - cy, 0); @@ -7032,6 +7032,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o const int xend = std::min(static_cast(lp.xc + lp.lx) - cx, original->W); const int bfh = yend - ystart; const int bfw = xend - xstart; + bool fft = params->locallab.spots.at(sp).fftwbl; if (bfw >= mSP && bfh >= mSP) { @@ -7082,9 +7083,8 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o #ifdef _OPENMP #pragma omp parallel #endif - { - if (radius > 200.f && call == 2) //to test not optimize + if (fft && call == 2) { ImProcFunctions::fftw_convol_blur2(tmp1->L, tmp1->L, bfw, bfh, radius, 0, 0); ImProcFunctions::fftw_convol_blur2(tmp1->a, tmp1->a, bfw, bfh, radius, 0, 0); @@ -7103,7 +7103,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o #pragma omp parallel #endif { - if (radius > 200.f && call == 2) //to test not optimize + if (fft && call == 2) { ImProcFunctions::fftw_convol_blur2(tmp1->L, tmp1->L, GW, GH, radius, 0, 0); ImProcFunctions::fftw_convol_blur2(tmp1->a, tmp1->a, GW, GH, radius, 0, 0); @@ -7187,7 +7187,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o if (lp.blurmet == 0 && lp.blmet == 2) { - if (lp.guidb > 1) { + if (lp.guidb > 0) { lp.actsp = true; #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) @@ -7200,28 +7200,63 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o } } - double thresM = 0.05 * lp.epsb; - double thresm = 0.001 * lp.epsb; - softproc(bufgb.get(), tmp1.get(), 3.f * lp.guidb, bfh, bfw, thresM, thresm, 0.1f, sk, multiThread, 0); + array2D LL(bfw, bfh); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + LL[y][x] = tmp1->L[y][x]; + } + } + int r = max(int(lp.guidb / sk), 1); + + const float epsil = 0.001f * std::pow(2, - lp.epsb); + rtengine::guidedFilterLog(10.f, LL, r, epsil, multiThread); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmp1->L[y][x] = LL[y][x]; + } + } } } else if (lp.blurmet == 1 && lp.blmet == 2) { - if (lp.guidb > 1) { + if (lp.guidb > 0) { lp.actsp = true; #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif for (int y = 0; y < GH ; y++) { - for (int x = 0; x < GH; x++) { + for (int x = 0; x < GW; x++) { tmp1->L[y][x] = original->L[y][x]; tmp2->L[y][x] = original->L[y][x]; } } - - double thresM = 0.05 * lp.epsb; - double thresm = 0.001 * lp.epsb; - softproc(tmp2.get(), tmp1.get(), 3.f * lp.guidb, GH, GW, thresM, thresm, 0.1f, sk, multiThread, 0); + array2D LLI(GW, GH); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < GH ; y++) { + for (int x = 0; x < GW; x++) { + LLI[y][x] = tmp1->L[y][x]; + } + } + + int r = max(int(lp.guidb / sk), 1); + const float epsil = 0.001f * std::pow(2, - lp.epsb); + rtengine::guidedFilterLog(10.f, LLI, r, epsil, multiThread); +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < GH ; y++) { + for (int x = 0; x < GW; x++) { + tmp1->L[y][x] = LLI[y][x]; + } + } } } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index db7bc57fb..45eb8c2a4 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -792,6 +792,7 @@ enum ProcEventCode { Evlocallablapmaskbl = 762, Evlocallablaplac = 763, Evlocallabdetailthr = 764, + Evlocallabfftwbl = 765, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index d26fa33dc..f7091b1f5 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2544,8 +2544,8 @@ LocallabParams::LocallabSpot::LocallabSpot() : strength(0), sensibn(40), itera(1), - guidbl(1), - epsbl(10), + guidbl(0), + epsbl(0), blMethod("guid"), blurMethod("norm"), medMethod("33"), @@ -2554,6 +2554,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : LLmaskblcurve{(double)FCT_MinMaxCPoints, 0.0, 1.0, 0.35, 0.35, 0.50, 1.0, 0.35, 0.35, 1.0, 1.0, 0.35, 0.35}, HHmaskblcurve{(double)FCT_MinMaxCPoints, 0.0, 1.0, 0.35, 0.35, 0.50, 1.0, 0.35, 0.35, 1.0, 1.0, 0.35, 0.35}, enablMask(false), + fftwbl(false), blendmaskbl(0), radmaskbl(0.0), chromaskbl(0.0), @@ -2832,6 +2833,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && LLmaskblcurve == other.LLmaskblcurve && HHmaskblcurve == other.HHmaskblcurve && enablMask == other.enablMask + && fftwbl == other.fftwbl && blendmaskbl == other.blendmaskbl && radmaskbl == other.radmaskbl && chromaskbl == other.chromaskbl @@ -4096,6 +4098,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->locallab.spots.at(i).LLmaskblcurve, "Locallab", "LLmaskblCurve_" + std::to_string(i), spot.LLmaskblcurve, keyFile); saveToKeyfile(!pedited || pedited->locallab.spots.at(i).HHmaskblcurve, "Locallab", "HHmaskblCurve_" + std::to_string(i), spot.HHmaskblcurve, keyFile); saveToKeyfile(!pedited || pedited->locallab.spots.at(i).enablMask, "Locallab", "EnablMask_" + std::to_string(i), spot.enablMask, keyFile); + saveToKeyfile(!pedited || pedited->locallab.spots.at(i).fftwbl, "Locallab", "Fftwbl_" + std::to_string(i), spot.fftwbl, keyFile); saveToKeyfile(!pedited || pedited->locallab.spots.at(i).blendmaskbl, "Locallab", "Blendmaskbl_" + std::to_string(i), spot.blendmaskbl, keyFile); saveToKeyfile(!pedited || pedited->locallab.spots.at(i).radmaskbl, "Locallab", "Radmaskbl_" + std::to_string(i), spot.radmaskbl, keyFile); saveToKeyfile(!pedited || pedited->locallab.spots.at(i).chromaskbl, "Locallab", "Chromaskbl_" + std::to_string(i), spot.chromaskbl, keyFile); @@ -5487,6 +5490,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "LLmaskblCurve_" + std::to_string(i), pedited, spot.LLmaskblcurve, spotEdited.LLmaskblcurve); assignFromKeyfile(keyFile, "Locallab", "HHmaskblCurve_" + std::to_string(i), pedited, spot.HHmaskblcurve, spotEdited.HHmaskblcurve); assignFromKeyfile(keyFile, "Locallab", "EnablMask_" + std::to_string(i), pedited, spot.enablMask, spotEdited.enablMask); + assignFromKeyfile(keyFile, "Locallab", "Fftwbl_" + std::to_string(i), pedited, spot.fftwbl, spotEdited.fftwbl); assignFromKeyfile(keyFile, "Locallab", "Blendmaskbl_" + std::to_string(i), pedited, spot.blendmaskbl, spotEdited.blendmaskbl); assignFromKeyfile(keyFile, "Locallab", "Radmaskbl_" + std::to_string(i), pedited, spot.radmaskbl, spotEdited.radmaskbl); assignFromKeyfile(keyFile, "Locallab", "Chromaskbl_" + std::to_string(i), pedited, spot.chromaskbl, spotEdited.chromaskbl); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 2f86a6e80..cb78ff180 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1103,6 +1103,7 @@ struct LocallabParams { std::vector LLmaskblcurve; std::vector HHmaskblcurve; bool enablMask; + bool fftwbl; int blendmaskbl; double radmaskbl; double chromaskbl; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 1a1bf1008..74ee8c1cd 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -791,7 +791,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { LUMINANCECURVE, //Evlocallablapmaskcb LUMINANCECURVE, //Evlocallablapmaskbl LUMINANCECURVE, //Evlocallablaplac - LUMINANCECURVE //Evlocallabdetailthr + LUMINANCECURVE, //Evlocallabdetailthr + LUMINANCECURVE //Evlocallabfftwbl }; namespace rtengine diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index c61a2bbb5..8635e6beb 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -246,8 +246,8 @@ Locallab::Locallab(): radius(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADIUS"), 1.5, 1000.0, 0.1, 1.5))), strength(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRENGTH"), 0, 100, 1, 0))), itera(Gtk::manage(new Adjuster(M("TP_DIRPYRDENOISE_MEDIAN_PASSES"), 1, 4, 1, 1))), - guidbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GUIDBL"), 1, 300, 1, 1))), - epsbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_EPSBL"), 1, 500, 1, 10))), + guidbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GUIDBL"), 0, 1000, 1, 0))), + epsbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_EPSBL"), -10, 10, 1, 0))), sensibn(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSIBN"), 0, 100, 1, 40))), blendmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), radmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), @@ -360,6 +360,7 @@ Locallab::Locallab(): // Blur & Noise activlum(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ACTIV")))), enablMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), + fftwbl(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_FFTW2")))), //TM equiltm(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_EQUIL")))), enatmMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), @@ -1937,6 +1938,7 @@ Locallab::Locallab(): expblur->signal_button_release_event().connect_notify(sigc::bind(sigc::mem_fun(this, &Locallab::foldAllButMe), expblur)); enableblurConn = expblur->signal_enabled_toggled().connect(sigc::bind(sigc::mem_fun(this, &Locallab::enableToggled), expblur)); + fftwblConn = fftwbl->signal_toggled().connect(sigc::mem_fun(*this, &Locallab::fftwblChanged)); blMethod->append(M("TP_LOCALLAB_BLUR")); blMethod->append(M("TP_LOCALLAB_BLMED")); @@ -2076,6 +2078,7 @@ Locallab::Locallab(): ToolParamBlock* const blurrBox = Gtk::manage(new ToolParamBlock()); blurrBox->pack_start(*blMethod); + blurrBox->pack_start(*fftwbl, Gtk::PACK_SHRINK, 0); blurrBox->pack_start(*radius); blurrBox->pack_start(*strength); blurrBox->pack_start(*medMethod); @@ -3250,6 +3253,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited) pp->locallab.spots.at(pp->locallab.selspot).gammaskbl = gammaskbl->getValue(); pp->locallab.spots.at(pp->locallab.selspot).slomaskbl = slomaskbl->getValue(); pp->locallab.spots.at(pp->locallab.selspot).lapmaskbl = lapmaskbl->getValue(); + pp->locallab.spots.at(pp->locallab.selspot).fftwbl = fftwbl->get_active(); // Tone Mapping pp->locallab.spots.at(pp->locallab.selspot).exptonemap = exptonemap->getEnabled(); @@ -3545,6 +3549,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited) pe->locallab.spots.at(pp->locallab.selspot).gammaskbl = pe->locallab.spots.at(pp->locallab.selspot).gammaskbl || gammaskbl->getEditedState(); pe->locallab.spots.at(pp->locallab.selspot).slomaskbl = pe->locallab.spots.at(pp->locallab.selspot).slomaskbl || slomaskbl->getEditedState(); pe->locallab.spots.at(pp->locallab.selspot).lapmaskbl = pe->locallab.spots.at(pp->locallab.selspot).lapmaskbl || lapmaskbl->getEditedState(); + pe->locallab.spots.at(pp->locallab.selspot).fftwbl = pe->locallab.spots.at(pp->locallab.selspot).fftwbl || !fftwbl->get_inconsistent(); // Tone Mapping pe->locallab.spots.at(pp->locallab.selspot).exptonemap = pe->locallab.spots.at(pp->locallab.selspot).activlum || !exptonemap->get_inconsistent(); pe->locallab.spots.at(pp->locallab.selspot).stren = pe->locallab.spots.at(pp->locallab.selspot).stren || stren->getEditedState(); @@ -3827,6 +3832,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited) pedited->locallab.spots.at(pp->locallab.selspot).gammaskbl = pedited->locallab.spots.at(pp->locallab.selspot).gammaskbl || gammaskbl->getEditedState(); pedited->locallab.spots.at(pp->locallab.selspot).slomaskbl = pedited->locallab.spots.at(pp->locallab.selspot).slomaskbl || slomaskbl->getEditedState(); pedited->locallab.spots.at(pp->locallab.selspot).lapmaskbl = pedited->locallab.spots.at(pp->locallab.selspot).lapmaskbl || lapmaskbl->getEditedState(); + pedited->locallab.spots.at(pp->locallab.selspot).fftwbl = pedited->locallab.spots.at(pp->locallab.selspot).fftwbl || !fftwbl->get_inconsistent(); // Tone Mapping pedited->locallab.spots.at(pp->locallab.selspot).exptonemap = pedited->locallab.spots.at(pp->locallab.selspot).exptonemap || !exptonemap->get_inconsistent(); pedited->locallab.spots.at(pp->locallab.selspot).stren = pedited->locallab.spots.at(pp->locallab.selspot).stren || stren->getEditedState(); @@ -4346,6 +4352,7 @@ void Locallab::blMethodChanged() // printf("blMethodChanged\n"); if (blMethod->get_active_row_number() == 0) { radius->show(); + fftwbl->show(); strength->show(); itera->hide(); medMethod->hide(); @@ -4354,6 +4361,7 @@ void Locallab::blMethodChanged() activlum->show(); } else if (blMethod->get_active_row_number() == 1) { radius->hide(); + fftwbl->hide(); strength->hide(); itera->show(); medMethod->show(); @@ -4362,6 +4370,7 @@ void Locallab::blMethodChanged() activlum->show(); } else if (blMethod->get_active_row_number() == 2) { radius->hide(); + fftwbl->hide(); strength->hide(); itera->hide(); medMethod->hide(); @@ -4885,6 +4894,29 @@ void Locallab::enablMaskChanged() } } +void Locallab::fftwblChanged() +{ + // printf("fftwblChanged\n"); + + if (multiImage) { + if (fftwbl->get_inconsistent()) { + fftwbl->set_inconsistent(false); + fftwblConn.block(true); + fftwbl->set_active(false); + fftwblConn.block(false); + } + } + + if (getEnabled() && expblur->getEnabled()) { + if (listener) { + if (fftwbl->get_active()) { + listener->panelChanged(Evlocallabfftwbl, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallabfftwbl, M("GENERAL_DISABLED")); + } + } + } +} void Locallab::enatmMaskChanged() @@ -7550,6 +7582,7 @@ void Locallab::enableListener() medMethodConn.block(false); activlumConn.block(false); enablMaskConn.block(false); + fftwblConn.block(false); showmaskblMethodConn.block(false); // Tone Mapping enabletonemapConn.block(false); @@ -7628,6 +7661,7 @@ void Locallab::disableListener() medMethodConn.block(true); activlumConn.block(true); enablMaskConn.block(true); + fftwblConn.block(true); showmaskblMethodConn.block(true); // Tone Mapping enabletonemapConn.block(true); @@ -7872,6 +7906,7 @@ void Locallab::updateLocallabGUI(const rtengine::procparams::ProcParams* pp, con gammaskbl->setValue(pp->locallab.spots.at(index).gammaskbl); slomaskbl->setValue(pp->locallab.spots.at(index).slomaskbl); lapmaskbl->setValue(pp->locallab.spots.at(index).lapmaskbl); + fftwbl->set_active(pp->locallab.spots.at(index).fftwbl); // Tone Mapping exptonemap->setEnabled(pp->locallab.spots.at(index).exptonemap); @@ -8212,6 +8247,7 @@ void Locallab::updateLocallabGUI(const rtengine::procparams::ProcParams* pp, con gammaskbl->setEditedState(spotState->gammaskbl ? Edited : UnEdited); slomaskbl->setEditedState(spotState->slomaskbl ? Edited : UnEdited); lapmaskbl->setEditedState(spotState->lapmaskbl ? Edited : UnEdited); + fftwbl->set_inconsistent(multiImage && !spotState->fftwbl); // Tone Mapping exptonemap->set_inconsistent(!spotState->exptonemap); @@ -8545,6 +8581,7 @@ void Locallab::updateSpecificGUIState() if (blMethod->get_active_row_number() == 0) { radius->show(); + fftwbl->show(); strength->show(); itera->hide(); medMethod->hide(); @@ -8553,6 +8590,7 @@ void Locallab::updateSpecificGUIState() activlum->show(); } else if (blMethod->get_active_row_number() == 1) { radius->hide(); + fftwbl->hide(); strength->hide(); itera->show(); medMethod->show(); @@ -8561,6 +8599,7 @@ void Locallab::updateSpecificGUIState() activlum->show(); } else if (blMethod->get_active_row_number() == 2) { radius->hide(); + fftwbl->hide(); strength->hide(); itera->hide(); medMethod->hide(); diff --git a/rtgui/locallab.h b/rtgui/locallab.h index 0aa59f35d..04865fb07 100644 --- a/rtgui/locallab.h +++ b/rtgui/locallab.h @@ -321,6 +321,8 @@ private: sigc::connection activlumConn; Gtk::CheckButton* const enablMask; sigc::connection enablMaskConn; + Gtk::CheckButton* const fftwbl; + sigc::connection fftwblConn; //Tone mapping Gtk::CheckButton* const equiltm; sigc::connection equiltmConn; @@ -481,6 +483,7 @@ private: // Blur & Noise void activlumChanged(); void enablMaskChanged(); + void fftwblChanged(); //TM void equiltmChanged(); void enatmMaskChanged(); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 590961fbc..4a0e85970 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -1101,6 +1101,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).gammaskbl = locallab.spots.at(j).gammaskbl && pSpot.gammaskbl == otherSpot.gammaskbl; locallab.spots.at(j).slomaskbl = locallab.spots.at(j).slomaskbl && pSpot.slomaskbl == otherSpot.slomaskbl; locallab.spots.at(j).lapmaskbl = locallab.spots.at(j).lapmaskbl && pSpot.lapmaskbl == otherSpot.lapmaskbl; + locallab.spots.at(j).fftwbl = locallab.spots.at(j).fftwbl && pSpot.fftwbl == otherSpot.fftwbl; // Tone Mapping locallab.spots.at(j).exptonemap = locallab.spots.at(j).exptonemap && pSpot.exptonemap == otherSpot.exptonemap; locallab.spots.at(j).stren = locallab.spots.at(j).stren && pSpot.stren == otherSpot.stren; @@ -3246,6 +3247,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).enablMask = mods.locallab.spots.at(i).enablMask; } + if (locallab.spots.at(i).fftwbl) { + toEdit.locallab.spots.at(i).fftwbl = mods.locallab.spots.at(i).fftwbl; + } + if (locallab.spots.at(i).blendmaskbl) { toEdit.locallab.spots.at(i).blendmaskbl = mods.locallab.spots.at(i).blendmaskbl; } @@ -4843,6 +4848,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : LLmaskblcurve(v), HHmaskblcurve(v), enablMask(v), + fftwbl(v), blendmaskbl(v), radmaskbl(v), chromaskbl(v), @@ -5118,6 +5124,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) LLmaskblcurve = v; HHmaskblcurve = v; enablMask = v; + fftwbl = v; blendmaskbl = v; radmaskbl = v; chromaskbl = v; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index bef35607d..477fb134f 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -513,6 +513,7 @@ public: bool LLmaskblcurve; bool HHmaskblcurve; bool enablMask; + bool fftwbl; bool blendmaskbl; bool radmaskbl; bool chromaskbl;