Speedup for Vibrance and Contrast by Detail Levels, Issue 2520

This commit is contained in:
Ingo
2014-10-04 12:10:31 +02:00
parent e182daaddc
commit 96d80d1102
5 changed files with 723 additions and 419 deletions

View File

@@ -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] && HH<huelimit[2*zo-1]) {
//zone=zo;
@@ -1251,7 +1198,9 @@ munsDbgInfo->maxdhue[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 <jdesmis@gmail.com> and Jean-Christophe Frisch <natureh@free.fr>
*
* 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
}
/*

View File

@@ -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;
}
}
/**

View File

@@ -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 <omp.h>
#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<srcheight; i++) {
tmpHue[i] = new float[srcwidth];
}
#ifdef __SSE2__
#pragma omp parallel for
for(int i=0;i<srcheight;i++) {
int j;
for(j=0;j<srcwidth-3;j+=4) {
_mm_storeu_ps(&tmpHue[i][j],xatan2f(LVFU(l_b[i][j]),LVFU(l_a[i][j])));
}
for(;j<srcwidth;j++) {
tmpHue[i][j] = xatan2f(l_b[i][j],l_a[i][j]);
}
}
#else
#pragma omp parallel for
for(int i=0;i<srcheight;i++) {
for(int j=0;j<srcwidth;j++) {
tmpHue[i][j] = xatan2f(l_b[i][j],l_a[i][j]);
}
}
#endif
tmpChr = new float*[srcheight];
for (int i=0; i<srcheight; i++) {
tmpChr[i] = new float[srcwidth];
}
#ifdef __SSE2__
#pragma omp parallel
{
__m128 div = _mm_set1_ps(327.68f);
#pragma omp for
for(int i=0;i<srcheight;i++) {
int j;
for(j=0;j<srcwidth-3;j+=4) {
_mm_storeu_ps(&tmpChr[i][j], _mm_sqrt_ps(SQRV(LVFU(l_b[i][j]))+SQRV(LVFU(l_a[i][j])))/div);
}
for(;j<srcwidth;j++) {
tmpChr[i][j] = sqrtf(SQR((l_b[i][j]))+SQR((l_a[i][j])))/327.68f;
}
}
}
#else
#pragma omp parallel for
for(int i=0;i<srcheight;i++) {
for(int j=0;j<srcwidth;j++) {
tmpChr[i][j] = sqrtf(SQR((l_b[i][j]))+SQR((l_a[i][j])))/327.68f;
}
}
#endif
}
// with the current implementation of idirpyr_eq_channel we can safely use the buffer from last level as buffer, saves some memory
float ** buffer = dirpyrlo[lastlevel-1];
for(int level = lastlevel - 1; level > 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; i<srcheight; i++)
delete [] tmpChr[i];
delete [] tmpChr;
for (int i=0; i<srcheight; i++)
delete [] tmpHue[i];
delete [] tmpHue;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#pragma omp parallel for
for (int i=0; i<srcheight; i++)
for (int j=0; j<srcwidth; j++) {
dst[i][j] = CLIP( buffer[i][j] ); // TODO: Really a clip necessary?
dest_a[i][j] = l_a[i][j];
dest_b[i][j] = l_b[i][j];
dst[i][j] = CLIP(buffer[i][j]); // TODO: Really a clip necessary?
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
}
void ImProcFunctions :: 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 scaleprev)
{
// StopWatch Stop1("Dirpyr equalizer CAM");
int lastlevel=maxlevel;
if(settings->verbose) 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<srcheight; i++)
for (int j=0; j<srcwidth; j++) {
@@ -241,44 +294,36 @@ namespace rtengine {
}
#if defined( __SSE2__ ) && defined( WIN32 )
__attribute__((force_align_arg_pointer)) void ImProcFunctions::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)
#else
void ImProcFunctions::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 )
#endif
SSEFUNCTION void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, int width, int height, int level, int scale)
{
//scale is spacing of directional averaging weights
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// calculate weights, compute directionally weighted average
int halfwin;
int scalewin;
if(level > 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)<noiselo) {
irangefn[i] = 1.f ;
irangefn[i] = 1.f + offs ;
} else {
irangefn[i] = 1.f + (mult[level]-1.f) * (noisehi-abs(i-0x10000))/(noisehi-noiselo+0.01f) ;
irangefn[i] = 1.f + offs + (mult[level]-1.f) * (noisehi-abs(i-0x10000))/(noisehi-noiselo+0.01f) ;
}
}
}
}
if(skinprot==0.f)
#ifdef _OPENMP
#pragma omp parallel for
#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]);
buffer[i][j] += irangefn[hipass+0x10000] * hipass;
}
}
else if(skinprot > 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)<noiselo) {
irangefn[i] = 1.f + offs ;
} else {
irangefn[i] = 1.f + offs + (mult[level]-1.f) * (noisehi-abs(i-0x10000))/(noisehi-noiselo+0.01f) ;
}
}
}
}
if(skinprot == 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]);
buffer[i][j] += irangefn[hipass+0x10000] * hipass ;
}
}
else if(skinprot > 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 ;

View File

@@ -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);

View File

@@ -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 <omp.h>
@@ -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<float>(params->vibrance.psthreshold.value[ThresholdSelector::TS_TOPLEFT]) / 100.0f;
float transitionweighting = static_cast<float>(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<float>(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<float>(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; i<height; i++)
for (int j=0; j<width; j++) {
//int pos = i*width+j;
float LL=lab->L[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<skend) {
if(Chprov < 60.0f) {//skin hue : todo ==> 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;