Speedup for Vibrance and Contrast by Detail Levels, Issue 2520
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
123
rtengine/color.h
123
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user