diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 527219713..c2468fc65 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -258,7 +258,7 @@ public: //3 functions from Alberto Griggio, adapted J.Desmis 2019 void filmGrain(Imagefloat *rgb, int isogr, int strengr, int scalegr, int bfw, int bfh); - void log_encode(Imagefloat *rgb, struct local_params & lp, float scale, bool multiThread); + void log_encode(Imagefloat *rgb, struct local_params & lp, float scale, bool multiThread, int bfw, int bfh); void getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg, float *blackev, float *whiteev, bool *Autogr, int fw, int fh, float xsta, float xend, float ysta, float yend, int SCALE); void MSRLocal(int call, int sp, bool fftw, int lum, float** reducDE, LabImage * bufreti, LabImage * bufmask, LabImage * buforig, LabImage * buforigmas, float** luminance, float** templ, const float* const *originalLuminance, diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index d57856bf5..d8afea4a3 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -1309,7 +1309,7 @@ float find_gray(float source_gray, float target_gray) // basic log encoding taken from ACESutil.Lin_to_Log2, from // https://github.com/ampas/aces-dev // (as seen on pixls.us) -void ImProcFunctions::log_encode(Imagefloat *rgb, struct local_params & lp, float scale, bool multiThread) +void ImProcFunctions::log_encode(Imagefloat *rgb, struct local_params & lp, float scale, bool multiThread, int bfw, int bfh) { /* J.Desmis 12 2019 small adaptations to local adjustements @@ -1380,15 +1380,16 @@ void ImProcFunctions::log_encode(Imagefloat *rgb, struct local_params & lp, floa // } }; - const int detail = float(max(lp.detail, 0)) / scale + 0.5f; - - if (detail == 0) { + const int detail2 = float(max(lp.detail, 0)) / scale + 0.5f; + const int detail = lp.detail; + const int W = rgb->getWidth(), H = rgb->getHeight(); + if (detail == 0) {//no preser contrast #ifdef _OPENMP # pragma omp parallel for if (multiThread) #endif - for (int y = 0; y < rgb->getHeight(); ++y) { - for (int x = 0; x < rgb->getWidth(); ++x) { + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { float r = rgb->r(y, x); float g = rgb->g(y, x); float b = rgb->b(y, x); @@ -1411,7 +1412,8 @@ void ImProcFunctions::log_encode(Imagefloat *rgb, struct local_params & lp, floa rgb->b(y, x) = b; } } - } else { + } else if (detail > 1) {//old process ==>2 + const int W = rgb->getWidth(), H = rgb->getHeight(); array2D tmp(W, H); #ifdef _OPENMP @@ -1424,8 +1426,8 @@ void ImProcFunctions::log_encode(Imagefloat *rgb, struct local_params & lp, floa } } - const float epsilon = 0.01f + 0.002f * max(detail - 3, 0); - guidedFilterLog(10.f, tmp, detail, epsilon, multiThread); + const float epsilon = 0.01f + 0.002f * max(detail2 - 3, 0); + guidedFilterLog(10.f, tmp, detail2, epsilon, multiThread); #ifdef _OPENMP # pragma omp parallel for if (multiThread) @@ -1448,7 +1450,49 @@ void ImProcFunctions::log_encode(Imagefloat *rgb, struct local_params & lp, floa } } } + } else if (detail == 1) {//preserve local contrast + + array2D Y(W, H); + { + constexpr float base_posterization = 20.f; + array2D Y2(W, H); + +#ifdef _OPENMP +# pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + Y2[y][x] = norm(rgb->r(y, x), rgb->g(y, x), rgb->b(y, x)) / 65535.f; + float l = xlogf(std::max(Y2[y][x], 1e-9f)); + float ll = round(l * base_posterization) / base_posterization; + Y[y][x] = xexpf(ll); + } + } + const float radius = max(max(bfw, W), max(bfh, H)) / 30.f; + const float epsilon = 0.005f; + rtengine::guidedFilter(Y2, Y, Y, radius, epsilon, multiThread); + } + +#ifdef _OPENMP +# pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + float &r = rgb->r(y, x); + float &g = rgb->g(y, x); + float &b = rgb->b(y, x); + float t = Y[y][x]; + if (t > noise) { + float c = apply(t, false); + float f = c / t; + r *= f; + g *= f; + b *= f; + } + } + } } + } @@ -9279,7 +9323,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o Imagefloat *tmpImage = nullptr; tmpImage = new Imagefloat(bfw, bfh); lab2rgb(*bufexpfin, *tmpImage, params->icm.workingProfile); - log_encode(tmpImage, lp, float (sk), multiThread); + log_encode(tmpImage, lp, float (sk), multiThread, bfw, bfh); rgb2lab(*tmpImage, *bufexpfin, params->icm.workingProfile); diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index 937ef26e4..4d40281ac 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -639,7 +639,7 @@ sourceGray(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOURCE_GRAY"), 1.0, 100.0, 0. targetGray(Gtk::manage(new Adjuster(M("TP_LOCALLAB_TARGET_GRAY"), 5.0, 80.0, 0.1, 18.0))), blackEv(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLACK_EV"), -16.0, 0.0, 0.1, -5.0))), whiteEv(Gtk::manage(new Adjuster(M("TP_LOCALLAB_WHITE_EV"), 0.0, 32.0, 0.1, 10.0))), -detail(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DETAIL"), 0, 5, 1, 1))), +detail(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DETAIL"), 0, 2, 1, 1))), sensilog(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSILOG"), 0, 100, 1, 50))), baselog(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BASELOG"), 1.3, 8., 0.05, 2., Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))),