diff --git a/rtdata/languages/default b/rtdata/languages/default index 60fe106e7..b518b568d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2220,12 +2220,13 @@ TP_LOCALLAB_CLARIFRA;Clarity & Sharp mask - Blend images TP_LOCALLAB_CLARILRES;Merge Luma TP_LOCALLAB_CLARISOFT;Soft radius TP_LOCALLAB_CLARITYML;Clarity -TP_LOCALLAB_CLARI_TOOLTIP;Under or equal level wavelet 4, 'Sharp mask' is enabled.\nAbove level wavelet 5 'Clarity' is enabled. +TP_LOCALLAB_CLARI_TOOLTIP;Under or equal level wavelet 4, 'Sharp mask' is enabled.\nAbove level wavelet 5 'Clarity' is enabled.\nUsefull if you use 'Level dynamic Range Compression' TP_LOCALLAB_CLIPTM;Clip Restored datas (gain) TP_LOCALLAB_COFR;Color & Light - Small defects TP_LOCALLAB_COL_NAME;Name TP_LOCALLAB_COL_VIS;Status TP_LOCALLAB_COMPFRA;Levels Dynamic Range Compression +TP_LOCALLAB_COMPFRAME_TOOLTIP;Allows special effects. You can reduce artifacts with 'Clarity & Sharp mask - Blend Images".\nUses a lot of resources TP_LOCALLAB_COMPLEX_METHOD;Software Complexity TP_LOCALLAB_COMPLEX_TOOLTIP; Allow user to select Local adjustements rubrics. TP_LOCALLAB_CONTCOL;Contrast threshold Mask Blur diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 3387125d0..0addd1c5d 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -737,7 +737,7 @@ void Crop::update(int todo) if (need_fattal) { parent->ipf.dehaze(f, params.dehaze); - parent->ipf.ToneMapFattal02(f, params.fattal, 3, false, nullptr, 0, 0); + parent->ipf.ToneMapFattal02(f, params.fattal, 3, 0, nullptr, 0, 0); } // crop back to the size expected by the rest of the pipeline diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 0c9797a3c..adef1c550 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -637,7 +637,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } ipf.dehaze(orig_prev, params->dehaze); - ipf.ToneMapFattal02(orig_prev, params->fattal, 3, false, nullptr, 0, 0); + ipf.ToneMapFattal02(orig_prev, params->fattal, 3, 0, nullptr, 0, 0); if (oprevi != orig_prev) { delete oprevi; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 4ee3ba8ed..ac6e66fe1 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -411,7 +411,7 @@ public: void dehaze(Imagefloat *rgb, const procparams::DehazeParams &dehazeParams); void dehazeloc(Imagefloat *rgb, const procparams::DehazeParams &dehazeParams); - void ToneMapFattal02(Imagefloat *rgb, const procparams::FattalToneMappingParams &fatParams, int detail_level, bool Lalone, float **Lum, int WW, int HH); + void ToneMapFattal02(Imagefloat *rgb, const procparams::FattalToneMappingParams &fatParams, int detail_level, int Lalone, float **Lum, int WW, int HH); void localContrast(LabImage *lab, float **destination, const procparams::LocalContrastParams &localContrastParams, bool fftwlc, double scale); void colorToningLabGrid(LabImage *lab, int xstart, int xend, int ystart, int yend, bool MultiThread); // void shadowsHighlights(LabImage *lab); diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index d00cd42f6..bb1ffca92 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -4052,7 +4052,7 @@ void ImProcFunctions::maskcalccol(int call, bool invmask, bool pde, int bfw, int Imagefloat *tmpImagefat = nullptr; tmpImagefat = new Imagefloat(bfw, bfh); lab2rgb(*bufmaskblurcol, *tmpImagefat, params->icm.workingProfile); - ToneMapFattal02(tmpImagefat, fatParams, nlev, false, nullptr, 0, 0); + ToneMapFattal02(tmpImagefat, fatParams, nlev, 0, nullptr, 0, 0); rgb2lab(*tmpImagefat, *bufmaskblurcol, params->icm.workingProfile); delete tmpImagefat; } @@ -6736,6 +6736,8 @@ void ImProcFunctions::fftw_tile_blur(int GW, int GH, int tilssize, int max_numbl fftwf_destroy_plan(plan_backward_blox[1]); fftwf_cleanup(); } + + void ImProcFunctions::wavcontrast4(float ** tmp, float contrast, float fatres, float radblur, float radlevblur, int bfw, int bfh, int level_bl, int level_hl, int level_br, int level_hr, int sk, bool numThreads, const LocwavCurve & locwavCurve, bool & locwavutili, const LocwavCurve & loclevwavCurve, bool & loclevwavutili, bool wavcurvelev, const LocwavCurve & locconwavCurve, bool & locconwavutili, bool wavcurvecon, @@ -6743,7 +6745,7 @@ void ImProcFunctions::wavcontrast4(float ** tmp, float contrast, float fatres, f float sigm, int & maxlvl, float fatdet, float fatanch) { wavelet_decomposition *wdspot = new wavelet_decomposition(tmp[0], bfw, bfh, level_br, 1, sk, numThreads, 6); - + //first decomposition for compress dynamic range positive values and other process if (wdspot->memoryAllocationFailed) { return; } @@ -6771,7 +6773,7 @@ void ImProcFunctions::wavcontrast4(float ** tmp, float contrast, float fatres, f } } - ToneMapFattal02(nullptr, fatParams, 3, true, bufl, W_L, H_L); + ToneMapFattal02(nullptr, fatParams, 3, 1, bufl, W_L, H_L); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) @@ -6944,8 +6946,6 @@ void ImProcFunctions::wavcontrast4(float ** tmp, float contrast, float fatres, f float blow = 0.f; if (level_hl != level_bl) { - // alow = 0.5f / (level_hl - level_bl);//to test with 0.5 - // blow = 0.5f -alow * level_bl; alow = 1.f / (level_hl - level_bl); blow = -alow * level_bl; } @@ -6954,8 +6954,6 @@ void ImProcFunctions::wavcontrast4(float ** tmp, float contrast, float fatres, f float bhigh = 0.f; if (level_hr != level_br) { - // ahigh = 0.5f / (level_hr - level_br);//to test with 0.5 - // bhigh = 0.5f -ahigh * level_br; ahigh = 1.f / (level_hr - level_br); bhigh = -ahigh * level_br; } @@ -6983,25 +6981,34 @@ void ImProcFunctions::wavcontrast4(float ** tmp, float contrast, float fatres, f } } + //fill array templevel with wavelet value level dir for (int dir = 1; dir < 4; dir++) { for (int level = level_bl; level < maxlvl; ++level) { int W_L = wdspot->level_W(level); int H_L = wdspot->level_H(level); float **wav_L = wdspot->level_coeffs(level); + // float **wav_LN = wdspotneg->level_coeffs(level); for (int y = 0; y < H_L; y++) { for (int x = 0; x < W_L; x++) { float val = wav_L[dir][y * W_L + x]; - templevel[dir - 1][level][y][x] = val; + +// if (val >= 0.f) { + templevel[dir - 1][level][y][x] = val; +// } else { +// templevel[dir - 1][level][y][x] = 0.f; +// } } } } } -//Compress dynamic range + +//Compress dynamic range positives values decomposition if (wavcurvecomp) { - printf("Dynamic Range levels\n"); +// printf("Dynamic Range levels\n"); + for (int dir = 1; dir < 4; dir++) { for (int level = level_bl; level < maxlvl; ++level) { int W_L = wdspot->level_W(level); @@ -7012,7 +7019,7 @@ void ImProcFunctions::wavcontrast4(float ** tmp, float contrast, float fatres, f float klev = (loccompwavCurve[level * 50.f]); fatParams.amount = 50.f * klev; { - ToneMapFattal02(nullptr, fatParams, 3, true, templevel[dir - 1][level], W_L, H_L); + ToneMapFattal02(nullptr, fatParams, 3, 1, templevel[dir - 1][level], W_L, H_L); } } } @@ -7023,8 +7030,8 @@ void ImProcFunctions::wavcontrast4(float ** tmp, float contrast, float fatres, f //blur level and dir if (wavcurvelev && radlevblur > 0.f) { - printf("Blur levels\n"); - +// printf("Blur levels\n"); + for (int dir = 1; dir < 4; dir++) { for (int level = level_bl; level < maxlvl; ++level) { int W_L = wdspot->level_W(level); @@ -7058,26 +7065,29 @@ void ImProcFunctions::wavcontrast4(float ** tmp, float contrast, float fatres, f } - //free memory - for (int i = 0; i < dir; i++) { - for (int j = 0; j < leve; j++) { - for (int l = 0; l < H_L; l++) { - delete [] templevel[i][j][l]; + //free memory templevel + if (wavcurvelev || wavcurvecomp) { + for (int i = 0; i < dir; i++) { + for (int j = 0; j < leve; j++) { + for (int l = 0; l < H_L; l++) { + delete [] templevel[i][j][l]; + } } } - } - for (int i = 0; i < dir; i++) { - for (int j = 0; j < leve; j++) { - delete [] templevel[i][j]; + for (int i = 0; i < dir; i++) { + for (int j = 0; j < leve; j++) { + delete [] templevel[i][j]; + } } - } - for (int i = 0; i < dir; i++) { - delete [] templevel[i]; - } + for (int i = 0; i < dir; i++) { + delete [] templevel[i]; + } - delete [] templevel; + delete [] templevel; + + } } if (locwavCurve && locwavutili) { @@ -7149,9 +7159,112 @@ void ImProcFunctions::wavcontrast4(float ** tmp, float contrast, float fatres, f } } } - + //reconstruct all and compress dynamic range positive wdspot->reconstruct(tmp[0], 1.f); delete wdspot; + +//compress dynamic range negative in case of - seems no need + float ****templevelN = nullptr; + bool negativ = false; + + if (wavcurvecomp && negativ) { + array2D tmpneg(bfw, bfh); + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + tmpneg[y][x] = tmp[y][x]; + } + } + + wavelet_decomposition *wdspotneg = new wavelet_decomposition(tmpneg[0], bfw, bfh, level_br, 1, sk, numThreads, 6); + + if (wdspotneg->memoryAllocationFailed) { + return; + } + maxlvl = wdspotneg->maxlevel(); + int W_L = wdspotneg->level_W(0); + int H_L = wdspotneg->level_H(0); + + fatParams.enabled = wavcurvecomp; + + templevelN = new float***[dir]; + + //allocate memory for 3 DIR n levels, H_L, W_L + for (int d = 0; d < dir; d++) { + templevelN[d] = new float**[leve]; + + for (int k = 0; k < leve; k++) { + templevelN[d][k] = new float*[H_L]; + + for (int i = 0; i < H_L; i++) { + templevelN[d][k][i] = new float[W_L]; + } + } + } + + + for (int dir = 1; dir < 4; dir++) { + for (int level = level_bl; level < maxlvl; ++level) { + int W_L = wdspotneg->level_W(level); + int H_L = wdspotneg->level_H(level); + float **wav_LN = wdspotneg->level_coeffs(level); + + for (int y = 0; y < H_L; y++) { + for (int x = 0; x < W_L; x++) { + float valN = wav_LN[dir][y * W_L + x]; + + templevelN[dir - 1][level][y][x] = -valN; + + } + } + } + } + + for (int dir = 1; dir < 4; dir++) { + for (int level = level_bl; level < maxlvl; ++level) { + int W_L = wdspotneg->level_W(level); + int H_L = wdspotneg->level_H(level); + + if (loccompwavCurve && loccompwavutili) { + + float klev = (loccompwavCurve[level * 50.f]); + fatParams.amount = 50.f * klev; + { + ToneMapFattal02(nullptr, fatParams, 3, -1, templevelN[dir - 1][level], W_L, H_L); + } + } + } + } + + for (int i = 0; i < dir; i++) { + for (int j = 0; j < leve; j++) { + for (int l = 0; l < H_L; l++) { + delete [] templevelN[i][j][l]; + } + } + } + + for (int i = 0; i < dir; i++) { + for (int j = 0; j < leve; j++) { + delete [] templevelN[i][j]; + } + } + + for (int i = 0; i < dir; i++) { + delete [] templevelN[i]; + } + + delete [] templevelN; + + wdspotneg->reconstruct(tmpneg[0], 1.f); + + for (int y = 0; y < bfh; y++) { + for (int x = 0; x < bfw; x++) { + tmp[y][x] = tmpneg[y][x]; + } + } + + delete wdspotneg; + } } @@ -12286,7 +12399,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o int nlev = params->locallab.spots.at(sp).fatlevel; tmpImagefat = new Imagefloat(bfwr, bfhr); lab2rgb(*bufexpfin, *tmpImagefat, params->icm.workingProfile); - ToneMapFattal02(tmpImagefat, fatParams, nlev, false, nullptr, 0, 0); + ToneMapFattal02(tmpImagefat, fatParams, nlev, 0, nullptr, 0, 0); rgb2lab(*tmpImagefat, *bufexpfin, params->icm.workingProfile); delete tmpImagefat; } diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 470023135..0a2d21d9d 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -1244,7 +1244,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.firstAnalysis (baseImg, params, hist16); ipf.dehaze(baseImg, params.dehaze); - ipf.ToneMapFattal02(baseImg, params.fattal, 3, false, nullptr, 0, 0); + ipf.ToneMapFattal02(baseImg, params.fattal, 3, 0, nullptr, 0, 0); // perform transform if (ipf.needsTransform()) { diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 0228ac805..2d0d4c356 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -872,7 +872,7 @@ private: ipf.firstAnalysis(baseImg, params, hist16); ipf.dehaze(baseImg, params.dehaze); - ipf.ToneMapFattal02(baseImg, params.fattal, 3, false, nullptr, 0, 0); + ipf.ToneMapFattal02(baseImg, params.fattal, 3, 0, nullptr, 0, 0); // perform transform (excepted resizing) if (ipf.needsTransform()) { diff --git a/rtengine/tmo_fattal02.cc b/rtengine/tmo_fattal02.cc index 3703d78de..79a2e1335 100644 --- a/rtengine/tmo_fattal02.cc +++ b/rtengine/tmo_fattal02.cc @@ -1056,7 +1056,7 @@ inline int find_fast_dim(int dim) } // namespace -void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, const FattalToneMappingParams &fatParams, int detail_level, bool Lalone, float **Lum, int WW, int HH) +void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, const FattalToneMappingParams &fatParams, int detail_level, int Lalone, float **Lum, int WW, int HH) { if (!fatParams.enabled) { return; @@ -1082,14 +1082,13 @@ void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, const FattalToneMappingPa int w; int h; - if(Lalone) { + if(Lalone != 0) { w = WW; h = HH; } else { w = rgb->getWidth(); h = rgb->getHeight(); } - Array2Df Yr(w, h); @@ -1104,7 +1103,7 @@ void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, const FattalToneMappingPa for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { - if(Lalone) { + if(Lalone != 0) { Yr(x, y) = std::max(2.f * Lum[y][x], min_luminance); // clip really black pixels } else { Yr(x, y) = std::max(luminance(rgb->r(y, x), rgb->g(y, x), rgb->b(y, x), ws), min_luminance); // clip really black pixels @@ -1172,7 +1171,7 @@ void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, const FattalToneMappingPa float Y = std::max(Yr(x, y), epsilon); float l = std::max(L(xx, yy), epsilon) * (scale / Y); - if(!Lalone) { + if(Lalone == 0) { rgb->r(y, x) *= l; rgb->g(y, x) *= l; rgb->b(y, x) *= l; @@ -1181,7 +1180,11 @@ void ImProcFunctions::ToneMapFattal02(Imagefloat *rgb, const FattalToneMappingPa assert(std::isfinite(rgb->g(y, x))); assert(std::isfinite(rgb->b(y, x))); } else { - Lum[y][x] *= (0.5f * l); + if(Lalone == 1) { + Lum[y][x] *= (0.5f * l); + } else if(Lalone == -1){ + Lum[y][x] *= (-0.5f * l); + } } } } diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index e673d852a..b50720497 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -2930,6 +2930,9 @@ pe(nullptr) blurcontBox->pack_start(*blurlevelFrame); expcontrastpyr->add(*blurcontBox, false); + if (showtooltip) { + fatdet->set_tooltip_text(M("TP_LOCALLAB_COMPFRAME_TOOLTIP")); + } ToolParamBlock* const contrastBox = Gtk::manage(new ToolParamBlock());