From e03646fc5b0b8746eed1540ddb5137691565dba1 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 19 Mar 2018 01:34:15 +0100 Subject: [PATCH 1/3] Code review and speedup for ImProcFunctions::vibrance(), also fixes #4443 --- rtengine/color.cc | 159 ++++++++++++++++- rtengine/color.h | 2 + rtengine/ipvibrance.cc | 384 ++++++++++++++++------------------------- 3 files changed, 298 insertions(+), 247 deletions(-) diff --git a/rtengine/color.cc b/rtengine/color.cc index 3be412b6d..5685a72cc 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -2290,6 +2290,46 @@ void Color::AllMunsellLch(bool lumaMuns, float Lprov1, float Loldd, float HH, fl } +/* + * AllMunsellLch correction + * Copyright (c) 2012 Jacques Desmis + * + * This function corrects the color (hue) for changes in chromaticity and luminance + * to use in a "for" or "do while" statement + * + * Parameters: + * float Lprov1: luminance + * float HH: hue before + * float Chprov1, CC : chroma after and before + * float coorectionHuechroma : correction Hue for chromaticity (saturation) + */ +void Color::AllMunsellLch(float Lprov1, float HH, float Chprov1, float CC, float &correctionHuechroma) +{ + + float correctionHue = 0.f, correctionHueLum = 0.f; + bool correctL; + + if(CC >= 6.f && CC < 140.f) { //if C > 140 we say C=140 (only in Prophoto ...with very large saturation) + static const float huelimit[8] = { -2.48f, -0.55f, 0.44f, 1.52f, 1.87f, 3.09f, -0.27f, 0.44f}; //limits hue of blue-purple, red-yellow, green-yellow, red-purple + + if (Chprov1 > 140.f) { + Chprov1 = 139.f; //limits of LUTf + } + + Chprov1 = rtengine::max(Chprov1, 6.f); + + for(int zo = 1; zo <= 4; zo++) { + if(HH > huelimit[2 * zo - 2] && HH < huelimit[2 * zo - 1]) { + //zone=zo; + correctL = false; + MunsellLch (Lprov1, HH, Chprov1, CC, correctionHue, zo, correctionHueLum, correctL); //munsell chroma correction + correctionHuechroma = correctionHue; //preserve + break; + } + } + } +} + /* * GamutLchonly correction * Copyright (c)2012 Jacques Desmis and Jean-Christophe Frisch @@ -2386,7 +2426,7 @@ void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, flo } inGamut = false; - } else if (!isHLEnabled && (R > ClipLevel || G > ClipLevel || B > ClipLevel)) { + } else if (!isHLEnabled && rtengine::max(R, G, B) > ClipLevel && rtengine::min(R, G, B) <= ClipLevel) { // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut #ifdef _DEBUG @@ -2511,7 +2551,7 @@ void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chpr } inGamut = false; - } else if (!isHLEnabled && (R > ClipLevel || G > ClipLevel || B > ClipLevel)) { + } else if (!isHLEnabled && rtengine::max(R, G, B) > ClipLevel && rtengine::min(R, G, B) <= ClipLevel) { // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut #ifdef _DEBUG @@ -2535,6 +2575,109 @@ void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chpr //end first gamut control } +/* + * GamutLchonly correction + * Copyright (c)2012 Jacques Desmis and Jean-Christophe Frisch + * + * This function puts the data (Lab) in the gamut of "working profile": + * it returns the corrected values of the chromaticity and luminance + * + * float HH : hue + * float2 sincosval : sin and cos of HH + * float Lprov1 : input luminance value, sent back corrected + * float Chprov1: input chroma value, sent back corrected + * float wip : working profile + * bool isHLEnabled : if "highlight reconstruction " is enabled + * float coef : a float number between [0.95 ; 1.0[... the nearest it is from 1.0, the more precise it will be... and the longer too as more iteration will be necessary) + */ +void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &saturation, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef) +{ + constexpr float ClipLevel = 1.f; + bool inGamut; + float R, G, B; + + do { + inGamut = true; + + float aprov1 = Chprov1 * sincosval.y; + float bprov1 = Chprov1 * sincosval.x; + + //conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction + float fy = c1By116 * Lprov1 + c16By116; + float fx = 0.002f * aprov1 + fy; + float fz = fy - 0.005f * bprov1; + + float x_ = f2xyz(fx) * D50x; + float z_ = f2xyz(fz) * D50z; + float y_ = (Lprov1 > epskap) ? fy * fy * fy : Lprov1 / kappaf; + + xyz2rgb(x_, y_, z_, R, G, B, wip); + + // gamut control before saturation to put Lab values in future gamut, but not RGB + if (rtengine::min(R, G, B) < 0.f) { + + Lprov1 = rtengine::max(Lprov1, 0.1f); + + //gamut for L with ultra blue : we can improve the algorithm ... thinner, and other color ??? + if(HH < -0.9f && HH > -1.55f ) {//ultra blue + if(Chprov1 > 160.f) if (Lprov1 < 5.f) { + Lprov1 = 5.f; //very very very very high chroma + } + + if(Chprov1 > 140.f) if (Lprov1 < 3.5f) { + Lprov1 = 3.5f; + } + + if(Chprov1 > 120.f) if (Lprov1 < 2.f) { + Lprov1 = 2.f; + } + + if(Chprov1 > 105.f) if (Lprov1 < 1.f) { + Lprov1 = 1.f; + } + + if(Chprov1 > 90.f) if (Lprov1 < 0.7f) { + Lprov1 = 0.7f; + } + + if(Chprov1 > 50.f) if (Lprov1 < 0.5f) { + Lprov1 = 0.5f; + } + + if(Chprov1 > 20.f) if (Lprov1 < 0.4f) { + Lprov1 = 0.4f; + } + } + + Chprov1 *= higherCoef; // decrease the chromaticity value + + if (Chprov1 <= 3.f) { + Lprov1 += lowerCoef; + } + + inGamut = false; + } else if (!isHLEnabled && rtengine::max(R, G, B) > ClipLevel && rtengine::min(R, G, B) <= ClipLevel) { + + // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut + + if (Lprov1 > 99.999f) { + Lprov1 = 99.98f; + } + + Chprov1 *= higherCoef; + + if (Chprov1 <= 3.f) { + Lprov1 -= lowerCoef; + } + + inGamut = false; + } + } while (!inGamut); + + saturation = 1.f - (rtengine::min(R, G, B) / rtengine::max(R, G, B)); + //end first gamut control +} + #ifdef _DEBUG void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb) @@ -2585,7 +2728,7 @@ void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const } inGamut = false; - } else if (!isHLEnabled && (R > ClipLevel || G > ClipLevel || B > ClipLevel)) { + } else if (!isHLEnabled && rtengine::max(R, G, B) > ClipLevel && rtengine::min(R, G, B) <= ClipLevel) { // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut #ifdef _DEBUG @@ -4160,12 +4303,12 @@ void Color::SkinSat (float lum, float hue, float chrom, float &satreduc) { // to be adapted...by tests - float reduction = 0.3f; // use "reduction" for "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1 - float extendedreduction = 0.4f; // use "extendedreduction" for wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation - float extendedreduction2 = 0.6f; // use "extendedreduction2" for wide area for transition + constexpr float reduction = 0.3f; // use "reduction" for "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1 + constexpr float extendedreduction = 0.4f; // use "extendedreduction" for wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation + constexpr float extendedreduction2 = 0.6f; // use "extendedreduction2" for wide area for transition - float C9 = 8.0, C8 = 15.0, C7 = 12.0, C4 = 7.0, C3 = 5.0, C2 = 5.0, C1 = 5.0; - float H9 = 0.05, H8 = 0.25, H7 = 0.1, H4 = 0.02, H3 = 0.02, H2 = 0.1, H1 = 0.1, H10 = -0.2, H11 = -0.2; //H10 and H11 are curious...H11=-0.8 ?? + constexpr float C9 = 8.f, C8 = 15.f, C7 = 12.f, C4 = 7.f, C3 = 5.f, C2 = 5.f, C1 = 5.f; + constexpr float H9 = 0.05f, H8 = 0.25f, H7 = 0.1f, H4 = 0.02f, H3 = 0.02f, H2 = 0.1f, H1 = 0.1f, H10 = -0.2f, H11 = -0.2f; //H10 and H11 are curious...H11=-0.8 ?? if (lum >= 85.f) { if((hue > (0.78f - H9) && hue < (1.18f + H9)) && (chrom > 8.f && chrom < (14.f + C9))) { diff --git a/rtengine/color.h b/rtengine/color.h index 9775e0ecb..007df5661 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -1380,6 +1380,7 @@ public: #else static void AllMunsellLch (bool lumaMuns, float Lprov1, float Loldd, float HH, float Chprov1, float CC, float &correctionHueChroma, float &correctlum); #endif + static void AllMunsellLch (float Lprov1, float HH, float Chprov1, float CC, float &correctionHueChroma); /** @@ -1412,6 +1413,7 @@ public: static void gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef); static void gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef); #endif + static void gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chprov1, float &saturation, const float wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef); /** diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index d7fb0da97..b5d711c7c 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -19,7 +19,6 @@ */ #include "rt_math.h" -//#include #include "rtengine.h" #include "improcfun.h" @@ -28,7 +27,8 @@ #include "../rtgui/thresholdselector.h" #include "curves.h" #include "color.h" - +#define BENCHMARK +#include "StopWatch.h" #ifdef _OPENMP #include #endif @@ -41,8 +41,6 @@ namespace rtengine using namespace procparams; -#define SAT(a,b,c) ((float)max(a,b,c)-(float)min(a,b,c))/(float)max(a,b,c) - extern const Settings* settings; void fillCurveArrayVib (DiagonalCurve* diagCurve, LUTf &outCurve) @@ -72,6 +70,7 @@ void fillCurveArrayVib (DiagonalCurve* diagCurve, LUTf &outCurve) */ void ImProcFunctions::vibrance (LabImage* lab) { + BENCHFUN if (!params->vibrance.enabled) { return; } @@ -101,42 +100,23 @@ void ImProcFunctions::vibrance (LabImage* lab) const int width = lab->W; const int height = lab->H; -#ifdef _DEBUG - MyTime t1e, t2e; - t1e.set(); - int negat = 0, moreRGB = 0, negsat = 0, moresat = 0; -#endif - // skin hue curve // I use diagonal because I think it's better - LUTf skin_curve (65536, 0); - if (skinCurveIsSet) { - fillCurveArrayVib (dcurve, skin_curve); - } - - if (dcurve) { - delete dcurve; - dcurve = nullptr; - } - - -// skin_curve.dump("skin_curve"); - - const float chromaPastel = float (params->vibrance.pastels) / 100.0f; - const float chromaSatur = float (params->vibrance.saturated) / 100.0f; - const float p00 = 0.07f; - const float limitpastelsatur = (static_cast(params->vibrance.psthreshold.getTopLeft()) / 100.0f) * (1.0f - p00) + p00; - const float maxdp = (limitpastelsatur - p00) / 4.0f; - const float maxds = (1.0 - limitpastelsatur) / 4.0f; + const float chromaPastel = params->vibrance.pastels / 100.f; + const float chromaSatur = params->vibrance.saturated / 100.f; + constexpr float p00 = 0.07f; + const float limitpastelsatur = (static_cast(params->vibrance.psthreshold.getTopLeft()) / 100.f) * (1.f - p00) + p00; + const float maxdp = (limitpastelsatur - p00) / 4.f; + const float maxds = (1.f - limitpastelsatur) / 4.f; const float p0 = p00 + maxdp; - const float p1 = p00 + 2.0f * maxdp; - const float p2 = p00 + 3.0f * maxdp; + const float p1 = p00 + 2.f * maxdp; + const float p2 = p00 + 3.f * maxdp; const float s0 = limitpastelsatur + maxds; - const float s1 = limitpastelsatur + 2.0f * maxds; - const float s2 = limitpastelsatur + 3.0f * maxds; - const float transitionweighting = static_cast(params->vibrance.psthreshold.getBottomLeft()) / 100.0f; - float chromamean = 0.0f; + const float s1 = limitpastelsatur + 2.f * maxds; + const float s2 = limitpastelsatur + 3.f * maxds; + const float transitionweighting = static_cast(params->vibrance.psthreshold.getBottomLeft()) / 100.f; + float chromamean = 0.f; if (chromaPastel != chromaSatur) { //if sliders pastels and saturated are different: transition with a double linear interpolation: between p2 and limitpastelsatur, and between limitpastelsatur and s0 @@ -144,9 +124,9 @@ void ImProcFunctions::vibrance (LabImage* lab) chromamean = maxdp * (chromaSatur - chromaPastel) / (s0 - p2) + chromaPastel; // move chromaMean up or down depending on transitionCtrl - if (transitionweighting > 0.0f) { + if (transitionweighting > 0.f) { chromamean = (chromaSatur - chromamean) * transitionweighting + chromamean; - } else if (transitionweighting < 0.0f) { + } else if (transitionweighting < 0.f) { chromamean = (chromamean - chromaPastel) * transitionweighting + chromamean; } } @@ -157,13 +137,26 @@ void ImProcFunctions::vibrance (LabImage* lab) const float chromaSatur_a = (chromaSatur - chromamean) / (s0 - limitpastelsatur); const float chromaSatur_b = chromaSatur - chromaSatur_a * s0; - const float dhue = 0.15f; //hue transition - const float dchr = 20.0f; //chroma transition - const float skbeg = -0.05f; //begin hue skin - const float skend = 1.60f; //end hue skin - const float xx = 0.5f; //soft : between 0.3 and 1.0 - const float ask = 65535.0f / (skend - skbeg); - const float bsk = -skbeg * ask; + constexpr float dhue = 0.15f; //hue transition + constexpr float dchr = 20.f; //chroma transition + constexpr float skbeg = -0.05f; //begin hue skin + constexpr float skend = 1.60f; //end hue skin + constexpr float xx = 0.5f; //soft : between 0.3 and 1.0 + constexpr float ask = 65535.f / (skend - skbeg); + constexpr float bsk0 = -skbeg; + constexpr float bsk = -skbeg * ask; + + LUTf skin_curve (65536, 0); + + if (skinCurveIsSet) { + fillCurveArrayVib (dcurve, skin_curve); + skin_curve /= ask; + } + + if (dcurve) { + delete dcurve; + dcurve = nullptr; + } const bool highlight = params->toneCurve.hrenabled;//Get the value if "highlight reconstruction" is activated @@ -172,139 +165,118 @@ void ImProcFunctions::vibrance (LabImage* lab) TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.working); //inverse matrix user select - const double wip[3][3] = { - {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, - {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, - {wiprof[2][0], wiprof[2][1], wiprof[2][2]} + const float wip[3][3] = { + {static_cast(wiprof[0][0]), static_cast(wiprof[0][1]), static_cast(wiprof[0][2])}, + {static_cast(wiprof[1][0]), static_cast(wiprof[1][1]), static_cast(wiprof[1][2])}, + {static_cast(wiprof[2][0]), static_cast(wiprof[2][1]), static_cast(wiprof[2][2])} }; -#ifdef _DEBUG - MunsellDebugInfo* MunsDebugInfo = nullptr; - - if (avoidcolorshift) { - MunsDebugInfo = new MunsellDebugInfo(); + if (settings->verbose) { + printf ("vibrance: p0=%1.2f p1=%1.2f p2=%1.2f s0=%1.2f s1=%1.2f s2=%1.2f\n", p0, p1, p2, s0, s1, s2); + printf (" pastel=%f satur=%f limit= %1.2f chromamean=%0.5f\n", 1.0f + chromaPastel, 1.0f + chromaSatur, limitpastelsatur, chromamean); } - #pragma omp parallel default(shared) firstprivate(lab, MunsDebugInfo) reduction(+: negat, moreRGB, negsat, moresat) if (multiThread) -#else - #pragma omp parallel default(shared) if (multiThread) -#endif + #pragma omp parallel if (multiThread) { - float sathue[5], sathue2[4]; // adjust sat in function of hue - - /* - // Fitting limitpastelsatur into the real 0.07->1.0 range - // limitpastelsatur = limitpastelsatur*(1.0f-p00) + p00; - float p0,p1,p2;//adapt limit of pyramid to psThreshold - float s0,s1,s2; - */ - -#ifdef _OPENMP - - if (settings->verbose && omp_get_thread_num() == 0) { -#else - - if (settings->verbose) { +#ifdef __SSE2__ + float HHbuffer[width] ALIGNED16; + float CCbuffer[width] ALIGNED16; #endif - printf ("vibrance: p0=%1.2f p1=%1.2f p2=%1.2f s0=%1.2f s1=%1.2f s2=%1.2f\n", p0, p1, p2, s0, s1, s2); - printf (" pastel=%f satur=%f limit= %1.2f chromamean=%0.5f\n", 1.0f + chromaPastel, 1.0f + chromaSatur, limitpastelsatur, chromamean); - } + float sathue[5], sathue2[4]; // adjust sat in function of hue #pragma omp for schedule(dynamic, 16) - for (int i = 0; i < height; i++) + for (int i = 0; i < height; i++) { +#ifdef __SSE2__ + // vectorized per row calculation of HH and CC + vfloat c327d68v = F2V(327.68f); + int k = 0; + for (; k < width - 3; k += 4) { + vfloat av = LVFU(lab->a[i][k]); + vfloat bv = LVFU(lab->b[i][k]); + STVF(HHbuffer[k], xatan2f(bv, av)); + STVF(CCbuffer[k], vsqrtf(SQRV(av) + SQRV(bv)) / c327d68v); + } + for (; k < width; k++) { + HHbuffer[k] = xatan2f (lab->b[i][k], lab->a[i][k]); + CCbuffer[k] = sqrt (SQR (lab->a[i][k]) + SQR (lab->b[i][k])) / 327.68f; + } +#endif for (int j = 0; j < width; j++) { float LL = lab->L[i][j] / 327.68f; - float CC = sqrt (SQR (lab->a[i][j]) + SQR (lab->b[i][j])) / 327.68f; +#ifdef __SSE2__ + float HH = HHbuffer[j]; + float CC = CCbuffer[j]; +#else float HH = xatan2f (lab->b[i][j], lab->a[i][j]); - - float satredu = 1.0f; //reduct sat in function of skin - - if (protectskins) { - Color::SkinSat (LL, HH, CC, satredu);// for skin colors - } + float CC = sqrt (SQR (lab->a[i][j]) + SQR (lab->b[i][j])) / 327.68f; +#endif // here we work on Chromaticity and Hue // variation of Chromaticity ==> saturation via RGB // Munsell correction, then conversion to Lab float Lprov = LL; float Chprov = CC; - float R, G, B; float2 sincosval; - if (CC == 0.0f) { + if (CC == 0.f) { sincosval.y = 1.f; - sincosval.x = 0.0f; + sincosval.x = 0.f; } else { sincosval.y = lab->a[i][j] / (CC * 327.68f); sincosval.x = lab->b[i][j] / (CC * 327.68f); } -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly (HH, sincosval, Lprov, Chprov, R, G, B, wip, highlight, 0.15f, 0.98f, neg, more_rgb); + float saturation; + Color::gamutLchonly(HH, sincosval, Lprov, Chprov, saturation, wip, highlight, 0.15f, 0.98f); - if (neg) { - negat++; - } + if (Chprov > 6.f) { + float satredu = 1.f; //reduct sat in function of skin - if (more_rgb) { - moreRGB++; - } + if (protectskins) { + Color::SkinSat (LL, HH, CC, satredu);// for skin colors + } -#else - //gamut control : Lab values are in gamut - Color::gamutLchonly (HH, sincosval, Lprov, Chprov, R, G, B, wip, highlight, 0.15f, 0.98f); -#endif - - if (Chprov > 6.0f) { - const float saturation = SAT (R, G, B); - - if (saturation > 0.0f) { - if (satredu != 1.0f) { + if (saturation > 0.f) { + if (satredu != 1.f) { // for skin, no differentiation - sathue [0] = sathue [1] = sathue [2] = sathue [3] = sathue[4] = 1.0f; - sathue2[0] = sathue2[1] = sathue2[2] = sathue2[3] = 1.0f; + sathue [0] = sathue [1] = sathue [2] = sathue [3] = sathue[4] = 1.f; + sathue2[0] = sathue2[1] = sathue2[2] = sathue2[3] = 1.f; } else { //double pyramid: LL and HH //I try to take into account: Munsell response (human vision) and Gamut..(less response for red): preferably using Prophoto or WideGamut //blue: -1.80 -3.14 green = 2.1 3.14 green-yellow=1.4 2.1 red:0 1.4 blue-purple:-0.7 -1.4 purple: 0 -0.7 //these values allow a better and differential response if (LL < 20.0f) { //more for blue-purple, blue and red modulate + sathue[4] = 0.4f; + sathue2[3] = 1.f; if (/*HH> -3.1415f &&*/ HH < -1.5f ) { sathue[0] = 1.3f; //blue sathue[1] = 1.2f; sathue[2] = 1.1f; sathue[3] = 1.05f; - sathue[4] = 0.4f; sathue2[0] = 1.05f; sathue2[1] = 1.1f ; sathue2[2] = 1.05f; - sathue2[3] = 1.0f; } else if (/*HH>=-1.5f &&*/ HH < -0.7f ) { sathue[0] = 1.6f; //blue purple 1.2 1.1 sathue[1] = 1.4f; sathue[2] = 1.3f; sathue[3] = 1.2f ; - sathue[4] = 0.4f; sathue2[0] = 1.2f ; sathue2[1] = 1.15f; sathue2[2] = 1.1f ; - sathue2[3] = 1.0f; } else if (/*HH>=-0.7f &&*/ HH < 0.0f ) { sathue[0] = 1.2f; //purple sathue[1] = 1.0f; sathue[2] = 1.0f; sathue[3] = 1.0f ; - sathue[4] = 0.4f; sathue2[0] = 1.0f ; sathue2[1] = 1.0f ; sathue2[2] = 1.0f ; - sathue2[3] = 1.0f; } // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=1.1f;sathue[1]=1.1f;sathue[2]=1.1f;sathue[3]=1.0f ;sathue[4]=0.4f;sathue2[0]=1.0f ;sathue2[1]=1.0f ;sathue2[2]=1.0f ;sathue2[3]=1.0f;}//red 0.8 0.7 else if (/*HH>= 0.0f &&*/ HH <= 1.4f ) { @@ -312,39 +284,33 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.2f; sathue[2] = 1.1f; sathue[3] = 1.0f ; - sathue[4] = 0.4f; sathue2[0] = 1.0f ; sathue2[1] = 1.0f ; sathue2[2] = 1.0f ; - sathue2[3] = 1.0f; } else if (/*HH> 1.4f &&*/ HH <= 2.1f ) { sathue[0] = 1.0f; //green yellow 1.2 1.1 sathue[1] = 1.0f; sathue[2] = 1.0f; sathue[3] = 1.0f ; - sathue[4] = 0.4f; sathue2[0] = 1.0f ; sathue2[1] = 1.0f ; sathue2[2] = 1.0f ; - sathue2[3] = 1.0f; } else { /*if(HH> 2.1f && HH<= 3.1415f)*/ sathue[0] = 1.4f; //green sathue[1] = 1.3f; sathue[2] = 1.2f; sathue[3] = 1.15f; - sathue[4] = 0.4f; sathue2[0] = 1.15f; sathue2[1] = 1.1f ; sathue2[2] = 1.05f; - sathue2[3] = 1.0f; } } else if (LL < 50.0f) { //more for blue and green, less for red and green-yellow + sathue[4] = 0.4f; if (/*HH> -3.1415f &&*/ HH < -1.5f ) { sathue[0] = 1.5f; //blue sathue[1] = 1.4f; sathue[2] = 1.3f; sathue[3] = 1.2f ; - sathue[4] = 0.4f; sathue2[0] = 1.2f ; sathue2[1] = 1.1f ; sathue2[2] = 1.05f; @@ -354,7 +320,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.2f; sathue[2] = 1.1f; sathue[3] = 1.05f; - sathue[4] = 0.4f; sathue2[0] = 1.05f; sathue2[1] = 1.05f; sathue2[2] = 1.0f ; @@ -364,7 +329,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.0f; sathue[2] = 1.0f; sathue[3] = 1.0f ; - sathue[4] = 0.4f; sathue2[0] = 1.0f ; sathue2[1] = 1.0f ; sathue2[2] = 1.0f ; @@ -376,7 +340,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.0f; sathue[2] = 0.9f; sathue[3] = 0.8f ; - sathue[4] = 0.4f; sathue2[0] = 0.8f ; sathue2[1] = 0.8f ; sathue2[2] = 0.8f ; @@ -386,7 +349,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.1f; sathue[2] = 1.1f; sathue[3] = 1.05f; - sathue[4] = 0.4f; sathue2[0] = 0.9f ; sathue2[1] = 0.8f ; sathue2[2] = 0.7f ; @@ -396,7 +358,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.4f; sathue[2] = 1.3f; sathue[3] = 1.2f ; - sathue[4] = 0.4f; sathue2[0] = 1.2f ; sathue2[1] = 1.1f ; sathue2[2] = 1.05f; @@ -404,12 +365,12 @@ void ImProcFunctions::vibrance (LabImage* lab) } } else if (LL < 80.0f) { //more for green, less for red and green-yellow + sathue[4] = 0.3f; if (/*HH> -3.1415f &&*/ HH < -1.5f ) { sathue[0] = 1.3f; //blue sathue[1] = 1.2f; sathue[2] = 1.15f; sathue[3] = 1.1f ; - sathue[4] = 0.3f; sathue2[0] = 1.1f ; sathue2[1] = 1.1f ; sathue2[2] = 1.05f; @@ -419,7 +380,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.2f; sathue[2] = 1.15f; sathue[3] = 1.1f ; - sathue[4] = 0.3f; sathue2[0] = 1.1f ; sathue2[1] = 1.05f; sathue2[2] = 1.0f ; @@ -429,7 +389,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.0f; sathue[2] = 1.0f ; sathue[3] = 1.0f ; - sathue[4] = 0.3f; sathue2[0] = 1.0f ; sathue2[1] = 1.0f ; sathue2[2] = 1.0f ; @@ -441,7 +400,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.0f; sathue[2] = 0.9f ; sathue[3] = 0.8f ; - sathue[4] = 0.3f; sathue2[0] = 0.8f ; sathue2[1] = 0.8f ; sathue2[2] = 0.8f ; @@ -451,7 +409,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.2f; sathue[2] = 1.1f ; sathue[3] = 1.05f; - sathue[4] = 0.3f; sathue2[0] = 1.0f ; sathue2[1] = 0.9f ; sathue2[2] = 0.8f ; @@ -461,19 +418,18 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.4f; sathue[2] = 1.3f ; sathue[3] = 1.25f; - sathue[4] = 0.3f; sathue2[0] = 1.25f; sathue2[1] = 1.2f ; sathue2[2] = 1.15f; sathue2[3] = 1.05f; } } else { /*if (LL>=80.0f)*/ //more for green-yellow, less for red and purple + sathue[4] = 0.2f; if (/*HH> -3.1415f &&*/ HH < -1.5f ) { sathue[0] = 1.0f; //blue sathue[1] = 1.0f; sathue[2] = 0.9f; sathue[3] = 0.8f; - sathue[4] = 0.2f; sathue2[0] = 0.8f; sathue2[1] = 0.8f ; sathue2[2] = 0.8f ; @@ -483,7 +439,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.0f; sathue[2] = 0.9f; sathue[3] = 0.8f; - sathue[4] = 0.2f; sathue2[0] = 0.8f; sathue2[1] = 0.8f ; sathue2[2] = 0.8f ; @@ -493,7 +448,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.0f; sathue[2] = 1.0f; sathue[3] = 0.9f; - sathue[4] = 0.2f; sathue2[0] = 0.9f; sathue2[1] = 0.9f ; sathue2[2] = 0.8f ; @@ -505,7 +459,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.0f; sathue[2] = 0.9f; sathue[3] = 0.8f; - sathue[4] = 0.2f; sathue2[0] = 0.8f; sathue2[1] = 0.8f ; sathue2[2] = 0.8f ; @@ -515,7 +468,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.5f; sathue[2] = 1.4f; sathue[3] = 1.2f; - sathue[4] = 0.2f; sathue2[0] = 1.1f; sathue2[1] = 1.05f; sathue2[2] = 1.0f ; @@ -525,7 +477,6 @@ void ImProcFunctions::vibrance (LabImage* lab) sathue[1] = 1.3f; sathue[2] = 1.2f; sathue[3] = 1.1f; - sathue[4] = 0.2f; sathue2[0] = 1.1f; sathue2[1] = 1.05f; sathue2[2] = 1.05f; @@ -534,97 +485,83 @@ void ImProcFunctions::vibrance (LabImage* lab) } } - float chmodpastel = 0.f, chmodsat = 0.f; + float chmod = 0.f; // variables to improve transitions float pa, pb;// transition = pa*saturation + pb - float chl00 = chromaPastel * satredu * sathue[4]; - float chl0 = chromaPastel * satredu * sathue[0]; - float chl1 = chromaPastel * satredu * sathue[1]; - float chl2 = chromaPastel * satredu * sathue[2]; - float chl3 = chromaPastel * satredu * sathue[3]; - float chs0 = chromaSatur * satredu * sathue2[0]; - float chs1 = chromaSatur * satredu * sathue2[1]; - float chs2 = chromaSatur * satredu * sathue2[2]; - float chs3 = chromaSatur * satredu * sathue2[3]; - float s3 = 1.0f; // We handle only positive values here ; improve transitions if (saturation < p00) { - chmodpastel = chl00 ; //neutral tones + pa = 0.f; + pb = chromaPastel * sathue[4]; } else if (saturation < p0 ) { + float chl00 = chromaPastel * sathue[4]; + float chl0 = chromaPastel * sathue[0]; pa = (chl00 - chl0) / (p00 - p0); pb = chl00 - pa * p00; - chmodpastel = pa * saturation + pb; } else if (saturation < p1) { + float chl0 = chromaPastel * sathue[0]; + float chl1 = chromaPastel * sathue[1]; pa = (chl0 - chl1) / (p0 - p1); pb = chl0 - pa * p0; - chmodpastel = pa * saturation + pb; } else if (saturation < p2) { + float chl1 = chromaPastel * sathue[1]; + float chl2 = chromaPastel * sathue[2]; pa = (chl1 - chl2) / (p1 - p2); pb = chl1 - pa * p1; - chmodpastel = pa * saturation + pb; } else if (saturation < limitpastelsatur) { + float chl2 = chromaPastel * sathue[2]; + float chl3 = chromaPastel * sathue[3]; pa = (chl2 - chl3) / (p2 - limitpastelsatur); pb = chl2 - pa * p2; - chmodpastel = pa * saturation + pb; } else if (saturation < s0) { + float chl3 = chromaPastel * sathue[3]; + float chs0 = chromaSatur * sathue2[0]; pa = (chl3 - chs0) / (limitpastelsatur - s0) ; pb = chl3 - pa * limitpastelsatur; - chmodsat = pa * saturation + pb; } else if (saturation < s1) { + float chs0 = chromaSatur * sathue2[0]; + float chs1 = chromaSatur * sathue2[1]; pa = (chs0 - chs1) / (s0 - s1); pb = chs0 - pa * s0; - chmodsat = pa * saturation + pb; } else if (saturation < s2) { + float chs1 = chromaSatur * sathue2[1]; + float chs2 = chromaSatur * sathue2[2]; pa = (chs1 - chs2) / (s1 - s2); pb = chs1 - pa * s1; - chmodsat = pa * saturation + pb; } else { - pa = (chs2 - chs3) / (s2 - s3); + float chs2 = chromaSatur * sathue2[2]; + float chs3 = chromaSatur * sathue2[3]; + pa = (chs2 - chs3) / (s2 - 1.f); pb = chs2 - pa * s2; - chmodsat = pa * saturation + pb; } + chmod = pa * saturation + pb; + chmod *= satredu; if (chromaPastel != chromaSatur) { // Pastels if (saturation > p2 && saturation < limitpastelsatur) { float newchromaPastel = chromaPastel_a * saturation + chromaPastel_b; - chmodpastel = newchromaPastel * satredu * sathue[3]; + chmod = newchromaPastel * satredu * sathue[3]; } // Saturated if (saturation < s0 && saturation >= limitpastelsatur) { float newchromaSatur = chromaSatur_a * saturation + chromaSatur_b; - chmodsat = newchromaSatur * satredu * sathue2[0]; + chmod = newchromaSatur * satredu * sathue2[0]; } }// end transition if (saturation <= limitpastelsatur) { - if (chmodpastel > 2.0f ) { - chmodpastel = 2.0f; //avoid too big values - } else if (chmodpastel < -0.93f) { - chmodpastel = -0.93f; //avoid negative values - } + chmod = rtengine::LIM(chmod, -0.93f, 2.f); + Chprov *= 1.0f + chmod; - Chprov *= (1.0f + chmodpastel); - - if (Chprov < 6.0f) { - Chprov = 6.0f; - } } else { //if (saturation > limitpastelsatur) - if (chmodsat > 1.8f ) { - chmodsat = 1.8f; //saturated - } else if (chmodsat < -0.93f) { - chmodsat = -0.93f; - } + chmod = rtengine::LIM(chmod, -0.93f, 1.8f); + Chprov *= 1.0f + chmod; - Chprov *= 1.0f + chmodsat; - - if (Chprov < 6.0f) { - Chprov = 6.0f; - } } + Chprov = rtengine::max(Chprov, 6.f); } } @@ -633,36 +570,36 @@ void ImProcFunctions::vibrance (LabImage* lab) // Vibrance's Skin curve if (skinCurveIsSet) { if (HH > skbeg && HH < skend) { - if (Chprov < 60.0f) { //skin hue : todo ==> transition + if (Chprov < 60.f) { //skin hue : todo ==> transition float HHsk = ask * HH + bsk; - float Hn = (skin_curve[HHsk] - bsk) / ask; - float Hc = (Hn * xx + HH * (1.0f - xx)); + float Hn = skin_curve[HHsk] - bsk0; + float Hc = Hn * xx + HH * (1.f - xx); HH = Hc; hhModified = true; - } else if (Chprov < (60.0f + dchr)) { //transition chroma + } else if (Chprov < (60.f + dchr)) { //transition chroma float HHsk = ask * HH + bsk; - float Hn = (skin_curve[HHsk] - bsk) / ask; - float Hc = (Hn * xx + HH * (1.0f - xx)); + float Hn = skin_curve[HHsk] - bsk0; + float Hc = Hn * xx + HH * (1.f - xx); float aa = (HH - Hc) / dchr ; - float bb = HH - (60.0f + dchr) * aa; + float bb = HH - (60.f + dchr) * aa; HH = aa * Chprov + bb; hhModified = true; } } //transition hue - else if (HH > (skbeg - dhue) && HH <= skbeg && Chprov < (60.0f + dchr * 0.5f)) { + else if (HH > (skbeg - dhue) && HH <= skbeg && Chprov < (60.f + dchr * 0.5f)) { float HHsk = ask * skbeg + bsk; - float Hn = (skin_curve[HHsk] - bsk) / ask; - float Hcc = (Hn * xx + skbeg * (1.0f - xx)); - float adh = (Hcc - (skbeg - dhue)) / (dhue); + float Hn = skin_curve[HHsk] - bsk0; + float Hcc = Hn * xx + skbeg * (1.f - xx); + float adh = (Hcc - (skbeg - dhue)) / dhue; float bdh = Hcc - adh * skbeg; HH = adh * HH + bdh; hhModified = true; - } else if (HH >= skend && HH < (skend + dhue) && Chprov < (60.0f + dchr * 0.5f)) { + } else if (HH >= skend && HH < (skend + dhue) && Chprov < (60.f + dchr * 0.5f)) { float HHsk = ask * skend + bsk; - float Hn = (skin_curve[HHsk] - bsk) / ask; - float Hcc = (Hn * xx + skend * (1.0f - xx)); - float adh = (skend + dhue - Hcc) / (dhue); + float Hn = skin_curve[HHsk] - bsk0; + float Hcc = Hn * xx + skend * (1.f - xx); + float adh = (skend + dhue - Hcc) / dhue; float bdh = Hcc - adh * skend; HH = adh * HH + bdh; hhModified = true; @@ -670,7 +607,6 @@ void ImProcFunctions::vibrance (LabImage* lab) } // end skin hue //Munsell correction -// float2 sincosval; if (!avoidcolorshift && hhModified) { sincosval = xsincosf (HH); } @@ -678,21 +614,18 @@ void ImProcFunctions::vibrance (LabImage* lab) float aprovn, bprovn; bool inGamut; + const float fyy = Color::c1By116 * Lprov + Color::c16By116; + const float yy_ = (Lprov > Color::epskap) ? fyy * fyy*fyy : Lprov / Color::kappaf; do { inGamut = true; if (avoidcolorshift) { float correctionHue = 0.0f; - float correctlum = 0.0f; -#ifdef _DEBUG - Color::AllMunsellLch (/*lumaMuns*/false, Lprov, Lprov, HH, Chprov, CC, correctionHue, correctlum, MunsDebugInfo); -#else - Color::AllMunsellLch (/*lumaMuns*/false, Lprov, Lprov, HH, Chprov, CC, correctionHue, correctlum); -#endif + Color::AllMunsellLch(Lprov, HH, Chprov, CC, correctionHue); if (correctionHue != 0.f || hhModified) { - sincosval = xsincosf (HH + correctionHue); + sincosval = xsincosf(HH + correctionHue); hhModified = false; } } @@ -700,29 +633,21 @@ void ImProcFunctions::vibrance (LabImage* lab) aprovn = Chprov * sincosval.y; bprovn = Chprov * sincosval.x; - float fyy = (Color::c1By116 * Lprov ) + Color::c16By116; - float fxx = (0.002f * aprovn) + fyy; - float fzz = fyy - (0.005f * bprovn); - float xx_ = 65535.f * Color::f2xyz (fxx) * Color::D50x; - // float yy_ = 65535.0f * Color::f2xyz(fyy); - float zz_ = 65535.f * Color::f2xyz (fzz) * Color::D50z; - float yy_ = 65535.f * ((Lprov > Color::epskap) ? fyy * fyy*fyy : Lprov / Color::kappa); + float fxx = 0.002f * aprovn + fyy; + float fzz = fyy - 0.005f * bprovn; + float xx_ = Color::f2xyz(fxx) * Color::D50x; + float zz_ = Color::f2xyz(fzz) * Color::D50z; + float R, G, B; Color::xyz2rgb (xx_, yy_, zz_, R, G, B, wip); - if (R < 0.0f || G < 0.0f || B < 0.0f) { -#ifdef _DEBUG - negsat++; -#endif + if (rtengine::min(R, G, B) < 0.0f) { Chprov *= 0.98f; inGamut = false; } // if "highlight reconstruction" enabled don't control Gamut for highlights - if ((!highlight) && (R > 65535.0f || G > 65535.0f || B > 65535.0f)) { -#ifdef _DEBUG - moresat++; -#endif + if (!highlight && max(R, G, B) > 1.f && min(R, G, B) <= 1.f) { Chprov *= 0.98f; inGamut = false; } @@ -733,27 +658,8 @@ void ImProcFunctions::vibrance (LabImage* lab) lab->a[i][j] = aprovn * 327.68f; lab->b[i][j] = bprovn * 327.68f; } - - } // end of parallelization - -#ifdef _DEBUG - t2e.set(); - - if (settings->verbose) { - printf ("Vibrance (performed in %d usec):\n", t2e.etime (t1e)); - printf (" Gamut: G1negat=%iiter G165535=%iiter G2negsat=%iiter G265535=%iiter\n", negat, moreRGB, negsat, moresat); - - if (MunsDebugInfo) { - printf (" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%u\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); } - } - - if (MunsDebugInfo) { - delete MunsDebugInfo; - } - -#endif - + } // end of parallelization } From 32e9c454f57d2f7318a360440377f7b008df4e36 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 22 Mar 2018 02:16:57 +0100 Subject: [PATCH 2/3] Don't report vibrance processing time if vibrance is disabled --- rtengine/ipvibrance.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index b5d711c7c..f9b46f620 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -70,10 +70,10 @@ void fillCurveArrayVib (DiagonalCurve* diagCurve, LUTf &outCurve) */ void ImProcFunctions::vibrance (LabImage* lab) { - BENCHFUN if (!params->vibrance.enabled) { return; } + BENCHFUN // int skip=1; //scale==1 ? 1 : 16; bool skinCurveIsSet = false; From eb1e67e3fb6c5b783e68cc3efa02d8d101db4fa4 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 8 Apr 2018 00:56:56 +0200 Subject: [PATCH 3/3] Removed BENCHMARK --- rtengine/ipvibrance.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index f9b46f620..26141423c 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -27,7 +27,6 @@ #include "../rtgui/thresholdselector.h" #include "curves.h" #include "color.h" -#define BENCHMARK #include "StopWatch.h" #ifdef _OPENMP #include