diff --git a/rtengine/color.cc b/rtengine/color.cc index 38d0d96fa..756dd6d22 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -1106,61 +1106,8 @@ namespace rtengine { - void Color::SkinSatcdbl (float lum, float hue, float chrom, float skinprot, float &scale, bool ciec, bool neg, float b_l, float t_l, float t_r, float b_r, int choice) { - - - - float C9=0.0f, C8=0.0f, C7=0.0f, C4=0.0f, C3=0.0f, C2=0.0f, C1=0.0f; - float H9=0.0f, H8=0.0f, H7=0.0f, H4=0.0f, H3=0.0f, H2=0.0f, H1=0.0f, H10=0.0f,H11=0.0f; - 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 ?? - C9=8.0f;C8=15.0f;C7=12.0f;C4=7.0f;C3=5.0f;C2=5.0f;C1=5.0f; - if (ciec) { - float HH = 0.f; - bool doskin; - if ((float)hue>8.6f && (float)hue<=74.f ) {HH=(1.15f/65.4f)*(float)hue-0.0012f; doskin=true;}//H > 0.15 H<1.3 - else if((float)hue>0.f && (float)hue<=8.6f ) {HH=(0.19f/8.6f )*(float)hue-0.04f; doskin=true;}//H>-0.04 H < 0.15 - else if((float)hue>355.f && (float)hue<=360.f) {HH=(0.11f/5.0f )*(float)hue-7.96f; doskin=true;}//H>-0.15 <-0.04 - else if((float)hue>74.f && (float)hue<95.f ) {HH=(0.30f/21.0f)*(float)hue+0.24285f; doskin=true;}//H>1.3 H<1.6 - else if((float)hue>=95.f && (float)hue<137.5f) {HH= 0.01882*(float)hue-0.18823;}// H>1.6 H<2.4 - else if((float)hue>285.f && (float)hue<=355.f) {HH=0.1642*(float)hue -5.982;}//HH>-1.3 HH <-0.15 - - hue=HH; - - } - // wide area for transition - if((t_r-t_l)<0.55f) t_l=t_r+0.55f;//avoid too small range - if (lum >= 92.0f && (hue > b_l && hue < t_r) && (chrom > 7.0f && chrom < (18.0f))) scale = (100.f-skinprot*0.4f)/100.1f; - else if (lum >= 85.0f && lum < 92.0f && (hue > b_l+0.05f && hue < t_r) && (chrom > 7.0f && chrom < (35.0f+C9))) scale = (100.f-skinprot*0.4f)/100.1f; - else if ((lum >= 20.f && lum < 85.f) && (hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; - else if (lum < 20.0f && (hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; - - // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation - - if (lum >= 92.0f && (hue > t_l+0.4f && hue < t_r) && (chrom > 7.0f && chrom < (15.0f))) scale = (100.f-skinprot*0.6f)/100.1f; - else if (lum >= 85.0f && lum < 92.0f && (hue > t_l+0.4f && hue < t_r-0.3f) && (chrom > 7.0f && chrom < (26.0f+C9))) scale = (100.f-skinprot*0.6f)/100.1f; - else if ((lum >= 20.f && lum < 85.f) && (hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; - else if (lum < 20.0f && (hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; - - // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1 - - if (lum >= 85.0f && (hue > (t_l+0.53f-H9) && hue < (t_r+H9)) && (chrom > 8.0f && chrom < (14.0f+C9))) scale = (100.f-skinprot)/100.1f; - else if ((lum >= 70.0f && lum < 85.0f) && (hue > t_l+0.15f && hue < (t_r-0.2f+H8)) && (chrom > 8.0f && chrom < (35.0f+C8))) scale = (100.f-skinprot)/100.1f; - else if ((lum >= 52.0f && lum < 70.0f) && (hue > t_l && hue < (t_r+H7)) && (chrom > 11.0f && chrom < (35.0f+C7))) scale = (100.f-skinprot)/100.1f; - else if ((lum >= 35.0f && lum < 52.0f) && (hue > t_l && hue < (t_r+H4)) && (chrom > 13.0f && chrom < (37.0f+C4))) scale = (100.f-skinprot)/100.1f; - else if ((lum >= 20.0f && lum < 35.0f) && (hue > t_l && hue < (t_r+H3)) && (chrom > 7.0f && chrom <(35.0f+C3) )) scale = (100.f-skinprot)/100.1f; - else if ((lum > 10.0f && lum < 20.0f) && (hue > (t_l-0.25f + H10) && hue < (t_r-0.3f +H2)) && (chrom > 8.0f && chrom < (23.0f+C2))) scale = (100.f-skinprot)/100.1f; - else if ((lum < 10.0f) && (hue > (t_l -0.2f + H10) && hue < (t_r-0.3f+H1)) && (chrom > 8.0f && chrom < (23.0f+C1))) scale = (100.f-skinprot)/100.1f; - - //extended zone for hair, beard and if user adjust high value for skinprot - if(skinprot > 85.f && chrom < 20.f && neg) { - float modula = -0.0666f*skinprot + 6.66f; - scale *= modula; - } - } - - void Color::scalered ( float rstprotection, float param, float limit, float HH, float deltaHH, float &scale,float &scaleext) { @@ -1224,13 +1171,13 @@ namespace rtengine { bool contin1,contin2; float correctionHue=0.0,correctionHueLum=0.0; - float correctlumprov=0.0; - float correctlumprov2=0.0; - bool correctL=false; - float huelimit[8]={-2.48,-0.55,0.44,1.52,1.87,3.09,-0.27,0.44};//limits hue of blue-purple, red-yellow, green-yellow, red-purple + bool correctL; if(CC >= 6.0 && CC < 140) { //if C > 140 we say C=140 (only in Prophoto ...with very large saturation) - if (Chprov1 > 140) Chprov1=139; //limits of LUTf - if (Chprov1 < 6) Chprov1=6; + static const float huelimit[8]={-2.48,-0.55,0.44,1.52,1.87,3.09,-0.27,0.44};//limits hue of blue-purple, red-yellow, green-yellow, red-purple + if (Chprov1 > 140.f) + Chprov1=139.f; //limits of LUTf + if (Chprov1 < 6.f) + Chprov1=6.f; for(int zo=1;zo<=4;zo++) { if(HH>huelimit[2*zo-2] && HHmaxdhue[idx] = MAX(munsDbgInfo->maxdhue[idx], absCorrectionHue); munsDbgInfo->depass++; //verify if no bug in calculation #endif correctionHuechroma=correctionHue; //preserve - if(lumaMuns) { + if(lumaMuns) { + float correctlumprov=0.f; + float correctlumprov2=0.f; if(correctL) { //for Munsell luminance correction correctlumprov=correctionHueLum; @@ -1386,6 +1335,92 @@ munsDbgInfo->maxdhue[idx] = MAX(munsDbgInfo->maxdhue[idx], absCorrectionHue); while (!inGamut); //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 R,G,B : red, green and blue value of the corrected color + * double 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) + * bool neg and moreRGB : only in DEBUG mode to calculate iterations for negatives values and > 65535 + */ +#ifdef _DEBUG + void Color::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, bool &neg, bool &more_rgb) +#else + void Color::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) +#endif + { + const float ClipLevel = 65535.0f; + bool inGamut; +#ifdef _DEBUG + neg=false, more_rgb=false; +#endif + do { + inGamut=true; + + //Lprov1=LL; + 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 = (0.00862069f *Lprov1 )+ 0.137932f; + float fx = (0.002f * aprov1) + fy; + float fz = fy - (0.005f * bprov1); + + float x_ = 65535.0f * f2xyz(fx)*D50x; + // float y_ = 65535.0f * f2xyz(fy); + float z_ = 65535.0f * f2xyz(fz)*D50z; + float y_=(Lprov1>epskap) ? 65535.0*fy*fy*fy : 65535.0*Lprov1/kappa; + + xyz2rgb(x_,y_,z_,R,G,B,wip); + + // gamut control before saturation to put Lab values in future gamut, but not RGB + if (R<0.0f || G<0.0f || B<0.0f) { +#ifdef _DEBUG + neg=true; +#endif + if (Lprov1 < 0.1f) 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.0f) + Lprov1 += lowerCoef; + inGamut = false; + } else if (!isHLEnabled && (R>ClipLevel || G>ClipLevel || B>ClipLevel)) { + + // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut +#ifdef _DEBUG + more_rgb=true; +#endif + if (Lprov1 > 99.999f) + Lprov1 = 99.98f; + Chprov1 *= higherCoef; + if (Chprov1 <= 3.0f) + Lprov1 -= lowerCoef; + inGamut = false; + } + } + while (!inGamut); + //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) @@ -1861,42 +1896,57 @@ munsDbgInfo->maxdhue[idx] = MAX(munsDbgInfo->maxdhue[idx], absCorrectionHue); * pay attention to white balance, and do not change hue and saturation, upstream of the modification * */ - void Color::SkinSat (float lum, float hue, float chrom, float &satreduc, int chromx) { + 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 - float reduction=0.3;// to be adapted...by tests - float extendedreduction=0.4; - float extendedreduction2=0.6; + 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 ?? + + if (lum >= 85.f) { + if((hue > (0.78f-H9) && hue < (1.18f+H9)) && (chrom > 8.f && chrom < (14.f+C9))) satreduc=reduction; + else if (lum >= 92.f) { + if((hue > 0.8f && hue < 1.65f) && (chrom > 7.f && chrom < (15.f))) satreduc=extendedreduction; + else if ((hue > -0.1f && hue < 1.65f) && (chrom > 7.f && chrom < (18.f))) satreduc=extendedreduction2; + } + else if ((hue > 0.7f && hue < 1.4f) && (chrom > 7.f && chrom < (26.f+C9))) satreduc=extendedreduction; + else if (lum < 92.f && (hue > 0.f && hue < 1.65f) && (chrom > 7.f && chrom < (35.f+C9))) satreduc=extendedreduction2; + } + else if (lum >= 70.f) { + if((hue > 0.4f && hue < (1.04f+H8)) && (chrom > 8.f && chrom < (35.f+C8))) satreduc=reduction; + else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; + else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; + } + else if (lum >= 52.f) { + if((hue > 0.3f && hue < (1.27f+H7)) && (chrom > 11.f && chrom < (35.f+C7))) satreduc=reduction; + else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; + else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; + } + else if (lum >= 35.f) { + if((hue > 0.3f && hue < (1.25f+H4)) && (chrom > 13.f && chrom < (37.f+C4))) satreduc=reduction; + else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; + else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; + } + else if (lum >= 20.f) { + if((hue > 0.3f && hue < (1.2f+H3)) && (chrom > 7.f && chrom <(35.f+C3) )) satreduc=reduction; + else if ((hue > (0.02f + H11) && hue < 1.5f) && (chrom > 7.0f && chrom < (48.f+C9) )) satreduc=extendedreduction; + else if ((hue > (0.02f + H11) && hue < 1.65f) && (chrom > 7.f && chrom < (55.f+C9) )) satreduc=extendedreduction2; + } + else if (lum > 10.f) { + if((hue > (0.f + H10) && hue < (0.95f +H2)) && (chrom > 8.f && chrom < (23.f+C2))) satreduc=reduction; + else if ((hue > (0.02f+H11) && hue < 1.f) && (chrom > 7.f && chrom < (35.f+C1) )) satreduc=extendedreduction; + else if ((hue > (0.02f+H11) && hue < 1.6f) && (chrom > 7.f && chrom < (45.f+C1) )) satreduc=extendedreduction2; + } + else { + if((hue > (0.02f + H10) && hue < (0.9f+H1)) && (chrom > 8.f && chrom < (23.f+C1))) satreduc=reduction; // no data : extrapolate + else if ((hue > (0.02f+H11) && hue < 1.f) && (chrom > 7.f && chrom < (35.f+C1) )) satreduc=extendedreduction; + else if ((hue > (0.02f+H11) && hue < 1.6f) && (chrom > 7.f && chrom < (45.f+C1) )) satreduc=extendedreduction2; + + } - if(chromx==1) {reduction=0.6;extendedreduction=0.7;extendedreduction2=0.8;} - - float C9=0.0, C8=0.0, C7=0.0, C4=0.0, C3=0.0, C2=0.0, C1=0.0; - float H9=0.0, H8=0.0, H7=0.0, H4=0.0, H3=0.0, H2=0.0, H1=0.0, H10=0.0,H11=0.0; - 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 ?? - C9=8.0;C8=15.0;C7=12.0;C4=7.0;C3=5.0;C2=5.0;C1=5.0; - - // wide area for transition - - if (lum >= 92.0 && (hue > -0.1 && hue < 1.65) && (chrom > 7.0 && chrom < (18.0))) satreduc=extendedreduction2; - else if (lum >= 85.0 && lum < 92.0 && (hue > 0.0 && hue < 1.65) && (chrom > 7.0 && chrom < (35.0+C9))) satreduc=extendedreduction2; - else if ((lum > 20 && lum < 85) && (hue > (0.02 + H11) && hue < 1.65) && (chrom > 7.0 && chrom < (55.0+C9) )) satreduc=extendedreduction2; - else if (lum < 20.0 && (hue > (0.02+H11) && hue < 1.60) && (chrom > 7.0 && chrom < (45.0+C1) )) satreduc=extendedreduction2; - - // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation - - if (lum >= 92.0 && (hue > 0.8 && hue < 1.65) && (chrom > 7.0 && chrom < (15.0))) satreduc=extendedreduction; - else if (lum >= 85.0 && lum < 92.0 && (hue > 0.70 && hue < 1.4) && (chrom > 7.0 && chrom < (26.0+C9))) satreduc=extendedreduction; - else if ((lum > 20 && lum < 85) && (hue > (0.02 + H11) && hue < 1.5) && (chrom > 7.0 && chrom < (48.0+C9) )) satreduc=extendedreduction; - else if (lum < 20.0 && (hue > (0.02+H11) && hue < 1.0) && (chrom > 7.0 && chrom < (35.0+C1) )) satreduc=extendedreduction; - - // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1 - - if (lum >= 85.0 && (hue > (0.78-H9) && hue < (1.18+H9)) && (chrom > 8.0 && chrom < (14.0+C9))) satreduc=reduction; - else if ((lum >= 70.0 && lum < 85.0) && (hue > 0.4 && hue < (1.04+H8)) && (chrom > 8.0 && chrom < (35.0+C8))) satreduc=reduction; - else if ((lum >= 52.0 && lum < 70.0) && (hue > 0.3 && hue < (1.27+H7)) && (chrom > 11.0 && chrom < (35.0+C7))) satreduc=reduction; - else if ((lum >= 35.0 && lum < 52.0) && (hue > 0.3 && hue < (1.25+H4)) && (chrom > 13.0 && chrom < (37.0+C4))) satreduc=reduction; - else if ((lum >= 20.0 && lum < 35.0) && (hue > 0.3 && hue < (1.20+H3)) && (chrom > 7.0 && chrom <(35.0+C3) )) satreduc=reduction; - else if ((lum > 10.0 && lum < 20.0) && (hue > (0.0 + H10) && hue < (0.95 +H2)) && (chrom > 8.0 && chrom < (23.0+C2))) satreduc=reduction; - else if ((lum < 10.0) && (hue > (0.02 + H10) && hue < (0.90+H1)) && (chrom > 8.0 && chrom < (23.0+C1))) satreduc=reduction; // no data : extrapolate } /* diff --git a/rtengine/color.h b/rtengine/color.h index f2269e50e..8f3f7270c 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -976,9 +976,11 @@ public: */ #ifdef _DEBUG static void gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, float &G, float &B, const double wip[3][3], const bool isHLEnabled, const float lowerCoef, const float higherCoef, bool &neg, bool &more_rgb); + 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, bool &neg, bool &more_rgb); static void 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); #else static void gamutLchonly (float HH, 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 (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 @@ -1019,7 +1021,7 @@ public: * @param satreduc [0.1 ; 1] (return value) * @param chromx [0 or 1], actually only 0 is used */ - static void SkinSat (float lum, float hue, float chrom, float &satreduc, int chromx);//jacques Skin color + static void SkinSat (float lum, float hue, float chrom, float &satreduc);//jacques Skin color /** @@ -1045,7 +1047,124 @@ public: static void skinred ( double J, double h, double sres, double Sp, float dred, float protect_red, int sk, float rstprotection, float ko, double &s); static void skinredfloat ( float J, float h, float sres, float Sp, float dred, float protect_red, int sk, float rstprotection, float ko, float &s); // static void scaleredcdbl ( float skinprot, float param, float limit, float HH, float deltaHH, float &scale,float &scaleext); - static void SkinSatcdbl (float lum, float hue, float chrom, float skinprot, float &scale, bool ciec, bool neg, float b_l, float t_l, float t_r, float b_r, int choice); + + static inline void SkinSatCbdl (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r) { + + static const float C9=8.f, C8=15.f, C7=12.f, C4=7.f, C3=5.f, C2=5.f, C1=5.f; + static const 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; + + // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1, uses imolicit factor 1.0 + // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation, uses explicit facor 0.6 + // wide area for transition, uses explicit factor 0.4 + + if (lum >= 85.0f) { + if((hue > (t_l+0.53f-H9) && hue < (t_r+H9)) && (chrom > 8.0f && chrom < (14.0f+C9))) scale = (100.f-skinprot)/100.1f; + else if (lum >= 92.0f) { + if((hue > t_l+0.4f && hue < t_r) && (chrom > 7.0f && chrom < (15.0f))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l && hue < t_r) && (chrom > 7.0f && chrom < (18.0f))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > t_l+0.4f && hue < t_r-0.3f) && (chrom > 7.0f && chrom < (26.0f+C9))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l+0.05f && hue < t_r) && (chrom > 7.0f && chrom < (35.0f+C9))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 70.0f) { + if((hue > t_l+0.15f && hue < (t_r-0.2f+H8)) && (chrom > 8.0f && chrom < (35.0f+C8))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 52.0f) { + if((hue > t_l && hue < (t_r+H7)) && (chrom > 11.0f && chrom < (35.0f+C7))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 35.0f) { + if((hue > t_l && hue < (t_r+H4)) && (chrom > 13.0f && chrom < (37.0f+C4))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 20.0f) { + if((hue > t_l && hue < (t_r+H3)) && (chrom > 7.0f && chrom <(35.0f+C3) )) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 10.0f) { + if((hue > (t_l-0.25f + H10) && hue < (t_r-0.3f +H2)) && (chrom > 8.0f && chrom < (23.0f+C2))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > (t_l -0.2f + H10) && hue < (t_r-0.3f+H1)) && (chrom > 8.0f && chrom < (23.0f+C1))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + + //extended zone for hair, beard and if user adjust high value for skinprot + if(skinprot > 85.f && chrom < 20.f && neg) { + float modula = -0.0666f * skinprot + 6.66f; + scale *= modula; + } + } + + static inline void SkinSatCbdlCam (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r) { + + static const float C9=8.f, C8=15.f, C7=12.f, C4=7.f, C3=5.f, C2=5.f, C1=5.f; + static const 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; + + float HH = 0.f; + if (hue>8.6f && hue<=74.f ) {HH=(1.15f/65.4f)*hue-0.0012f;} //H > 0.15 H<1.3 + else if(hue>0.f && hue<=8.6f ) {HH=(0.19f/8.6f )*hue-0.04f;} //H>-0.04 H < 0.15 + else if(hue>355.f && hue<=360.f) {HH=(0.11f/5.0f )*hue-7.96f;} //H>-0.15 <-0.04 + else if(hue>74.f && hue<95.f ) {HH=(0.30f/21.0f)*hue+0.24285f;} //H>1.3 H<1.6 + else if(hue>=95.f && hue<137.5f) {HH= 0.01882f*hue-0.18823f;} // H>1.6 H<2.4 + else if(hue>285.f && hue<=355.f) {HH=0.1642f*hue -5.982f;} //HH>-1.3 HH <-0.15 + + hue=HH; + + // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1, uses imolicit factor 1.0 + // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation, uses explicit facor 0.6 + // wide area for transition, uses explicit factor 0.4 + + if (lum >= 85.0f) { + if((hue > (t_l+0.53f-H9) && hue < (t_r+H9)) && (chrom > 8.0f && chrom < (14.0f+C9))) scale = (100.f-skinprot)/100.1f; + else if (lum >= 92.0f) { + if((hue > t_l+0.4f && hue < t_r) && (chrom > 7.0f && chrom < (15.0f))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l && hue < t_r) && (chrom > 7.0f && chrom < (18.0f))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > t_l+0.4f && hue < t_r-0.3f) && (chrom > 7.0f && chrom < (26.0f+C9))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l+0.05f && hue < t_r) && (chrom > 7.0f && chrom < (35.0f+C9))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 70.0f) { + if((hue > t_l+0.15f && hue < (t_r-0.2f+H8)) && (chrom > 8.0f && chrom < (35.0f+C8))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 52.0f) { + if((hue > t_l && hue < (t_r+H7)) && (chrom > 11.0f && chrom < (35.0f+C7))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 35.0f) { + if((hue > t_l && hue < (t_r+H4)) && (chrom > 13.0f && chrom < (37.0f+C4))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 20.0f) { + if((hue > t_l && hue < (t_r+H3)) && (chrom > 7.0f && chrom <(35.0f+C3) )) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 10.0f) { + if((hue > (t_l-0.25f + H10) && hue < (t_r-0.3f +H2)) && (chrom > 8.0f && chrom < (23.0f+C2))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > (t_l -0.2f + H10) && hue < (t_r-0.3f+H1)) && (chrom > 8.0f && chrom < (23.0f+C1))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + + //extended zone for hair, beard and if user adjust high value for skinprot + if(skinprot > 85.f && chrom < 20.f && neg) { + float modula = -0.0666f * skinprot + 6.66f; + scale *= modula; + } + } /** diff --git a/rtengine/dirpyr_equalizer.cc b/rtengine/dirpyr_equalizer.cc index e1b9a9bf6..006519e31 100644 --- a/rtengine/dirpyr_equalizer.cc +++ b/rtengine/dirpyr_equalizer.cc @@ -24,15 +24,11 @@ #include "labimage.h" #include "color.h" #include "mytime.h" -//#include "StopWatch.h" - #include "improcfun.h" #include "rawimagesource.h" #include "array2D.h" #include "rt_math.h" -#ifdef __SSE2__ -#include "sleefsseavx.c" -#endif +#include "opthelper.h" #ifdef _OPENMP #include #endif @@ -46,20 +42,16 @@ namespace rtengine { static const int maxlevel = 5; static const float noise = 2000; - static const float thresh = 1000; //sequence of scales - static const int scales[8] = {1,2,4,8,16,32,64,128}; + static const int scales[5] = {1,2,4,8,16}; extern const Settings* settings; //sequence of scales - void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, int srcwidth, int srcheight, float ** l_a, float ** l_b, float ** dest_a, float ** dest_b,const double * mult, const double dirpyrThreshold, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scaleprev) +SSEFUNCTION void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, int srcwidth, int srcheight, float ** l_a, float ** l_b, float ** dest_a, float ** dest_b,const double * mult, const double dirpyrThreshold, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scaleprev) { - // StopWatch Stop1("Dirpyr equalizer"); - - int lastlevel=maxlevel; if(settings->verbose) printf("Dirpyr scaleprev=%i\n",scaleprev); float atten123=(float) settings->level123_cbdl; @@ -69,6 +61,9 @@ namespace rtengine { if(atten0 > 40.f) atten123=40.f; if(atten0 < 0.f) atten0=0.f; + if((t_r-t_l)<0.55f) + t_l = t_r + 0.55f;//avoid too small range + while (lastlevel>0 && fabs(mult[lastlevel-1]-1)<0.001) { lastlevel--; @@ -97,7 +92,7 @@ namespace rtengine { if(scale < 1) scale=1; - dirpyr_channel(src, dirpyrlo[0], srcwidth, srcheight, 0, scale, l_a, l_b, false ); + dirpyr_channel(src, dirpyrlo[0], srcwidth, srcheight, 0, scale); level = 1; @@ -107,48 +102,103 @@ namespace rtengine { scale = (int)(scales[level])/scaleprev; if(scale < 1) scale=1; - dirpyr_channel(dirpyrlo[level-1], dirpyrlo[level], srcwidth, srcheight, level, scale, l_a, l_b, false ); + dirpyr_channel(dirpyrlo[level-1], dirpyrlo[level], srcwidth, srcheight, level, scale); level ++; } + float **tmpHue,**tmpChr; + if(skinprot != 0.f) { + // precalculate hue and chroma, use SSE, if available + // by precalculating these values we can greatly reduce the number of calculations in idirpyr_eq_channel() + // but we need two additional buffers for this preprocessing + tmpHue = new float*[srcheight]; + for (int i=0; i 0; level--) { - idirpyr_eq_channel(dirpyrlo[level], dirpyrlo[level-1], buffer, srcwidth, srcheight, level, multi, dirpyrThreshold, l_a, l_b, false, skinprot, gamutlab, b_l,t_l,t_r,b_r, choice ); + idirpyr_eq_channel(dirpyrlo[level], dirpyrlo[level-1], buffer, srcwidth, srcheight, level, multi, dirpyrThreshold, tmpHue, tmpChr, skinprot, gamutlab, b_l,t_l,t_r,b_r, choice ); } - - + scale = scales[0]; - idirpyr_eq_channel(dirpyrlo[0], dst, buffer, srcwidth, srcheight, 0, multi, dirpyrThreshold, l_a, l_b, false, skinprot, gamutlab, b_l,t_l,t_r,b_r, choice ); - - + idirpyr_eq_channel(dirpyrlo[0], dst, buffer, srcwidth, srcheight, 0, multi, dirpyrThreshold, tmpHue, tmpChr, skinprot, gamutlab, b_l,t_l,t_r,b_r, choice ); + + if(skinprot != 0.f) { + for (int i=0; iverbose) printf("CAM dirpyr scaleprev=%i\n",scaleprev); float atten123=(float) settings->level123_cbdl; @@ -159,6 +209,9 @@ namespace rtengine { if(atten0 > 40.f) atten123=40.f; if(atten0 < 0.f) atten0=0.f; + if((t_r-t_l)<0.55f) + t_l = t_r + 0.55f;//avoid too small range + while (fabs(mult[lastlevel-1]-1)<0.001 && lastlevel>0) { lastlevel--; //printf("last level to process %d \n",lastlevel); @@ -190,7 +243,7 @@ namespace rtengine { int scale = (int)(scales[level])/scaleprev; if(scale < 1) scale=1; - dirpyr_channel(src, dirpyrlo[0], srcwidth, srcheight, 0, scale, h_p, C_p, true ); + dirpyr_channel(src, dirpyrlo[0], srcwidth, srcheight, 0, scale); level = 1; @@ -199,7 +252,7 @@ namespace rtengine { scale = (int)(scales[level])/scaleprev; if(scale < 1) scale=1; - dirpyr_channel(dirpyrlo[level-1], dirpyrlo[level], srcwidth, srcheight, level, scale, h_p, C_p, true ); + dirpyr_channel(dirpyrlo[level-1], dirpyrlo[level], srcwidth, srcheight, level, scale); level ++; } @@ -210,19 +263,19 @@ namespace rtengine { for(int level = lastlevel - 1; level > 0; level--) { - idirpyr_eq_channel(dirpyrlo[level], dirpyrlo[level-1], buffer, srcwidth, srcheight, level, multi, dirpyrThreshold , h_p, C_p, true, skinprot, false, b_l,t_l,t_r,b_r, choice); + idirpyr_eq_channelcam(dirpyrlo[level], dirpyrlo[level-1], buffer, srcwidth, srcheight, level, multi, dirpyrThreshold , h_p, C_p, skinprot, b_l,t_l,t_r); } scale = scales[0]; - idirpyr_eq_channel(dirpyrlo[0], dst, buffer, srcwidth, srcheight, 0, multi, dirpyrThreshold, h_p, C_p, true, skinprot, false, b_l,t_l,t_r,b_r, choice); + idirpyr_eq_channelcam(dirpyrlo[0], dst, buffer, srcwidth, srcheight, 0, multi, dirpyrThreshold, h_p, C_p, skinprot, b_l,t_l,t_r); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if(execdir){ #ifdef _OPENMP -#pragma omp parallel for +#pragma omp parallel for schedule(dynamic,16) #endif for (int i=0; i 1) { //generate domain kernel int domker[5][5] = {{1,1,1,1,1},{1,2,2,2,1},{1,2,2,2,1},{1,2,2,2,1},{1,1,1,1,1}}; - halfwin=2; - scalewin = halfwin*scale; + static const int halfwin=2; + const int scalewin = halfwin*scale; #ifdef _OPENMP #pragma omp parallel #endif { #ifdef __SSE2__ __m128 thousandv = _mm_set1_ps( 1000.0f ); - __m128 dirwtv, valv, normv; - float domkerv[5][5][4] = {{{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}},{{1,1,1,1},{2,2,2,2},{2,2,2,2},{2,2,2,2},{1,1,1,1}},{{1,1,1,1},{2,2,2,2},{2,2,2,2},{2,2,2,2},{1,1,1,1}},{{1,1,1,1},{2,2,2,2},{2,2,2,2},{2,2,2,2},{1,1,1,1}},{{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}}}; + __m128 dirwtv, valv, normv, dftemp1v, dftemp2v; +// multiplied each value of domkerv by 1000 to avoid multiplication by 1000 inside the loop + float domkerv[5][5][4] __attribute__ ((aligned (16))) = {{{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000}},{{1000,1000,1000,1000},{2000,2000,2000,2000},{2000,2000,2000,2000},{2000,2000,2000,2000},{1000,1000,1000,1000}},{{1000,1000,1000,1000},{2000,2000,2000,2000},{2000,2000,2000,2000},{2000,2000,2000,2000},{1000,1000,1000,1000}},{{1000,1000,1000,1000},{2000,2000,2000,2000},{2000,2000,2000,2000},{2000,2000,2000,2000},{1000,1000,1000,1000}},{{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000}}}; #endif // __SSE2__ int j; #ifdef _OPENMP -#pragma omp for +#pragma omp for //schedule (dynamic,8) #endif for(int i = 0; i < height; i++) { float dirwt; - for(j = 0; j < scalewin; j++) - { - float val=0; - float norm=0; + for(j = 0; j < scalewin; j++) { + float val=0.f; + float norm=0.f; for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { for (int jnbr=max(0,j-scalewin); jnbr<=j+scalewin; jnbr+=scale) { @@ -294,11 +339,13 @@ void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, i { valv = _mm_setzero_ps(); normv = _mm_setzero_ps(); - - for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { - for (int jnbr=j-scalewin; jnbr<=j+scalewin; jnbr+=scale) { - dirwtv = _mm_loadu_ps((float*)&domkerv[(inbr-i)/scale+halfwin][(jnbr-j)/scale+halfwin]) * (thousandv / (vabsf(LVFU(data_fine[inbr][jnbr])-(LVFU(data_fine[i][j]))) + thousandv)); - valv += dirwtv*LVFU(data_fine[inbr][jnbr]); + dftemp1v = LVFU(data_fine[i][j]); + for(int inbr=MAX(0,i-scalewin); inbr<=MIN(height-1,i+scalewin); inbr+=scale) { + int indexihlp = (inbr-i)/scale+halfwin; + for (int jnbr=j-scalewin, indexjhlp = 0; jnbr<=j+scalewin; jnbr+=scale,indexjhlp++) { + dftemp2v = LVFU(data_fine[inbr][jnbr]); + dirwtv = _mm_load_ps((float*)&domkerv[indexihlp][indexjhlp]) / (vabsf(dftemp1v-dftemp2v) + thousandv); + valv += dirwtv*dftemp2v; normv += dirwtv; } } @@ -306,8 +353,8 @@ void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, i } for(; j < width-scalewin; j++) { - float val=0; - float norm=0; + float val=0.f; + float norm=0.f; for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { for (int jnbr=j-scalewin; jnbr<=j+scalewin; jnbr+=scale) { @@ -321,8 +368,8 @@ void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, i #else for(; j < width-scalewin; j++) { - float val=0; - float norm=0; + float val=0.f; + float norm=0.f; for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { for (int jnbr=j-scalewin; jnbr<=j+scalewin; jnbr+=scale) { @@ -336,8 +383,8 @@ void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, i #endif for(; j < width; j++) { - float val=0; - float norm=0; + float val=0.f; + float norm=0.f; for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { for (int jnbr=j-scalewin; jnbr<=min(width-1,j+scalewin); jnbr+=scale) { @@ -351,29 +398,28 @@ void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, i } } } else { // level <=1 means that all values of domker would be 1.0f, so no need for multiplication - halfwin = 1; - scalewin = halfwin*scale; +// const int scalewin = scale; #ifdef _OPENMP #pragma omp parallel #endif { #ifdef __SSE2__ __m128 thousandv = _mm_set1_ps( 1000.0f ); - __m128 dirwtv, valv, normv; + __m128 dirwtv, valv, normv, dftemp1v, dftemp2v; #endif // __SSE2__ int j; #ifdef _OPENMP -#pragma omp for +#pragma omp for schedule(dynamic,16) #endif for(int i = 0; i < height; i++) { float dirwt; - for(j = 0; j < scalewin; j++) + for(j = 0; j < scale; j++) { - float val=0; - float norm=0; + float val=0.f; + float norm=0.f; - for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { - for (int jnbr=max(0,j-scalewin); jnbr<=j+scalewin; jnbr+=scale) { + for(int inbr=max(0,i-scale); inbr<=min(height-1,i+scale); inbr+=scale) { + for (int jnbr=max(0,j-scale); jnbr<=j+scale; jnbr+=scale) { dirwt = RANGEFN(fabsf(data_fine[inbr][jnbr]-data_fine[i][j])); val += dirwt*data_fine[inbr][jnbr]; norm += dirwt; @@ -382,28 +428,29 @@ void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, i data_coarse[i][j]=val/norm;//low pass filter } #ifdef __SSE2__ - for(; j < width-scalewin-3; j+=4) + for(; j < width-scale-3; j+=4) { valv = _mm_setzero_ps(); normv = _mm_setzero_ps(); - - for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { - for (int jnbr=j-scalewin; jnbr<=j+scalewin; jnbr+=scale) { - dirwtv = thousandv / (vabsf(LVFU(data_fine[inbr][jnbr])-(LVFU(data_fine[i][j]))) + thousandv); - valv += dirwtv*LVFU(data_fine[inbr][jnbr]); + dftemp1v = LVFU(data_fine[i][j]); + for(int inbr=MAX(0,i-scale); inbr<=MIN(height-1,i+scale); inbr+=scale) { + for (int jnbr=j-scale; jnbr<=j+scale; jnbr+=scale) { + dftemp2v = LVFU(data_fine[inbr][jnbr]); + dirwtv = thousandv / (vabsf(dftemp2v-dftemp1v) + thousandv); + valv += dirwtv*dftemp2v; normv += dirwtv; } } _mm_storeu_ps( &data_coarse[i][j], valv/normv);//low pass filter } - for(; j < width-scalewin; j++) + for(; j < width-scale; j++) { - float val=0; - float norm=0; + float val=0.f; + float norm=0.f; - for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { - for (int jnbr=j-scalewin; jnbr<=j+scalewin; jnbr+=scale) { + for(int inbr=max(0,i-scale); inbr<=min(height-1,i+scale); inbr+=scale) { + for (int jnbr=j-scale; jnbr<=j+scale; jnbr+=scale) { dirwt = RANGEFN(fabsf(data_fine[inbr][jnbr]-data_fine[i][j])); val += dirwt*data_fine[inbr][jnbr]; norm += dirwt; @@ -412,13 +459,13 @@ void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, i data_coarse[i][j]=val/norm;//low pass filter } #else - for(; j < width-scalewin; j++) + for(; j < width-scale; j++) { - float val=0; - float norm=0; + float val=0.f; + float norm=0.f; - for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { - for (int jnbr=j-scalewin; jnbr<=j+scalewin; jnbr+=scale) { + for(int inbr=max(0,i-scale); inbr<=min(height-1,i+scale); inbr+=scale) { + for (int jnbr=j-scale; jnbr<=j+scale; jnbr+=scale) { dirwt = RANGEFN(fabsf(data_fine[inbr][jnbr]-data_fine[i][j])); val += dirwt*data_fine[inbr][jnbr]; norm += dirwt; @@ -429,11 +476,11 @@ void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, i #endif for(; j < width; j++) { - float val=0; - float norm=0; + float val=0.f; + float norm=0.f; - for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { - for (int jnbr=j-scalewin; jnbr<=min(width-1,j+scalewin); jnbr+=scale) { + for(int inbr=max(0,i-scale); inbr<=min(height-1,i+scale); inbr+=scale) { + for (int jnbr=j-scale; jnbr<=min(width-1,j+scale); jnbr+=scale) { dirwt = RANGEFN(fabsf(data_fine[inbr][jnbr]-data_fine[i][j])); val += dirwt*data_fine[inbr][jnbr]; norm += dirwt; @@ -448,81 +495,157 @@ void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, i //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - void ImProcFunctions::idirpyr_eq_channel(float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, float mult[5], const double dirpyrThreshold, float ** l_a_h, float ** l_b_c, bool ciec, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r , int choice) + void ImProcFunctions::idirpyr_eq_channel(float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, float mult[5], const double dirpyrThreshold, float ** hue, float ** chrom, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r , int choice) { - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); - 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]} - }; - bool highlight = params->toneCurve.hrenabled; //Get the value if "highlight reconstruction" is activated + const float skinprotneg = -skinprot; + const float factorHard = (1.f - skinprotneg/100.f); - float noisehi = 1.33f*noise*dirpyrThreshold/expf(level*log(3.0)), noiselo = 0.66f*noise*dirpyrThreshold/expf(level*log(3.0)); + float offs; + if(skinprot==0.f) + offs = 0.f; + else + offs = -1.f; + + LUTf irangefn (0x20000); + { + const float noisehi = 1.33f*noise*dirpyrThreshold/expf(level*log(3.0)), noiselo = 0.66f*noise*dirpyrThreshold/expf(level*log(3.0)); //printf("level=%i multlev=%f noisehi=%f noiselo=%f skinprot=%f\n",level,mult[level], noisehi, noiselo, skinprot); - LUTf irangefn (0x20000); for (int i=0; i<0x20000; i++) { if (abs(i-0x10000)>noisehi || mult[level]<1.0) { - irangefn[i] = mult[level] ; + irangefn[i] = mult[level] + offs; } else { if (abs(i-0x10000) 0.f) +#ifdef _OPENMP +#pragma omp parallel for schedule(dynamic,16) #endif for(int i = 0; i < height; i++) { for(int j = 0; j < width; j++) { float scale=1.f; float hipass = (data_fine[i][j]-data_coarse[i][j]); - if(ciec) {//Ciecam - if(skinprot >= 0.) { - Color::SkinSatcdbl ((data_fine[i][j])/327.68f, l_a_h[i][j] ,l_b_c[i][j], skinprot, scale, ciec, true, b_l, t_l, t_r, b_r, choice); - buffer[i][j] += (1.f +(irangefn[hipass+0x10000]-1.f)*scale) * hipass ; - } - else { - double skinprotneg = -skinprot; - float correct; - correct=irangefn[hipass+0x10000]; - Color::SkinSatcdbl ((data_fine[i][j])/327.68f, l_a_h[i][j],l_b_c[i][j] , skinprotneg, scale, ciec, false, b_l, t_l, t_r, b_r, choice); - if (scale == 1.f) {//image hard - //buffer[i][j] += hipass ; - buffer[i][j] += (1.f +(correct-1.f)* (1.f- (float) skinprotneg/100.f)) * hipass ; - - } - else {//image soft - buffer[i][j] += (1.f +(correct-1.f)) * hipass ; - } - } + // These values are precalculated now + float modhue = hue[i][j]; + float modchro = chrom[i][j]; + Color::SkinSatCbdl ((data_fine[i][j])/327.68f, modhue, modchro, skinprot, scale, true, b_l, t_l, t_r); + buffer[i][j] += (1.f +(irangefn[hipass+0x10000])*scale) * hipass ; + } + } + else +#ifdef _OPENMP +#pragma omp parallel for schedule(dynamic,16) +#endif + for(int i = 0; i < height; i++) { + for(int j = 0; j < width; j++) { + float scale=1.f; + float hipass = (data_fine[i][j]-data_coarse[i][j]); + // These values are precalculated now + float modhue = hue[i][j]; + float modchro = chrom[i][j]; + Color::SkinSatCbdl ((data_fine[i][j])/327.68f, modhue, modchro, skinprotneg, scale, false, b_l, t_l, t_r); + float correct = irangefn[hipass+0x10000]; + if (scale == 1.f) {//image hard + buffer[i][j] += (1.f +(correct)* (factorHard)) * hipass ; + } + else {//image soft with scale < 1 ==> skin + buffer[i][j] += (1.f +(correct)) * hipass ; + } + } + } + } + + + void ImProcFunctions::idirpyr_eq_channelcam(float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, float mult[5], const double dirpyrThreshold, float ** l_a_h, float ** l_b_c, const double skinprot, float b_l, float t_l, float t_r) + { + + const float skinprotneg = -skinprot; + const float factorHard = (1.f - skinprotneg/100.f); + + float offs; + if(skinprot==0.f) + offs = 0.f; + else + offs = -1.f; + + LUTf irangefn (0x20000); + { + const float noisehi = 1.33f*noise*dirpyrThreshold/expf(level*log(3.0)), noiselo = 0.66f*noise*dirpyrThreshold/expf(level*log(3.0)); + //printf("level=%i multlev=%f noisehi=%f noiselo=%f skinprot=%f\n",level,mult[level], noisehi, noiselo, skinprot); + for (int i=0; i<0x20000; i++) { + if (abs(i-0x10000)>noisehi || mult[level]<1.0) { + irangefn[i] = mult[level] + offs; + } else { + if (abs(i-0x10000) 0.f) +#ifdef _OPENMP +#pragma omp parallel for schedule(dynamic,16) +#endif + for(int i = 0; i < height; i++) { + for(int j = 0; j < width; j++) { + float hipass = (data_fine[i][j]-data_coarse[i][j]); + float scale=1.f; + Color::SkinSatCbdlCam ((data_fine[i][j])/327.68f, l_a_h[i][j] ,l_b_c[i][j], skinprot, scale, true, b_l, t_l, t_r); + buffer[i][j] += (1.f +(irangefn[hipass+0x10000])*scale) * hipass ; + } + } + else +#ifdef _OPENMP +#pragma omp parallel for schedule(dynamic,16) +#endif + for(int i = 0; i < height; i++) { + for(int j = 0; j < width; j++) { + float hipass = (data_fine[i][j]-data_coarse[i][j]); + float scale=1.f; + float correct; + correct=irangefn[hipass+0x10000]; + Color::SkinSatCbdlCam ((data_fine[i][j])/327.68f, l_a_h[i][j],l_b_c[i][j] , skinprotneg, scale, false, b_l, t_l, t_r); + if (scale == 1.f) {//image hard + buffer[i][j] += (1.f +(correct)* factorHard) * hipass ; + + } + else {//image soft + buffer[i][j] += (1.f +(correct)) * hipass ; + } + } + } // if(gamutlab) { // ImProcFunctions::badpixcam (buffer[i][j], 6.0, 10, 2);//for bad pixels // } - } - else {//lab - float modhue=atan2(l_b_c[i][j],l_a_h[i][j]); - float modchro=sqrt(SQR((l_b_c[i][j])/327.68f)+SQR((l_a_h[i][j])/327.68f)); - if(skinprot >= 0.) { - Color::SkinSatcdbl ((data_fine[i][j])/327.68f, modhue, modchro, skinprot, scale, ciec, true, b_l, t_l, t_r, b_r, choice); - buffer[i][j] += (1.f +(irangefn[hipass+0x10000]-1.f)*scale) * hipass ; - } - else { - double skinprotneg = -skinprot; - float correct; - Color::SkinSatcdbl ((data_fine[i][j])/327.68f, modhue, modchro, skinprotneg, scale, ciec, false, b_l, t_l, t_r, b_r, choice); - correct=irangefn[hipass+0x10000]; - if (scale == 1.f) {//image hard - buffer[i][j] += (1.f +(correct-1.f)* (1.f- (float)skinprotneg/100.f)) * hipass ; - } - else {//image soft with scale < 1 ==> skin - buffer[i][j] += (1.f +(correct-1.f)) * hipass ; - } - } /* if(gamutlab) {//disabled float Lprov1=(buffer[i][j])/327.68f; float R,G,B; @@ -542,12 +665,8 @@ void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, i l_b_c[i][j]=327.68f*modchro*sincosval.x; } */ - } - } - } - } - + // float hipass = (data_fine[i][j]-data_coarse[i][j]); // buffer[i][j] += irangefn[hipass+0x10000] * hipass ; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index f6c41dc15..af7dd0638 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -286,9 +286,9 @@ class ImProcFunctions { // pyramid equalizer void dirpyr_equalizer (float ** src, float ** dst, int srcwidth, int srcheight, float ** l_a, float ** l_b, float ** dest_a, float ** dest_b, const double * mult, const double dirpyrThreshold, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scale);//Emil's directional pyramid equalizer void dirpyr_equalizercam (CieImage* ncie, float ** src, float ** dst, int srcwidth, int srcheight, float ** h_p, float ** C_p, const double * mult, const double dirpyrThreshold, const double skinprot, bool execdir, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scale);//Emil's directional pyramid equalizer - void dirpyr_channel (float ** data_fine, float ** data_coarse, int width, int height, int level, int scale, float ** l_a_h, float ** l_b_c, bool ciec); - void idirpyr_eq_channel (float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, float multi[5], const double dirpyrThreshold, float ** l_a_h, float ** l_b_c, bool ciec, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice); - + void dirpyr_channel (float ** data_fine, float ** data_coarse, int width, int height, int level, int scale); + void idirpyr_eq_channel (float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, float multi[5], const double dirpyrThreshold, float ** l_a_h, float ** l_b_c, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice); + void idirpyr_eq_channelcam (float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, float multi[5], const double dirpyrThreshold, float ** l_a_h, float ** l_b_c, const double skinprot, float b_l, float t_l, float t_r); void defringe (LabImage* lab); void defringecam (CieImage* ncie); void badpixcam (CieImage* ncie, double rad, int thr, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom, int hotbad); diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index c7d01868a..2582209d0 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -27,8 +27,7 @@ #include "mytime.h" #include "../rtgui/thresholdselector.h" #include "curves.h" -//#include "calc_distort.h" -#include "color.h" +#include "color.h" #ifdef _OPENMP #include @@ -40,13 +39,13 @@ 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) +#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, bool needed) { +void fillCurveArrayVib(DiagonalCurve* diagCurve, LUTf &outCurve) { - if (needed && diagCurve) { + if (diagCurve) { #ifdef _OPENMP #pragma omp parallel for #endif @@ -71,9 +70,9 @@ void fillCurveArrayVib(DiagonalCurve* diagCurve, LUTf &outCurve, bool needed) { * */ void ImProcFunctions::vibrance (LabImage* lab) { - if (!params->vibrance.enabled) return; + // int skip=1; //scale==1 ? 1 : 16; bool skinCurveIsSet=false; DiagonalCurve* dcurve = NULL; @@ -96,7 +95,8 @@ void ImProcFunctions::vibrance (LabImage* lab) { return; } - int width = lab->W, height = lab->H; + const int width = lab->W; + const int height = lab->H; #ifdef _DEBUG MyTime t1e,t2e; @@ -108,7 +108,7 @@ void ImProcFunctions::vibrance (LabImage* lab) { // I use diagonal because I think it's better LUTf skin_curve (65536,0); if(skinCurveIsSet) - fillCurveArrayVib(dcurve, skin_curve, skinCurveIsSet); + fillCurveArrayVib(dcurve, skin_curve); if (dcurve) { delete dcurve; dcurve = NULL; @@ -117,53 +117,19 @@ void ImProcFunctions::vibrance (LabImage* lab) { // skin_curve.dump("skin_curve"); - float chromaPastel = float(params->vibrance.pastels) / 100.0f; - float chromaSatur = float(params->vibrance.saturated) / 100.0f; - float limitpastelsatur = static_cast(params->vibrance.psthreshold.value[ThresholdSelector::TS_TOPLEFT]) / 100.0f; - float transitionweighting = static_cast(params->vibrance.psthreshold.value[ThresholdSelector::TS_BOTTOMLEFT]) / 100.0f; - - bool highlight = params->toneCurve.hrenabled;//Get the value if "highlight reconstruction" is activated - bool protectskins = params->vibrance.protectskins; - bool avoidcolorshift = params->vibrance.avoidcolorshift; - - -#ifdef _DEBUG - MunsellDebugInfo* MunsDebugInfo = NULL; - if (avoidcolorshift) - MunsDebugInfo = new MunsellDebugInfo(); - -#pragma omp parallel default(shared) firstprivate(lab, width, height, chromaPastel, chromaSatur, highlight, limitpastelsatur, \ - transitionweighting, protectskins, avoidcolorshift, MunsDebugInfo) reduction(+: negat, moreRGB, negsat, moresat) if (multiThread) -#else -#pragma omp parallel default(shared) firstprivate(lab, width, height, chromaPastel, chromaSatur, highlight, limitpastelsatur, \ - transitionweighting, protectskins, avoidcolorshift) if (multiThread) -#endif -{ - - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); - //inverse matrix user select - 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]} - }; - float sathue[5],sathue2[4];// adjust sat in function of hue - + const float chromaPastel = float(params->vibrance.pastels) / 100.0f; + const float chromaSatur = float(params->vibrance.saturated) / 100.0f; const float p00=0.07f; - - // 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; - float maxdp=(limitpastelsatur-p00)/4.0f; - float maxds=(1.0-limitpastelsatur)/4.0f; - p0=p00+maxdp; - p1=p00+2.0f*maxdp; - p2=p00+3.0f*maxdp; - s0=limitpastelsatur + maxds; - s1=limitpastelsatur + 2.0f*maxds; - s2=limitpastelsatur + 3.0f*maxds; - + const float limitpastelsatur = (static_cast(params->vibrance.psthreshold.value[ThresholdSelector::TS_TOPLEFT]) / 100.0f)*(1.0f-p00) + p00; + const float maxdp=(limitpastelsatur-p00)/4.0f; + const float maxds=(1.0-limitpastelsatur)/4.0f; + const float p0 = p00+maxdp; + const float p1 = p00+2.0f*maxdp; + const float p2 = p00+3.0f*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.value[ThresholdSelector::TS_BOTTOMLEFT]) / 100.0f; float chromamean=0.0f; 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 @@ -176,7 +142,56 @@ void ImProcFunctions::vibrance (LabImage* lab) { else if (transitionweighting < 0.0f) { chromamean = (chromamean-chromaPastel) * transitionweighting + chromamean; } - } + } + const float chromaPastel_a = (chromaPastel-chromamean)/(p2-limitpastelsatur); + const float chromaPastel_b = chromaPastel-chromaPastel_a*p2; + + 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; + + + const bool highlight = params->toneCurve.hrenabled;//Get the value if "highlight reconstruction" is activated + const bool protectskins = params->vibrance.protectskins; + const bool avoidcolorshift = params->vibrance.avoidcolorshift; + + TMatrix wiprof = iccStore->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]} + }; + + +#ifdef _DEBUG + MunsellDebugInfo* MunsDebugInfo = NULL; + if (avoidcolorshift) + MunsDebugInfo = new MunsellDebugInfo(); + +#pragma omp parallel default(shared) firstprivate(lab, width, height, chromaPastel, chromaSatur, highlight, limitpastelsatur, \ + transitionweighting, protectskins, avoidcolorshift, MunsDebugInfo) reduction(+: negat, moreRGB, negsat, moresat) if (multiThread) +#else +#pragma omp parallel default(shared) if (multiThread)// firstprivate(lab, width, height, chromaPastel, chromaSatur, highlight, limitpastelsatur, \ + transitionweighting, protectskins, avoidcolorshift) if (multiThread) +#endif +{ + + 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) { @@ -187,93 +202,93 @@ void ImProcFunctions::vibrance (LabImage* lab) { printf(" pastel=%f satur=%f limit= %1.2f chromamean=%0.5f\n",1.0f+chromaPastel,1.0f+chromaSatur, limitpastelsatur, chromamean); } -#pragma omp for schedule(dynamic, 10) +#pragma omp for schedule(dynamic, 16) for (int i=0; iL[i][j]/327.68f; - float CC=sqrt(SQR(lab->a[i][j]/327.68f)+ SQR(lab->b[i][j]/327.68f)); - float HH=xatan2f(lab->b[i][j],lab->a[i][j]); - //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 - if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.3f;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;}//blue - else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.6f;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;}//blue purple 1.2 1.1 - else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;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;}//purple - // 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 ) {sathue[0]=1.3f;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;}//red 0.8 0.7 - else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.0f;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;}//green yellow 1.2 1.1 - else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.4f;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;}//green - } - else if (LL< 50.0f) {//more for blue and green, less for red and green-yellow - if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.5f;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;sathue2[3]=1.0f;}//blue - else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.3f;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 ;sathue2[3]=1.0f;}//blue purple 1.2 1.1 - else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;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;}//purple - // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f;sathue[3]=0.8f ;sathue[4]=0.4f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;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 ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.1f;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 ;sathue2[3]=0.6f;}//green yellow 1.2 1.1 - else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.5f;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;sathue2[3]=1.0f;}//green - - } - else if (LL< 80.0f) {//more for green, less for red and green-yellow - if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.3f;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;sathue2[3]=1.0f;}//blue - else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.3f;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 ;sathue2[3]=1.0f;}//blue purple 1.2 1.1 - else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;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 ;sathue2[3]=1.0f;}//purple - // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f ;sathue[3]=0.8f ;sathue[4]=0.3f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;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 ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.3f;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 ;sathue2[3]=0.7f;}//green yellow 1.2 1.1 - else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.6f;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;}//green - even with Prophoto green are too "little" 1.5 1.3 - } - else /*if (LL>=80.0f)*/ {//more for green-yellow, less for red and purple - if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.0f;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 ;sathue2[3]=0.8f;}//blue - else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.0f;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 ;sathue2[3]=0.8f;}//blue purple 1.2 1.1 - else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;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 ;sathue2[3]=0.8f;}//purple - // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f;sathue[3]=0.8f;sathue[4]=0.2f;sathue2[0]=0.8f;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;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 ;sathue2[3]=0.8f;}//red 0.8 0.7 - else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.6f;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 ;sathue2[3]=1.0f;}//green yellow 1.2 1.1 - else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.4f;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;sathue2[3]=1.0f;}//green - } - + float CC=sqrt(SQR(lab->a[i][j])+ SQR(lab->b[i][j]))/327.68f; + 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, 0);// for skin colors - } + Color::SkinSat (LL, HH, CC, satredu);// for skin colors + } // 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 memChprov=CC; float R, G, B; + float2 sincosval; + if(CC==0.0f) { + sincosval.y = 1.f; + sincosval.x = 0.0f; + } 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, Lprov, Chprov, R, G, B, wip, highlight, 0.15f, 0.98f, neg, more_rgb); + Color::gamutLchonly(HH, sincosval, Lprov, Chprov, R, G, B, wip, highlight, 0.15f, 0.98f, neg, more_rgb); if(neg) negat++; if(more_rgb) moreRGB++; #else //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, Lprov, Chprov, R, G, B, wip, highlight, 0.15f, 0.98f); + Color::gamutLchonly(HH, sincosval, Lprov, Chprov, R, G, B, wip, highlight, 0.15f, 0.98f); #endif - - float saturation=SAT(R,G,B); - //evaluate saturation with curve chroma -// saturation=(sat_curve[saturation*65535.0f])/65535.0f; - - // work on saturation - if(Chprov > 6.0f) { //protect gray and LUT Munsell - //pyramid to adjust saturation in function of saturation and hue (and Luminance) - if(satredu!=1.0f) { - // 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; - } - + if(Chprov > 6.0f) { + const float saturation=SAT(R,G,B); if(saturation>0.0f) { + if(satredu!=1.0f) { + // 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; + } 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 + if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.3f;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;}//blue + else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.6f;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;}//blue purple 1.2 1.1 + else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;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;}//purple + // 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 ) {sathue[0]=1.3f;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;}//red 0.8 0.7 + else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.0f;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;}//green yellow 1.2 1.1 + else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.4f;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;}//green + } + else if (LL< 50.0f) {//more for blue and green, less for red and green-yellow + if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.5f;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;sathue2[3]=1.0f;}//blue + else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.3f;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 ;sathue2[3]=1.0f;}//blue purple 1.2 1.1 + else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;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;}//purple + // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f;sathue[3]=0.8f ;sathue[4]=0.4f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;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 ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.1f;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 ;sathue2[3]=0.6f;}//green yellow 1.2 1.1 + else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.5f;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;sathue2[3]=1.0f;}//green + + } + else if (LL< 80.0f) {//more for green, less for red and green-yellow + if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.3f;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;sathue2[3]=1.0f;}//blue + else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.3f;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 ;sathue2[3]=1.0f;}//blue purple 1.2 1.1 + else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;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 ;sathue2[3]=1.0f;}//purple + // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f ;sathue[3]=0.8f ;sathue[4]=0.3f;sathue2[0]=0.8f ;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;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 ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.3f;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 ;sathue2[3]=0.7f;}//green yellow 1.2 1.1 + else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.6f;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;}//green - even with Prophoto green are too "little" 1.5 1.3 + } + else /*if (LL>=80.0f)*/ {//more for green-yellow, less for red and purple + if (/*HH> -3.1415f &&*/ HH< -1.5f ) {sathue[0]=1.0f;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 ;sathue2[3]=0.8f;}//blue + else if(/*HH>=-1.5f &&*/ HH< -0.7f ) {sathue[0]=1.0f;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 ;sathue2[3]=0.8f;}//blue purple 1.2 1.1 + else if(/*HH>=-0.7f &&*/ HH< 0.0f ) {sathue[0]=1.2f;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 ;sathue2[3]=0.8f;}//purple + // else if( HH>= 0.0f && HH<= 1.4f ) {sathue[0]=0.8f;sathue[1]=0.8f;sathue[2]=0.8f;sathue[3]=0.8f;sathue[4]=0.2f;sathue2[0]=0.8f;sathue2[1]=0.8f ;sathue2[2]=0.8f ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH>= 0.0f &&*/ HH<= 1.4f ) {sathue[0]=1.1f;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 ;sathue2[3]=0.8f;}//red 0.8 0.7 + else if(/*HH> 1.4f &&*/ HH<= 2.1f ) {sathue[0]=1.6f;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 ;sathue2[3]=1.0f;}//green yellow 1.2 1.1 + else /*if(HH> 2.1f && HH<= 3.1415f)*/ {sathue[0]=1.4f;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;sathue2[3]=1.0f;}//green + } + } float chmodpastel,chmodsat; // variables to improve transitions float pa, pb;// transition = pa*saturation + pb @@ -302,112 +317,113 @@ void ImProcFunctions::vibrance (LabImage* lab) { // Pastels if(saturation > p2 && saturation < limitpastelsatur) { - float chromaPastel_a = (chromaPastel-chromamean)/(p2-limitpastelsatur); - float chromaPastel_b = chromaPastel-chromaPastel_a*p2; float newchromaPastel = chromaPastel_a*saturation + chromaPastel_b; chmodpastel = newchromaPastel*satredu*sathue[3]; } // Saturated if(saturation < s0 && saturation >=limitpastelsatur) { - float chromaSatur_a=(chromaSatur-chromamean)/(s0-limitpastelsatur); - float chromaSatur_b=chromaSatur-chromaSatur_a*s0; float newchromaSatur=chromaSatur_a*saturation + chromaSatur_b; chmodsat = 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 + if (chmodpastel > 2.0f ) + chmodpastel = 2.0f; //avoid too big values + else if(chmodpastel < -0.93f) + chmodpastel =-0.93f; //avoid negative values Chprov *=(1.0f+chmodpastel); - if(Chprov<6.0f) Chprov=6.0f; + 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; + if (chmodsat > 1.8f ) + chmodsat = 1.8f; //saturated + else if(chmodsat < -0.93f) + chmodsat =-0.93f; Chprov *= 1.0f+chmodsat; - if(Chprov < 6.0f) Chprov=6.0f; - } - } + if(Chprov < 6.0f) + Chprov=6.0f; + } + } } - + + bool hhModified = false; // Vibrance's Skin curve if(skinCurveIsSet) { - 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 - - float ask=65535.0f/(skend-skbeg); - float bsk=-skbeg*ask; - if (HH>skbeg && HH transition float HHsk=ask*HH+bsk; float Hn=(skin_curve[HHsk]-bsk)/ask; float Hc=(Hn*xx+HH*(1.0f-xx)); - HH=Hc; + HH=Hc; + hhModified = true; } else if(Chprov < (60.0f+dchr)) {//transition chroma float HHsk=ask*HH+bsk; float Hn=(skin_curve[HHsk]-bsk)/ask; float Hc=(Hn*xx+HH*(1.0f-xx)); float aa= (HH-Hc)/dchr ; float bb= HH-(60.0f+dchr)*aa; - HH=aa*Chprov+bb; + HH=aa*Chprov+bb; + hhModified = true; } } //transition hue - else if(HH>(skbeg-dhue) && HH<=skbeg && Chprov < (60.0f+dchr/2.0f)) { + else if(HH>(skbeg-dhue) && HH<=skbeg && Chprov < (60.0f+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 bdh=Hcc-adh*skbeg; - HH=adh*HH+bdh; + HH=adh*HH+bdh; + hhModified = true; } - else if(HH>=skend && HH<(skend+dhue) && Chprov < (60.0f+dchr/2.0f)) { + else if(HH>=skend && HH<(skend+dhue) && Chprov < (60.0f+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 bdh=Hcc-adh*skend; - HH=adh*HH+bdh; + HH=adh*HH+bdh; + hhModified = true; } } // end skin hue //Munsell correction - float correctionHue=0.0f; - float correctlum; - +// float2 sincosval; + if(!avoidcolorshift && hhModified) + sincosval = xsincosf(HH); float aprovn,bprovn; bool inGamut; do { inGamut=true; if(avoidcolorshift) { - correctionHue=0.0f; - correctlum=0.0f; + float correctionHue=0.0f; + float correctlum=0.0f; #ifdef _DEBUG - Color::AllMunsellLch(/*lumaMuns*/false, Lprov,Lprov,HH,Chprov,memChprov,correctionHue,correctlum, MunsDebugInfo); + Color::AllMunsellLch(/*lumaMuns*/false, Lprov,Lprov,HH,Chprov,CC,correctionHue,correctlum, MunsDebugInfo); #else - Color::AllMunsellLch(/*lumaMuns*/false, Lprov,Lprov,HH,Chprov,memChprov,correctionHue,correctlum); -#endif + Color::AllMunsellLch(/*lumaMuns*/false, Lprov,Lprov,HH,Chprov,CC,correctionHue,correctlum); +#endif + if(correctionHue != 0.f || hhModified) { + sincosval = xsincosf(HH+correctionHue); + hhModified = false; + } } - float2 sincosval = xsincosf(HH+correctionHue); aprovn=Chprov*sincosval.y; bprovn=Chprov*sincosval.x; float fyy = (0.00862069f *Lprov )+ 0.137932f; float fxx = (0.002f * aprovn) + fyy; float fzz = fyy - (0.005f * bprovn); - float xx_ = 65535.0f * Color::f2xyz(fxx)*Color::D50x; + float xx_ = 65535.f * Color::f2xyz(fxx)*Color::D50x; // float yy_ = 65535.0f * Color::f2xyz(fyy); - float zz_ = 65535.0f * Color::f2xyz(fzz)*Color::D50z; - float yy_= (Lprov>Color::epskap) ? 65535.0*fyy*fyy*fyy : 65535.0*Lprov/Color::kappa; + float zz_ = 65535.f * Color::f2xyz(fzz)*Color::D50z; + float yy_ = 65535.f * ((Lprov>Color::epskap) ? fyy*fyy*fyy : Lprov/Color::kappa); Color::xyz2rgb(xx_,yy_,zz_,R,G,B,wip); @@ -415,8 +431,8 @@ void ImProcFunctions::vibrance (LabImage* lab) { #ifdef _DEBUG negsat++; #endif - Chprov*=0.98f; - inGamut=false; + Chprov *= 0.98f; + inGamut = false; } // if "highlight reconstruction" enabled don't control Gamut for highlights @@ -424,11 +440,11 @@ void ImProcFunctions::vibrance (LabImage* lab) { #ifdef _DEBUG moresat++; #endif - Chprov*=0.98f; - inGamut=false; + Chprov *= 0.98f; + inGamut = false; } - } - while (!inGamut); + } while (!inGamut); + //put new values in Lab lab->L[i][j]=Lprov*327.68f; lab->a[i][j]=aprovn*327.68f;