diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index cd2242c7d..683810a50 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -422,6 +422,8 @@ HISTORY_MSG_195;CAM02 - Courbe tonale HISTORY_MSG_196;CAM02 - Courbe tonale 2 HISTORY_MSG_197;CAM02 - Courbe couleur HISTORY_MSG_198;CAM02 - Courbe couleur +HISTORY_MSG_199;CAM02 - Montre les histogrammes CIECAM +HISTORY_MSG_200;CAM02 - Compression tonale avec Q HISTORY_NEWSNAPSHOTAS;Sous... HISTORY_NEWSNAPSHOT;Ajouter HISTORY_NEWSSDIALOGLABEL;Label de la capture: @@ -682,6 +684,9 @@ PREFERENCES_D50;5000K PREFERENCES_D55;5500K PREFERENCES_D60;6000K PREFERENCES_D65;6500K +PREFERENCES_CIEART;CIECAM02 optimisation +PREFERENCES_CIEART_LABEL;Utilise la précision float au lieu de double pour CIECAM02 +PREFERENCES_CIEART_TOOLTIP;Si activé, les calculs CIECAM sont réalisés en précision float au lieu de précision double. Cela amène un léger accroissement de vitesse, et une légère réduction de qualité PREFERENCES_DARKFRAMEFOUND;Trouvé PREFERENCES_DARKFRAMESHOTS;image(s) PREFERENCES_DARKFRAMETEMPLATES;modèle(s) @@ -980,7 +985,7 @@ TP_CROP_X;X TP_CROP_Y;Y TP_DARKFRAME_AUTOSELECT;Sélection automatique TP_DARKFRAME_LABEL;Trame Noire -TP_DEFRINGE_LABEL;Aberration chromatique +TP_DEFRINGE_LABEL;Aberration chromatique (lab / ciecam02) TP_DEFRINGE_RADIUS;Rayon TP_DEFRINGE_THRESHOLD;Seuil TP_DETAIL_AMOUNT;Quantité @@ -988,7 +993,7 @@ TP_DIRPYRDENOISE_CHROMA;Chrominance TP_DIRPYRDENOISE_GAMMA;Gamma TP_DIRPYRDENOISE_LABEL;Réduction du bruit TP_DIRPYRDENOISE_LUMA;Luminance -TP_DIRPYREQUALIZER_LABEL;Contraste par niveaux de détail +TP_DIRPYREQUALIZER_LABEL;Contraste par niveaux de détail (lab / ciecam02) TP_DIRPYREQUALIZER_LUMACOARSEST;les plus gros TP_DIRPYREQUALIZER_LUMACONTRAST_MINUS;Contraste- TP_DIRPYREQUALIZER_LUMACONTRAST_PLUS;Contraste+ @@ -1000,7 +1005,7 @@ TP_DISTORTION_AUTO;Correction auto de la distorsion TP_DISTORTION_AUTO_TIP;(Experimental) Corrige la distorsion de l'objectif automatiquement pour certains APN (M4/3, quelques compacts, etc.) TP_DISTORTION_LABEL;Distorsion TP_EPD_EDGESTOPPING;Arrêt des bords -TP_EPD_LABEL;Compression tonale [Lab] ou [CIECAM02] +TP_EPD_LABEL;Compression tonale (lab / ciecam02) TP_EPD_REWEIGHTINGITERATES;Itérations de la pondération TP_EPD_SCALE;Échelle TP_EPD_STRENGTH;Force @@ -1197,6 +1202,7 @@ TP_SHADOWSHLIGHTS_LOCALCONTR;Contraste local TP_SHADOWSHLIGHTS_RADIUS;Rayon TP_SHADOWSHLIGHTS_SHADOWS;Ombres TP_SHADOWSHLIGHTS_SHTONALW;Amplitude tonale des ombres +TP_SHARPENING_TOOLTIP;Un effet légèrement différent peut être obtenu avec CIECAM02. Si différence observée, ajuster les réglages TP_SHARPENEDGE_AMOUNT;Quantité TP_SHARPENEDGE_LABEL;Bords TP_SHARPENEDGE_PASSES;Itérations @@ -1206,7 +1212,7 @@ TP_SHARPENING_EDRADIUS;Rayon TP_SHARPENING_EDTOLERANCE;Tolérance des bords TP_SHARPENING_HALOCONTROL;Contrôle du halo TP_SHARPENING_HCAMOUNT;Quantité -TP_SHARPENING_LABEL;Netteté +TP_SHARPENING_LABEL;Netteté (lab / ciecam02) TP_SHARPENING_METHOD;Méthode TP_SHARPENING_ONLYEDGES;Améliorer seulement les bords TP_SHARPENING_RADIUS;Rayon @@ -1217,7 +1223,7 @@ TP_SHARPENING_RLD_ITERATIONS;Itérations TP_SHARPENING_THRESHOLD;Seuil TP_SHARPENING_USM;Masque flou TP_SHARPENMICRO_AMOUNT;Quantité -TP_SHARPENMICRO_LABEL;Microcontraste +TP_SHARPENMICRO_LABEL;Microcontraste (lab / ciecam02) TP_SHARPENMICRO_MATRIX;Matrice 3×3 au lieu de 5×5 TP_SHARPENMICRO_UNIFORMITY;Uniformité TP_VIBRANCE_AVOIDCOLORSHIFT;Éviter les dérives de teinte @@ -1307,8 +1313,6 @@ ZOOMPANEL_ZOOMOUT;Zoom - !GENERAL_CLOSE;Close !HISTOGRAM_TOOLTIP_CHRO;Show/Hide chromaticity histogram -!HISTORY_MSG_199;CAM02 - Show CIECAM in histograms -!HISTORY_MSG_200;CAM02 - Tone mapping with Q !HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s !PARTIALPASTE_LENSPROFILE;Lens correction profile !PREFERENCES_FLUOF2;Fluorescent F2 diff --git a/rtdata/languages/default b/rtdata/languages/default index 6fa811a08..8428dea72 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -425,7 +425,7 @@ HISTORY_MSG_196;CAM02 - Tone curve 2 HISTORY_MSG_197;CAM02 - Color curve HISTORY_MSG_198;CAM02 - Color curve HISTORY_MSG_199;CAM02 - Show CIECAM in histograms -HISTORY_MSG_200;CAM02 - Tone mapping with Q +HISTORY_MSG_200;CAMO2 - Tone mapping with Q HISTORY_NEWSNAPSHOTAS;As... HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s @@ -688,6 +688,9 @@ PREFERENCES_D50;5000K PREFERENCES_D55;5500K PREFERENCES_D60;6000K PREFERENCES_D65;6500K +PREFERENCES_CIEART;CIECAM02 optimization +PREFERENCES_CIEART_LABEL;Use float precision instead of double in CIECAM02 +PREFERENCES_CIEART_TOOLTIP;If enabled, CIECAM02 calculations are performed in float precision instead of double precision. This provides a small increase in speed at expense of a minor loss of quality PREFERENCES_DARKFRAMEFOUND;Found PREFERENCES_DARKFRAMESHOTS;shots PREFERENCES_DARKFRAMETEMPLATES;templates @@ -894,9 +897,9 @@ TP_COARSETRAF_TOOLTIP_HFLIP;Flip horizontally TP_COARSETRAF_TOOLTIP_ROTLEFT;Rotate left.\nShortcut: [ TP_COARSETRAF_TOOLTIP_ROTRIGHT;Rotate right.\nShortcut: ] TP_COARSETRAF_TOOLTIP_VFLIP;Flip vertically -TP_COLORAPP_ADAPTSCENE;Adaptation luminosity (cd/m2) +TP_COLORAPP_ADAPTSCENE;Adaptation scene luminosity(cd/m2) TP_COLORAPP_ADAPTSCENE_TOOLTIP;Absolute luminance of the scene environnement\n(usually 2000cd/m2) -TP_COLORAPP_ADAPTVIEWING;Adaptation luminosity (cd/m2) +TP_COLORAPP_ADAPTVIEWING;Adaptation viewing luminosity (cd/m2) TP_COLORAPP_ADAPTVIEWING_TOOLTIP;Absolute luminance of the viewing environnement\n(usually 16cd/m2) TP_COLORAPP_ALGO;Algorithm TP_COLORAPP_ALGO_ALL;All @@ -959,6 +962,8 @@ TP_COLORAPP_TCMODE_LIGHTNESS;Lightness TP_COLORAPP_TCMODE_SATUR;Saturation TP_COLORAPP_TONECIE;Tone-mapping with Q brightness CIECAM TP_COLORAPP_TONECIE_TOOLTIP;Additional tone mapping adjustments are controlled in Tone Mapping section and must be enabled for tone mapping to engage. +TP_COLORAPP_SHARPCIE;Sharpening & Contrast(det/mic) & Defringe with Q/C +TP_COLORAPP_SHARPCIE_TOOLTIP;Additional sharpening / Contrast by details / Microcontrast / Defringe are controlled in appropriates sections and must be enabled to engage\n. See label (lab / ciecam02) TP_COLORAPP_WBCAM;WB [RT+CAT02] + [output] TP_COLORAPP_WBRT;WB [RT] + [output] TP_CROP_FIXRATIO;Fix ratio: @@ -982,7 +987,7 @@ TP_CROP_X;X TP_CROP_Y;Y TP_DARKFRAME_AUTOSELECT;Auto selection TP_DARKFRAME_LABEL;Dark Frame -TP_DEFRINGE_LABEL;Defringe +TP_DEFRINGE_LABEL;Defringe (lab / ciecam02) TP_DEFRINGE_RADIUS;Radius TP_DEFRINGE_THRESHOLD;Threshold TP_DIRPYRDENOISE_CHROMA;Chrominance @@ -990,10 +995,10 @@ TP_DIRPYRDENOISE_GAMMA;Gamma TP_DIRPYRDENOISE_LABEL;Noise Reduction (raw images only) TP_DIRPYRDENOISE_LDETAIL;Luminance Detail TP_DIRPYRDENOISE_LUMA;Luminance -TP_DIRPYREQUALIZER_LABEL;Contrast by Detail Levels +TP_DIRPYREQUALIZER_LABEL;Contrast by Detail Levels (lab / ciecam02) TP_DIRPYREQUALIZER_LUMACOARSEST;Coarsest TP_DIRPYREQUALIZER_LUMACONTRAST_MINUS;Contrast- -TP_DIRPYREQUALIZER_LUMACONTRAST_PLUS;Contrast+ +TP_DIRPYREQUALIZER_LUMACONTRAST_PLUS;Contrast+ TP_DIRPYREQUALIZER_LUMAFINEST;Finest TP_DIRPYREQUALIZER_LUMANEUTRAL;Neutral TP_DIRPYREQUALIZER_THRESHOLD;Threshold @@ -1002,7 +1007,7 @@ TP_DISTORTION_AUTO;Auto Distortion Correction TP_DISTORTION_AUTO_TIP;(Exprimental) Correct lens distortion automatically for some cameras (Micro 4/3, some compact digital cameras, etc.) TP_DISTORTION_LABEL;Distortion TP_EPD_EDGESTOPPING;Edge Stopping -TP_EPD_LABEL;Tone Mapping [Lab] or [CIECAM02] +TP_EPD_LABEL;Tone Mapping (lab / ciecam02) TP_EPD_REWEIGHTINGITERATES;Reweighting Iterates TP_EPD_SCALE;Scale TP_EPD_STRENGTH;Strength @@ -1189,6 +1194,7 @@ TP_SHADOWSHLIGHTS_LOCALCONTR;Local Contrast TP_SHADOWSHLIGHTS_RADIUS;Radius TP_SHADOWSHLIGHTS_SHADOWS;Shadows TP_SHADOWSHLIGHTS_SHTONALW;Tonal Width for Shadows +TP_SHARPENING_TOOLTIP;Expect a slightly different effect when used with CIECAM02. If difference is observed, adjust to taste. TP_SHARPENEDGE_AMOUNT;Quantity TP_SHARPENEDGE_LABEL;Edges TP_SHARPENEDGE_PASSES;Iterations @@ -1198,7 +1204,7 @@ TP_SHARPENING_EDRADIUS;Radius TP_SHARPENING_EDTOLERANCE;Edge Tolerance TP_SHARPENING_HALOCONTROL;Halo control TP_SHARPENING_HCAMOUNT;Amount -TP_SHARPENING_LABEL;Sharpening +TP_SHARPENING_LABEL;Sharpening (lab / ciecam02) TP_SHARPENING_METHOD;Method TP_SHARPENING_ONLYEDGES;Sharpen only edges TP_SHARPENING_RADIUS;Radius @@ -1209,7 +1215,7 @@ TP_SHARPENING_RLD_ITERATIONS;Iterations TP_SHARPENING_THRESHOLD;Threshold TP_SHARPENING_USM;Unsharp Mask TP_SHARPENMICRO_AMOUNT;Quantity -TP_SHARPENMICRO_LABEL;Microcontrast +TP_SHARPENMICRO_LABEL;Microcontrast (lab / ciecam02) TP_SHARPENMICRO_MATRIX;3×3 matrix instead of 5×5 TP_SHARPENMICRO_UNIFORMITY;Uniformity TP_VIBRANCE_AVOIDCOLORSHIFT;Avoid color shift diff --git a/rtengine/PF_correct_RT.cc b/rtengine/PF_correct_RT.cc index ed8f623c7..a6efb85e0 100644 --- a/rtengine/PF_correct_RT.cc +++ b/rtengine/PF_correct_RT.cc @@ -79,7 +79,7 @@ void ImProcFunctions::PF_correct_RT(LabImage * src, LabImage * dst, double radiu } } chromave /= (height*width); - +// printf("Chro %f \n",chromave); #ifdef _OPENMP #pragma omp parallel for #endif @@ -91,15 +91,15 @@ void ImProcFunctions::PF_correct_RT(LabImage * src, LabImage * dst, double radiu //test for pixel darker than some fraction of neighborhood ave, near an edge, more saturated than average /*if (100*tmp1->L[i][j]>50*src->L[i][j] && \*/ /*1000*abs(tmp1->L[i][j]-src->L[i][j])>thresh*(tmp1->L[i][j]+src->L[i][j]) && \*/ - if (33*fringe[i*width+j]>thresh*chromave) { - float atot=0; - float btot=0; - float norm=0; + if (33.f*fringe[i*width+j]>thresh*chromave) { + float atot=0.f; + float btot=0.f; + float norm=0.f; float wt; for (int i1=max(0,i-halfwin+1); i1a[i1][j1]; btot += wt*src->b[i1][j1]; norm += wt; @@ -125,6 +125,145 @@ void ImProcFunctions::PF_correct_RT(LabImage * src, LabImage * dst, double radiu delete tmp1; free(fringe); } +void ImProcFunctions::PF_correct_RTcam(CieImage * src, CieImage * dst, double radius, int thresh) { + int halfwin = ceil(2*radius)+1; + +#include "rt_math.h" + + // local variables + int width=src->W, height=src->H; + float piid=3.14159265f/180.f; + //temporary array to store chromaticity + int (*fringe); + fringe = (int (*)) calloc ((height)*(width), sizeof *fringe); + + float** sraa; + sraa = new float*[height]; + for (int i=0; iC_p[i][j]*cos(piid*src->h_p[i][j]); + } + float** tmaa; + tmaa = new float*[height]; + for (int i=0; iC_p[i][j]*sin(piid*src->h_p[i][j]); + } + float** tmbb; + tmbb = new float*[height]; + for (int i=0; i buffer(max(src->W,src->H)); + gaussHorizontal (sraa, tmaa, buffer, src->W, src->H, radius); + gaussHorizontal (srbb, tmbb, buffer, src->W, src->H, radius); + gaussVertical (tmaa, tmaa, buffer, src->W, src->H, radius); + gaussVertical (tmbb, tmbb, buffer, src->W, src->H, radius); + // gaussHorizontal (src->sh_p, tmL, buffer, src->W, src->H, radius); + // gaussVertical (tmL, tmL, buffer, src->W, src->H, radius); + + } + +//#ifdef _OPENMP +//#pragma omp parallel for +//#endif + float chromave=0; + for(int i = 0; i < height; i++ ) { + for(int j = 0; j < width; j++) { + float chroma =SQR(sraa[i][j]-tmaa[i][j])+SQR(srbb[i][j]-tmbb[i][j]); + chromave += chroma; + fringe[i*width+j]=chroma; + } + } + chromave /= (height*width); + // printf("Chromave CAM %f \n",chromave); + +#ifdef _OPENMP +#pragma omp parallel for +#endif + + for(int i = 0; i < height; i++ ) { + for(int j = 0; j < width; j++) { + tmaa[i][j] = sraa[i][j]; + tmbb[i][j] = srbb[i][j]; + + //test for pixel darker than some fraction of neighborhood ave, near an edge, more saturated than average + /*if (100*tmp1->L[i][j]>50*src->L[i][j] && \*/ + /*1000*abs(tmp1->L[i][j]-src->L[i][j])>thresh*(tmp1->L[i][j]+src->L[i][j]) && \*/ + if (33.f*fringe[i*width+j]>thresh*chromave) { + float atot=0.f; + float btot=0.f; + float norm=0.f; + float wt; + for (int i1=max(0,i-halfwin+1); i1sh_p[i][j] = src->sh_p[i][j]; + float intera = tmaa[i][j]; + float interb = tmbb[i][j]; + dst->h_p[i][j]=(atan2(interb,intera))/piid; + dst->C_p[i][j]=sqrt(SQR(interb)+SQR(intera)); + } + } + for (int i=0; idata, W*H*5*sizeof(float)); + memcpy(data, Img->data, W*H*6*sizeof(float)); } } diff --git a/rtengine/cieimage.h b/rtengine/cieimage.h index ee9534451..ca6e5785c 100644 --- a/rtengine/cieimage.h +++ b/rtengine/cieimage.h @@ -34,7 +34,8 @@ public: float** Q_p; float** M_p; float** C_p; - //float** s_p; + float** sh_p; +// float** ch_p; float** h_p; CieImage (int w, int h); diff --git a/rtengine/color.cc b/rtengine/color.cc index 4db2bcce8..738211e92 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -561,6 +561,48 @@ namespace rtengine { else s=ko*sres; } + void Color::skinredfloat ( float J, float h, float sres, float Sp, float dred, float protect_red, int sk, float rstprotection, float ko, float &s) + { + float factorskin, factorsat,factor, factorskinext, interm; + float scale = 100.0f/100.1f;//reduction in normal zone + float scaleext=1.0f;//reduction in transition zone + float protect_redh; + float deltaHH=0.3f;//HH value transition : I have choice 0.3 radians + float HH; + bool doskin=false; + //rough correspondence between h (JC) and H (lab) that has relatively little importance because transitions that blur the correspondence is not linear + if ((float)h>8.6f && (float)h<=74.f ) {HH=(1.15f/65.4f)*(float)h-0.0012f; doskin=true;}//H > 0.15 H<1.3 + else if((float)h>0.f && (float)h<=8.6f ) {HH=(0.19f/8.6f )*(float)h-0.04f; doskin=true;}//H>-0.04 H < 0.15 + else if((float)h>355.f && (float)h<=360.f) {HH=(0.11f/5.0f )*(float)h-7.96f; doskin=true;}//H>-0.15 <-0.04 + else if((float)h>74.f && (float)h<95.f ) {HH=(0.30f/21.0f)*(float)h+0.24285f; doskin=true;}//H>1.3 H<1.6 + + if(doskin) + { + float chromapro=sres/Sp; + if(sk==1){//in C mode to adapt dred to J + if (J<16.0) dred = 40.0f; + else if(J<22.0) dred = (4.1666f)*(float)J -26.6f; + else if(J<60.0) dred = 55.0f; + else if(J<70.0) dred = -1.5f*(float)J +145.0f; + else dred = 40.0f; + } + if(chromapro>0.0) Color::scalered ( rstprotection, chromapro, 0.0, HH, deltaHH, scale, scaleext);//Scale factor + if(chromapro>1.0) {interm=(chromapro-1.0f)*100.0f; + factorskin= 1.0f+(interm*scale)/100.0f; + factorskinext=1.0f+(interm*scaleext)/100.0f;} + else { + factorskin= chromapro ; + factorskinext= chromapro ; + } + factorsat=chromapro; + factor=factorsat; + Color::transitred ( HH, s, dred, factorskin, protect_red, factorskinext, deltaHH, factorsat, factor); //transition + s*=factor; + } + else s=ko*sres; + + } + void Color::scalered ( float rstprotection, float param, float limit, float HH, float deltaHH, float &scale,float &scaleext) diff --git a/rtengine/color.h b/rtengine/color.h index b0836f1a2..5ddfa91d4 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -165,6 +165,7 @@ public: static void scalered ( float rstprotection, float param, float limit, float HH, float deltaHH, float &scale, float &scaleext); static void transitred (float HH, float Chprov1, float dred, float factorskin, float protect_red, float factorskinext, float deltaHH, float factorsat, float &factor); 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); //void gamutmap(LabImage* ); static void gamutmap(float &X, float &Y, float &Z, const double p[3][3]); diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc index 2bdf6816d..db0b35925 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -903,6 +903,16 @@ void ColorTemp::curvecolor(double satind, double satval, double &sres, double pa sres = satval*(1.+(satind)/100.); } } +void ColorTemp::curvecolorfloat(float satind, float satval, float &sres, float parsat) { + if (satind >=0.0f) { + sres = (1.-(satind)/100.f)*satval+(satind)/100.f*(1.f-SQR(SQR(1.f-min(satval,1.0f)))); + if (sres>parsat) sres=parsat; + if (sres<0.f) sres=0.f; + } else { + if (satind < -0.1f) + sres = satval*(1.f+(satind)/100.f); + } +} void ColorTemp::curveJ (double br, double contr, int db, LUTf & outCurve, LUTu & histogram ) { @@ -1001,6 +1011,102 @@ void ColorTemp::curveJ (double br, double contr, int db, LUTf & outCurve, LUTu & // for (int i=0; i<32768; i++) outCurve[i] = 32768.0*dcurve[i]; for (int i=0; i<(db*32768); i++) outCurve[i] = db*32768.0*dcurve[i]; } +void ColorTemp::curveJfloat (float br, float contr, int db, LUTf & outCurve, LUTu & histogram ) { + LUTf dcurve(65536,0); + int skip=1; + + // check if brightness curve is needed + if (br>0.00001f || br<-0.00001f) { + + std::vector brightcurvePoints; + brightcurvePoints.resize(9); + brightcurvePoints.at(0) = double(DCT_NURBS); + + brightcurvePoints.at(1) = 0.f; // black point. Value in [0 ; 1] range + brightcurvePoints.at(2) = 0.f; // black point. Value in [0 ; 1] range + + if (br>0) { + brightcurvePoints.at(3) = 0.1f; // toe point + brightcurvePoints.at(4) = 0.1f+br/150.0f; //value at toe point + + brightcurvePoints.at(5) = 0.7f; // shoulder point + brightcurvePoints.at(6) = min(1.0f,0.7f+br/300.0f); //value at shoulder point + } else { + brightcurvePoints.at(3) = 0.1f-br/150.0f; // toe point + brightcurvePoints.at(4) = 0.1f; // value at toe point + + brightcurvePoints.at(5) = min(1.0f,0.7f-br/300.0f); // shoulder point + brightcurvePoints.at(6) = 0.7f; // value at shoulder point + } + brightcurvePoints.at(7) = 1.f; // white point + brightcurvePoints.at(8) = 1.f; // value at white point + + DiagonalCurve* brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); + + // Applying brightness curve + for (int i=0; i<32768; i++) { + + // change to [0,1] range + float val = (float)i / 32767.0f; + + // apply brightness curve + val = brightcurve->getVal (val); + + // store result in a temporary array + dcurve[i] = CLIPD(val); + } + delete brightcurve; + } + else { + // for (int i=0; i<32768; i++) { // L values range up to 32767, higher values are for highlight overflow + for (int i=0; i<(32768*db); i++) { // L values range up to 32767, higher values are for highlight overflow + + // set the identity curve in the temporary array + dcurve[i] = (float)i / (db*32768.0f); + } + } + + + if (contr>0.00001f || contr<-0.00001f) { + + // compute mean luminance of the image with the curve applied + int sum = 0; + float avg = 0; + //float sqavg = 0; + for (int i=0; i<32768; i++) { + avg += dcurve[i] * histogram[i];//approximation for average : usage of L (lab) instead of J + sum += histogram[i]; + } + avg /= sum; + std::vector contrastcurvePoints; + contrastcurvePoints.resize(9); + contrastcurvePoints.at(0) = double(DCT_NURBS); + + contrastcurvePoints.at(1) = 0.f; // black point. Value in [0 ; 1] range + contrastcurvePoints.at(2) = 0.f; // black point. Value in [0 ; 1] range + + contrastcurvePoints.at(3) = avg-avg*(0.6f-contr/250.0f); // toe point + contrastcurvePoints.at(4) = avg-avg*(0.6f+contr/250.0f); // value at toe point + + contrastcurvePoints.at(5) = avg+(1-avg)*(0.6f-contr/250.0f); // shoulder point + contrastcurvePoints.at(6) = avg+(1-avg)*(0.6f+contr/250.0f); // value at shoulder point + + contrastcurvePoints.at(7) = 1.f; // white point + contrastcurvePoints.at(8) = 1.f; // value at white point + + DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); + + // apply contrast enhancement + for (int i=0; i<(32768*db); i++) { + dcurve[i] = contrastcurve->getVal (dcurve[i]); + } + + delete contrastcurve; + } + + // for (int i=0; i<32768; i++) outCurve[i] = 32768.0*dcurve[i]; + for (int i=0; i<(db*32768); i++) outCurve[i] = db*32768.0f*dcurve[i]; +} void ColorTemp::cieCAT02(double Xw, double Yw, double Zw, double &CAM02BB00,double &CAM02BB01,double &CAM02BB02,double &CAM02BB10,double &CAM02BB11,double &CAM02BB12,double &CAM02BB20,double &CAM02BB21,double &CAM02BB22, double adap ) { @@ -1596,8 +1702,131 @@ and also gamut correction M.H.Brill S.Susstrunk * SOFTWARE. * */ +void ColorTemp::xyz_to_cat02( double &r, double &g, double &b, double x, double y, double z, int gamu ) +{ +gamu=1; +if(gamu==0){ + r = ( 0.7328 * x) + (0.4296 * y) - (0.1624 * z); + g = (-0.7036 * x) + (1.6975 * y) + (0.0061 * z); + b = ( 0.0030 * x) + (0.0136 * y) + (0.9834 * z); + } +else if (gamu==1) {//gamut correction M.H.Brill S.Susstrunk + //r = ( 0.7328 * x) + (0.4296 * y) - (0.1624 * z); + //g = (-0.7036 * x) + (1.6975 * y) + (0.0061 * z); + //b = ( 0.0000 * x) + (0.0000 * y) + (1.0000 * z); + r = ( 1.007245 * x) + (0.011136* y) - (0.018381 * z);//Changjun Li + g = (-0.318061 * x) + (1.314589 * y) + (0.003471 * z); + b = ( 0.0000 * x) + (0.0000 * y) + (1.0000 * z); + +} +} -inline void Aab_to_rgb( double &r, double &g, double &b, double A, double aa, double bb, double nbb ) + void ColorTemp::xyz_to_cat02float( float &r, float &g, float &b, float x, float y, float z, int gamu ) +{ +gamu=1; +if(gamu==0){ + r = ( 0.7328f * x) + (0.4296f * y) - (0.1624f * z); + g = (-0.7036f * x) + (1.6975f * y) + (0.0061f * z); + b = ( 0.0030f * x) + (0.0136f * y) + (0.9834f * z); + } +else if (gamu==1) {//gamut correction M.H.Brill S.Susstrunk + //r = ( 0.7328 * x) + (0.4296 * y) - (0.1624 * z); + //g = (-0.7036 * x) + (1.6975 * y) + (0.0061 * z); + //b = ( 0.0000 * x) + (0.0000 * y) + (1.0000 * z); + r = ( 1.007245f * x) + (0.011136f* y) - (0.018381f * z);//Changjun Li + g = (-0.318061f * x) + (1.314589f * y) + (0.003471f * z); + b = ( 0.0000f * x) + (0.0000f * y) + (1.0000f * z); + +} +} + + + void ColorTemp::cat02_to_xyz( double &x, double &y, double &z, double r, double g, double b, int gamu ) +{ +gamu=1; +if(gamu==0) { + x = ( 1.096124 * r) - (0.278869 * g) + (0.182745 * b); + y = ( 0.454369 * r) + (0.473533 * g) + (0.072098 * b); + z = (-0.009628 * r) - (0.005698 * g) + (1.015326 * b); + } +else if(gamu==1) {//gamut correction M.H.Brill S.Susstrunk + //x = ( 1.0978566 * r) - (0.277843 * g) + (0.179987 * b); + //y = ( 0.455053 * r) + (0.473938 * g) + (0.0710096* b); + //z = ( 0.000000 * r) - (0.000000 * g) + (1.000000 * b); + x = ( 0.99015849 * r) - (0.00838772* g) + (0.018229217 * b);//Changjun Li + y = ( 0.239565979 * r) + (0.758664642 * g) + (0.001770137* b); + z = ( 0.000000 * r) - (0.000000 * g) + (1.000000 * b); + +} +} + + void ColorTemp::cat02_to_xyzfloat( float &x, float &y, float &z, float r, float g, float b, int gamu ) +{ +gamu=1; +if(gamu==0) { + x = ( 1.096124f * r) - (0.278869f * g) + (0.182745f * b); + y = ( 0.454369f * r) + (0.473533f * g) + (0.072098f * b); + z = (-0.009628f * r) - (0.005698f * g) + (1.015326f * b); + } +else if(gamu==1) {//gamut correction M.H.Brill S.Susstrunk + //x = ( 1.0978566 * r) - (0.277843 * g) + (0.179987 * b); + //y = ( 0.455053 * r) + (0.473938 * g) + (0.0710096* b); + //z = ( 0.000000 * r) - (0.000000 * g) + (1.000000 * b); + x = ( 0.99015849f * r) - (0.00838772f* g) + (0.018229217f * b);//Changjun Li + y = ( 0.239565979f * r) + (0.758664642f * g) + (0.001770137f* b); + z = ( 0.000000f * r) - (0.000000f * g) + (1.000000f * b); + +} +} + + +void ColorTemp::hpe_to_xyz( double &x, double &y, double &z, double r, double g, double b ) +{ + x = (1.910197 * r) - (1.112124 * g) + (0.201908 * b); + y = (0.370950 * r) + (0.629054 * g) - (0.000008 * b); + z = b; + +} + + void ColorTemp::hpe_to_xyzfloat( float &x, float &y, float &z, float r, float g, float b ) +{ + x = (1.910197f * r) - (1.112124f * g) + (0.201908f * b); + y = (0.370950f * r) + (0.629054f * g) - (0.000008f * b); + z = b; + +} + + + +void ColorTemp::cat02_to_hpe( double &rh, double &gh, double &bh, double r, double g, double b, int gamu ) +{ gamu=1; + if(gamu==0){ + rh = ( 0.7409792 * r) + (0.2180250 * g) + (0.0410058 * b); + gh = ( 0.2853532 * r) + (0.6242014 * g) + (0.0904454 * b); + bh = (-0.0096280 * r) - (0.0056980 * g) + (1.0153260 * b); + } + else if (gamu==1) {//Changjun Li + rh = ( 0.550930835 * r) + (0.519435987* g) - ( 0.070356303* b); + gh = ( 0.055954056 * r) + (0.89973132 * g) + (0.044315524 * b); + bh = (0.0 * r) - (0.0* g) + (1.0 * b); + } +} +void ColorTemp::cat02_to_hpefloat( float &rh, float &gh, float &bh, float r, float g, float b, int gamu ) +{ gamu=1; + if(gamu==0){ + rh = ( 0.7409792f * r) + (0.2180250f * g) + (0.0410058f * b); + gh = ( 0.2853532f * r) + (0.6242014f * g) + (0.0904454f * b); + bh = (-0.0096280f * r) - (0.0056980f * g) + (1.0153260f * b); + } + else if (gamu==1) {//Changjun Li + rh = ( 0.550930835f * r) + (0.519435987f* g) - ( 0.070356303f* b); + gh = ( 0.055954056f * r) + (0.89973132f * g) + (0.044315524f * b); + bh = (0.0f * r) - (0.0f* g) + (1.0f * b); + } +} + + + void ColorTemp::Aab_to_rgb( double &r, double &g, double &b, double A, double aa, double bb, double nbb ) { double x = (A / nbb) + 0.305; @@ -1608,8 +1837,19 @@ inline void Aab_to_rgb( double &r, double &g, double &b, double A, double aa, do /* c1 c6 c7 */ b = (0.32787 * x) - (0.15681 * aa) - (4.49038 * bb); } + void ColorTemp::Aab_to_rgbfloat( float &r, float &g, float &b, float A, float aa, float bb, float nbb ) +{ + float x = (A / nbb) + 0.305f; -inline void calculate_ab( double &aa, double &bb, double h, double e, double t, double nbb, double a ) + /* c1 c2 c3 */ + r = (0.32787f * x) + (0.32145f * aa) + (0.20527f * bb); + /* c1 c4 c5 */ + g = (0.32787f * x) - (0.63507f * aa) - (0.18603f * bb); + /* c1 c6 c7 */ + b = (0.32787f * x) - (0.15681f * aa) - (4.49038f * bb); +} + +void ColorTemp::calculate_ab( double &aa, double &bb, double h, double e, double t, double nbb, double a ) { double hrad = (h * M_PI) / 180.0; double sinh = sin( hrad ); @@ -1636,6 +1876,36 @@ inline void calculate_ab( double &aa, double &bb, double h, double e, double t, bb = (aa * sinh) / cosh; } } +void ColorTemp::calculate_abfloat( float &aa, float &bb, float h, float e, float t, float nbb, float a ) +{ + float hrad = (h * M_PI) / 180.0f; + float sinh = sin( hrad ); + float cosh = cos( hrad ); + float x = (a / nbb) + 0.305f; + float p3 = 21.0f/20.0f; + if( fabs( sinh ) >= fabs( cosh ) ) { + bb = ((0.32787f * x) * (2.0f + p3)) / + ((e / (t * sinh)) - + // ((0.32145 - 0.63507 - (p3 * 0.15681)) * (cosh / sinh)) - + // (0.20527 - 0.18603 - (p3 * 4.49038))); + ((-0.31362f - (p3 * 0.15681f)) * (cosh / sinh)) - + (0.01924f - (p3 * 4.49038f))); + + aa = (bb * cosh) / sinh; + } else { + aa = ((0.32787f * x) * (2.0f + p3)) / + ((e / (t * cosh)) - + // (0.32145 - 0.63507 - (p3 * 0.15681)) - + // ((0.20527 - 0.18603 - (p3 * 4.49038)) * (sinh / cosh))); + (-0.31362f - (p3 * 0.15681f)) - + ((0.01924f - (p3 * 4.49038f)) * (sinh / cosh))); + + bb = (aa * sinh) / cosh; + } +} + + + void ColorTemp::xyz2jchqms_ciecam02( double &J, double &C, double &h, double &Q, double &M, double &s,double &aw, double &fl, double &wh, double x, double y, double z, double xw, double yw, double zw, double yb, double la, double f, double c, double nc, double pilotd, bool doneinit, int gamu) @@ -1727,6 +1997,98 @@ void ColorTemp::xyz2jchqms_ciecam02( double &J, double &C, double &h, double &Q, } +void ColorTemp::xyz2jchqms_ciecam02float( float &J, float &C, float &h, float &Q, float &M, float &s,float &aw, float &fl, float &wh, + float x, float y, float z, float xw, float yw, float zw, + float yb, float la, float f, float c, float nc, float pilotd, bool doneinit, int gamu) +{ + float r, g, b; + float rw, gw, bw; + float rc, gc, bc; + float rp, gp, bp; + float rpa, gpa, bpa; + float a, ca, cb; + float d; + float n, nbb, ncb; + float e, t; + float cz; + float myh, myj, myc, myq, mym, mys; + float pfl; + gamu=1; + xyz_to_cat02float( r, g, b, x, y, z, gamu ); + xyz_to_cat02float( rw, gw, bw, xw, yw, zw, gamu ); + + if(doneinit){//if one day, we have a pipette... + n = yb / yw; + if(pilotd==2.0) d = d_factorfloat( f, la );else d=pilotd; + fl = calculate_fl_from_la_ciecam02float( la ); + nbb = ncb = 0.725f * pow_F( 1.0f / n, 0.2f ); + cz = 1.48f + sqrt( n ); + aw = achromatic_response_to_whitefloat( xw, yw, zw, d, fl, nbb, gamu ); + wh =( 4.0f / c ) * ( aw + 4.0f ) * pow_F( fl, 0.25f ); + pfl = pow_F( fl, 0.25f ); + doneinit=false; + } + + rc = r * (((yw * d) / rw) + (1.0 - d)); + gc = g * (((yw * d) / gw) + (1.0 - d)); + bc = b * (((yw * d) / bw) + (1.0 - d)); + + ColorTemp::cat02_to_hpefloat( rp, gp, bp, rc, gc, bc, gamu ); + if(gamu==1){//gamut correction M.H.Brill S.Susstrunk + rp=MAXR(rp,0.0f); + gp=MAXR(gp,0.0f); + bp=MAXR(bp,0.0f); + } + rpa = nonlinear_adaptationfloat( rp, fl ); + gpa = nonlinear_adaptationfloat( gp, fl ); + bpa = nonlinear_adaptationfloat( bp, fl ); + + ca = rpa - ((12.0f * gpa) / 11.0f) + (bpa / 11.0f); + cb = (1.0f / 9.0f) * (rpa + gpa - (2.0f * bpa)); + + myh = (180.0f / M_PI) * atan2( cb, ca ); + if( myh < 0.0f ) myh += 360.0f; + //we can also calculate H, if necessary...but it's using time...for what usage ? + /*double temp; + if(myh<20.14) { + temp = ((myh + 122.47)/1.2) + ((20.14 - myh)/0.8); + H = 300 + (100*((myh + 122.47)/1.2)) / temp; + } + else if(myh < 90.0) { + temp = ((myh - 20.14)/0.8) + ((90.00 - myh)/0.7); + H = (100*((myh - 20.14)/0.8)) / temp; + } + else if (myh < 164.25) { + temp = ((myh - 90.00)/0.7) + ((164.25 - myh)/1.0); + H = 100 + ((100*((myh - 90.00)/0.7)) / temp); + } + else if (myh < 237.53) { + temp = ((myh - 164.25)/1.0) + ((237.53 - myh)/1.2); + H = 200 + ((100*((myh - 164.25)/1.0)) / temp); + } + else { + temp = ((myh - 237.53)/1.2) + ((360 - myh + 20.14)/0.8); + H = 300 + ((100*((myh - 237.53)/1.2)) / temp); + } + */ + a = ((2.0f * rpa) + gpa + ((1.0f / 20.0f) * bpa) - 0.305f) * nbb; + if (gamu==1) a=MAXR(a,0.0f);//gamut correction M.H.Brill S.Susstrunk + J = 100.0f * pow_F( a / aw, c * cz ); + + e = ((12500.0f / 13.0f) * nc * ncb) * (cos( ((myh * M_PI) / 180.0f) + 2.0f ) + 3.8f); + t = (e * sqrt( (ca * ca) + (cb * cb) )) / (rpa + gpa + ((21.0f / 20.0f) * bpa)); + + C = pow_F( t, 0.9f ) * sqrt( J / 100.0f ) + * pow_F( 1.64f - pow_F( 0.29f, n ), 0.73f ); + + Q = wh * sqrt( J / 100.0f ); + M = C * pfl; + s = 100.0f * sqrt( M / Q ); + h = myh; + +} + + void ColorTemp::jch2xyz_ciecam02( double &x, double &y, double &z, double J, double C, double h, double xw, double yw, double zw, double yb, double la, @@ -1775,6 +2137,53 @@ void ColorTemp::jch2xyz_ciecam02( double &x, double &y, double &z, double J, dou ColorTemp::cat02_to_xyz( x, y, z, r, g, b, gamu ); } +void ColorTemp::jch2xyz_ciecam02float( float &x, float &y, float &z, float J, float C, float h, + float xw, float yw, float zw, float yb, float la, + float f, float c, float nc , bool doneinit2, int gamu) +{ + float r, g, b; + float rc, gc, bc; + float rp, gp, bp; + float rpa, gpa, bpa; + float rw, gw, bw; + float fl, d; + float n, nbb, ncb; + float a, ca, cb; + float aw; + float e, t; + float cz; + gamu=1; + ColorTemp::xyz_to_cat02float( rw, gw, bw, xw, yw, zw, gamu ); + if(doneinit2){ + n = yb / yw; + d = d_factorfloat( f, la ); + fl = calculate_fl_from_la_ciecam02float( la ); + nbb = ncb = 0.725f * pow_F( 1.0f / n, 0.2f ); + cz = 1.48f + sqrt( n ); + aw = achromatic_response_to_whitefloat( xw, yw, zw, d, fl, nbb, gamu ); + doneinit2=false; + } + e = ((12500.0f / 13.0f) * nc * ncb) * (cos( ((h * M_PI) / 180.0f) + 2.0f ) + 3.8f); + a = pow_F( J / 100.0f, 1.0f / (c * cz) ) * aw; + t = pow_F( C / (sqrt( J / 100.f) * pow_F( 1.64f - pow_F( 0.29f, n ), 0.73f )), 10.0f / 9.0f ); + + calculate_abfloat( ca, cb, h, e, t, nbb, a ); + Aab_to_rgbfloat( rpa, gpa, bpa, a, ca, cb, nbb ); + + rp = inverse_nonlinear_adaptationfloat( rpa, fl ); + gp = inverse_nonlinear_adaptationfloat( gpa, fl ); + bp = inverse_nonlinear_adaptationfloat( bpa, fl ); + + ColorTemp::hpe_to_xyzfloat( x, y, z, rp, gp, bp ); + ColorTemp::xyz_to_cat02float( rc, gc, bc, x, y, z, gamu ); + + r = rc / (((yw * d) / rw) + (1.0f - d)); + g = gc / (((yw * d) / gw) + (1.0f - d)); + b = bc / (((yw * d) / bw) + (1.0f - d)); + + ColorTemp::cat02_to_xyzfloat( x, y, z, r, g, b, gamu ); +} + //end CIECAM Billy Bigg diff --git a/rtengine/colortemp.h b/rtengine/colortemp.h index 3373dd0ae..2e20acff3 100644 --- a/rtengine/colortemp.h +++ b/rtengine/colortemp.h @@ -25,6 +25,8 @@ #include "imagefloat.h" #include "labimage.h" #define MAXR(a,b) ((a) > (b) ? (a) : (b)) +#define pow_F(a,b) (exp(b*log(a))) + namespace rtengine { @@ -66,6 +68,9 @@ class ColorTemp { static double d_factor( double f, double la ) { return f * (1.0 - ((1.0 / 3.6) * exp((-la - 42.0) / 92.0))); } + static float d_factorfloat( float f, float la ) { + return f * (1.0f - ((1.0f / 3.6f) * exp((-la - 42.0f) / 92.0f))); + } static double calculate_fl_from_la_ciecam02( double la ) { double la5 = la * 5.0; @@ -77,6 +82,16 @@ class ColorTemp { return (0.2 * k * la5) + (0.1 * (1.0 - k) * (1.0 - k) * pow(la5, 1.0 / 3.0)); } + static float calculate_fl_from_la_ciecam02float( float la ) { + float la5 = la * 5.0f; + float k = 1.0f / (la5 + 1.0f); + + /* Calculate k^4. */ + k = k * k; + k = k * k; + + return (0.2f * k * la5) + (0.1f * (1.0f - k) * (1.0f - k) * pow_F(la5, 1.0f / 3.0f)); + } static double achromatic_response_to_white( double x, double y, double z, double d, double fl, double nbb, int gamu ) { double r, g, b; @@ -103,25 +118,76 @@ class ColorTemp { return ((2.0 * rpa) + gpa + ((1.0 / 20.0) * bpa) - 0.305) * nbb; } + + static float achromatic_response_to_whitefloat( float x, float y, float z, float d, float fl, float nbb, int gamu ) { + float r, g, b; + float rc, gc, bc; + float rp, gp, bp; + float rpa, gpa, bpa; + gamu=1; + xyz_to_cat02float( r, g, b, x, y, z, gamu ); + + rc = r * (((y * d) / r) + (1.0f - d)); + gc = g * (((y * d) / g) + (1.0f - d)); + bc = b * (((y * d) / b) + (1.0f - d)); + + cat02_to_hpefloat( rp, gp, bp, rc, gc, bc, gamu ); + if(gamu==1){//gamut correction M.H.Brill S.Susstrunk + rp=MAXR(rp,0.0f); + gp=MAXR(gp,0.0f); + bp=MAXR(bp,0.0f); + } + + rpa = nonlinear_adaptationfloat( rp, fl ); + gpa = nonlinear_adaptationfloat( gp, fl ); + bpa = nonlinear_adaptationfloat( bp, fl ); + + return ((2.0f * rpa) + gpa + ((1.0f / 20.0f) * bpa) - 0.305f) * nbb; + } static void xyz_to_cat02 ( double &r, double &g, double &b, double x, double y, double z, int gamu ); static void cat02_to_hpe ( double &rh, double &gh, double &bh, double r, double g, double b, int gamu ); static void cat02_to_xyz ( double &x, double &y, double &z, double r, double g, double b, int gamu ); static void hpe_to_xyz ( double &x, double &y, double &z, double r, double g, double b ); + static void xyz_to_cat02float ( float &r, float &g, float &b, float x, float y, float z, int gamu ); + static void cat02_to_hpefloat ( float &rh, float &gh, float &bh, float r, float g, float b, int gamu ); + static void cat02_to_xyzfloat ( float &x, float &y, float &z, float r, float g, float b, int gamu ); + static void hpe_to_xyzfloat ( float &x, float &y, float &z, float r, float g, float b ); + + static void Aab_to_rgb( double &r, double &g, double &b, double A, double aa, double bb, double nbb ); + static void Aab_to_rgbfloat( float &r, float &g, float &b, float A, float aa, float bb, float nbb ); + static void calculate_ab( double &aa, double &bb, double h, double e, double t, double nbb, double a ); + static void calculate_abfloat( float &aa, float &bb, float h, float e, float t, float nbb, float a ); + + static double nonlinear_adaptation( double c, double fl ) { double p; if(c<0.0){ p = pow( (-1.0*fl * c) / 100.0, 0.42 );return ((-1.0*400.0 * p) / (27.13 + p)) + 0.1;} else {p = pow( (fl * c) / 100.0, 0.42 ); return ((400.0 * p) / (27.13 + p)) + 0.1;} } + static float nonlinear_adaptationfloat( float c, float fl ) { + float p; + if(c<0.0f){ p = pow_F( (-1.0f*fl * c) / 100.0f, 0.42f );return ((-1.0f*400.0f * p) / (27.13f + p)) + 0.1f;} + else {p = pow_F( (fl * c) / 100.0f, 0.42f ); return ((400.0f * p) / (27.13f + p)) + 0.1f;} + } static double inverse_nonlinear_adaptation( double c, double fl ) { int c1; if(c-0.1 < 0.0) c1=-1; else c1=1; return c1*(100.0 / fl) * pow( (27.13 * fabs( c - 0.1 )) / (400.0 - fabs( c - 0.1 )), 1.0 / 0.42 ); } + static float inverse_nonlinear_adaptationfloat( float c, float fl ) { + int c1; + if(c-0.1f < 0.0f) c1=-1; else c1=1; + return c1*(100.0f / fl) * pow_F( (27.13f * fabs( c - 0.1f )) / (400.0f - fabs( c - 0.1f )), 1.0f / 0.42f ); + } + + static void curvecolor(double satind, double satval, double &sres, double parsat); + static void curvecolorfloat(float satind, float satval, float &sres, float parsat); static void curveJ (double br, double contr, int db, LUTf & outCurve , LUTu & histogram ) ; + static void curveJfloat (float br, float contr, int db, LUTf & outCurve , LUTu & histogram ) ; bool operator== (const ColorTemp& other) { return fabs(temp-other.temp)<1e-10 && fabs(green-other.green)<1e-10; } bool operator!= (const ColorTemp& other) { return !(*this==other); } @@ -234,6 +300,13 @@ class ColorTemp { double xw, double yw, double zw, double yb, double la, double f, double c, double nc, bool doneinit2, int gamu ); + + static void jch2xyz_ciecam02float( float &x, float &y, float &z, + float J, float C, float h, + float xw, float yw, float zw, + float yb, float la, + float f, float c, float nc, bool doneinit2, int gamu ); + /** * Forward transform from XYZ to CIECAM02 JCh. */ @@ -244,69 +317,14 @@ class ColorTemp { double yb, double la, double f, double c, double nc, double pilotd, bool doneinit1, int gamu ); + static void xyz2jchqms_ciecam02float( float &J, float &C, float &h, + float &Q, float &M, float &s,float &aw, float &fl, float &wh, + float x, float y, float z, + float xw, float yw, float zw, + float yb, float la, + float f, float c, float nc, float pilotd, bool doneinit1, int gamu ); + + }; -inline void ColorTemp::xyz_to_cat02( double &r, double &g, double &b, double x, double y, double z, int gamu ) -{ -gamu=1; -if(gamu==0){ - r = ( 0.7328 * x) + (0.4296 * y) - (0.1624 * z); - g = (-0.7036 * x) + (1.6975 * y) + (0.0061 * z); - b = ( 0.0030 * x) + (0.0136 * y) + (0.9834 * z); - } -else if (gamu==1) {//gamut correction M.H.Brill S.Susstrunk - //r = ( 0.7328 * x) + (0.4296 * y) - (0.1624 * z); - //g = (-0.7036 * x) + (1.6975 * y) + (0.0061 * z); - //b = ( 0.0000 * x) + (0.0000 * y) + (1.0000 * z); - r = ( 1.007245 * x) + (0.011136* y) - (0.018381 * z);//Changjun Li - g = (-0.318061 * x) + (1.314589 * y) + (0.003471 * z); - b = ( 0.0000 * x) + (0.0000 * y) + (1.0000 * z); - -} -} - -inline void ColorTemp::cat02_to_xyz( double &x, double &y, double &z, double r, double g, double b, int gamu ) -{ -gamu=1; -if(gamu==0) { - x = ( 1.096124 * r) - (0.278869 * g) + (0.182745 * b); - y = ( 0.454369 * r) + (0.473533 * g) + (0.072098 * b); - z = (-0.009628 * r) - (0.005698 * g) + (1.015326 * b); - } -else if(gamu==1) {//gamut correction M.H.Brill S.Susstrunk - //x = ( 1.0978566 * r) - (0.277843 * g) + (0.179987 * b); - //y = ( 0.455053 * r) + (0.473938 * g) + (0.0710096* b); - //z = ( 0.000000 * r) - (0.000000 * g) + (1.000000 * b); - x = ( 0.99015849 * r) - (0.00838772* g) + (0.018229217 * b);//Changjun Li - y = ( 0.239565979 * r) + (0.758664642 * g) + (0.001770137* b); - z = ( 0.000000 * r) - (0.000000 * g) + (1.000000 * b); - -} -} - -inline void ColorTemp::hpe_to_xyz( double &x, double &y, double &z, double r, double g, double b ) -{ - x = (1.910197 * r) - (1.112124 * g) + (0.201908 * b); - y = (0.370950 * r) + (0.629054 * g) - (0.000008 * b); - z = b; - -} - - - - -inline void ColorTemp::cat02_to_hpe( double &rh, double &gh, double &bh, double r, double g, double b, int gamu ) -{ gamu=1; - if(gamu==0){ - rh = ( 0.7409792 * r) + (0.2180250 * g) + (0.0410058 * b); - gh = ( 0.2853532 * r) + (0.6242014 * g) + (0.0904454 * b); - bh = (-0.0096280 * r) - (0.0056980 * g) + (1.0153260 * b); - } - else if (gamu==1) {//Changjun Li - rh = ( 0.550930835 * r) + (0.519435987* g) - ( 0.070356303* b); - gh = ( 0.055954056 * r) + (0.89973132 * g) + (0.044315524 * b); - bh = (0.0 * r) - (0.0* g) + (1.0 * b); - } -} - } #endif diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 1da822266..37c5f3d99 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -831,7 +831,6 @@ void CurveFactory::curveLightBrightColor ( }*/ } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 73b5ea567..e894eecbe 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -1,3 +1,4 @@ +/* /* * This file is part of RawTherapee. * @@ -186,26 +187,24 @@ void Crop::update (int todo) { LUTu dummy; parent->ipf.chromiLuminanceCurve (1,labnCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve, parent->satcurve, parent->lhskcurve, parent->lumacurve, utili, autili, butili, ccutili,cclutili, dummy); parent->ipf.vibrance (labnCrop); - // if(!params.colorappearance.tonecie) parent->ipf.EPDToneMap(labnCrop, 5, 1); //Go with much fewer than normal iterates for fast redisplay. - // if(!params.colorappearance.tonecie) parent->ipf.EPDToneMap(labnCrop, 0, 1); //Go with much fewer than normal iterates for fast redisplay. - if(params.colorappearance.enabled && !params.colorappearance.tonecie)parent->ipf.EPDToneMap(labnCrop, 5, 1); - - if(!params.colorappearance.enabled){parent->ipf.EPDToneMap(labnCrop, 5, 1);} - + if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) parent->ipf.EPDToneMap(labnCrop,5,1); // parent->ipf.EPDToneMap(labnCrop, 5, 1); //Go with much fewer than normal iterates for fast redisplay. - + // for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled if (skip==1) { parent->ipf.impulsedenoise (labnCrop); - parent->ipf.defringe (labnCrop); + if((params.colorappearance.enabled && !settings->autocielab) ||(!params.colorappearance.enabled) ) {parent->ipf.defringe (labnCrop);} parent->ipf.MLsharpen (labnCrop); - parent->ipf.MLmicrocontrast (labnCrop); - //parent->ipf.MLmicrocontrast (labnCrop); - parent->ipf.sharpening (labnCrop, (float**)cbuffer); - parent->ipf.dirpyrequalizer (labnCrop); + if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) { + parent->ipf.MLmicrocontrast (labnCrop); + parent->ipf.sharpening (labnCrop, (float**)cbuffer); + parent->ipf.dirpyrequalizer (labnCrop); + } } int begh = 0, endh = labnCrop->H; - - parent->ipf.ciecam_02 (cieCrop,begh, endh, 1,labnCrop, ¶ms,parent->customColCurve1,parent->customColCurve2,parent->customColCurve3, dummy, dummy, 5, 1); + bool execsharp=false; + if(skip==1) execsharp=true; + if(settings->ciecamfloat) parent->ipf.ciecam_02float (cieCrop,begh, endh, 1,labnCrop, ¶ms,parent->customColCurve1,parent->customColCurve2,parent->customColCurve3, dummy, dummy, 5, 1,(float**)cbuffer, execsharp); + else parent->ipf.ciecam_02 (cieCrop,begh, endh, 1,labnCrop, ¶ms,parent->customColCurve1,parent->customColCurve2,parent->customColCurve3, dummy, dummy, 5, 1,(float**)cbuffer, execsharp); } // switch back to rgb parent->ipf.lab2monitorRgb (labnCrop, cropImg); @@ -287,8 +286,8 @@ void Crop::freeAll () { delete labnCrop; delete cropImg; delete cshmap; - //for (int i=0; i #endif +#define CLIPI(a) ((a)>0 ?((a)<32768 ?(a):32768):0) #define CLIPC(a) ((a)>-32000?((a)<32000?(a):32000):-32000) #define DIRWT(i1,j1,i,j) ( domker[(i1-i)/scale+halfwin][(j1-j)/scale+halfwin] * rangefn[abs((int)data_fine[i1][j1]-data_fine[i][j])] ) @@ -48,7 +49,7 @@ namespace rtengine { //scale is spacing of directional averaging weights - void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, int srcwidth, int srcheight, const double * mult ) + void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, int srcwidth, int srcheight, const double * mult) { int lastlevel=maxlevel; @@ -135,8 +136,7 @@ namespace rtengine { for (int i=0; i0) { + lastlevel--; + //printf("last level to process %d \n",lastlevel); + } + if (lastlevel==0) return; + + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + LUTf rangefn(0x10000); + + int intfactor = 1024;//16384; + + + //set up range functions + + for (int i=0; i<0x10000; i++) { + rangefn[i] = (int)((thresh/((double)(i) + thresh))*intfactor); + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + int level; + array2D buffer (srcwidth, srcheight); + + multi_array2D dirpyrlo (srcwidth, srcheight); + + + for (int i=0; i 0; level--) + { + idirpyr_eq_channel(dirpyrlo[level], dirpyrlo[level-1], buffer, srcwidth, srcheight, level, mult ); + } + + + scale = scales[0]; + + idirpyr_eq_channel(dirpyrlo[0], dst, buffer, srcwidth, srcheight, 0, mult ); + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + for (int i=0; iJ_p[i][j] > 8.f && ncie->J_p[i][j] < 92.f) dst[i][j] = CLIP((int)( buffer[i][j] )); // TODO: Really a clip necessary? + else dst[i][j]=src[i][j];} + else dst[i][j] = CLIP((int)( buffer[i][j] )); // TODO: Really a clip necessary? + + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + } + + + + void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** data_coarse, int width, int height, LUTf & rangefn, int level, int scale, const double * mult ) { diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 07cf6c672..c6b56c65d 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -349,35 +349,31 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { ipf.chromiLuminanceCurve (pW,nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve,lhskcurve, lumacurve, utili, autili, butili, ccutili,cclutili, histCCurve); ipf.vibrance(nprevl); - // if(!params.colorappearance.tonecie) ipf.EPDToneMap(nprevl,0,scale); -/* if(params.colorappearance.enabled){ - if(!params.colorappearance.tonecie) ipf.EPDToneMap(nprevl,5,1); - } - if(!params.colorappearance.enabled){ipf.EPDToneMap(nprevl,5,1);} - */ - if(params.colorappearance.enabled && !params.colorappearance.tonecie) ipf.EPDToneMap(nprevl,5,1); - - if(!params.colorappearance.enabled){ipf.EPDToneMap(nprevl,5,1);} - + if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) ipf.EPDToneMap(nprevl,5,1); + // for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled readyphase++; if (scale==1) { progress ("Denoising luminance impulse...",100*readyphase/numofphases); ipf.impulsedenoise (nprevl); readyphase++; + if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ progress ("Defringing...",100*readyphase/numofphases); - ipf.defringe (nprevl); - readyphase++; + ipf.defringe (nprevl); + readyphase++; + } if (params.sharpenEdge.enabled) { progress ("Edge sharpening...",100*readyphase/numofphases); ipf.MLsharpen (nprevl); readyphase++; } if (params.sharpenMicro.enabled) { + if(( params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ progress ("Microcontrast...",100*readyphase/numofphases); ipf.MLmicrocontrast (nprevl); readyphase++; + } } - if (params.sharpening.enabled) { + if(((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) { progress ("Sharpening...",100*readyphase/numofphases); float **buffer = new float*[pH]; @@ -391,10 +387,13 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { delete [] buffer; readyphase++; } - - progress ("Pyramid equalizer...",100*readyphase/numofphases); - ipf.dirpyrequalizer (nprevl); - readyphase++; + if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ +// if(params.colorappearance.enabled && !params.colorappearance.sharpcie){ + progress ("Pyramid equalizer...",100*readyphase/numofphases); + ipf.dirpyrequalizer (nprevl); + readyphase++; + } + } //L histo and Chroma histo for ciecam // histogram well be for Lab (Lch) values, because very difficult to do with J,Q, M, s, C @@ -425,7 +424,16 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { int Iterates=0; int begh=0; int endh=pH; - ipf.ciecam_02 (ncie, begh, endh, pW, nprevl, ¶ms, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1); + + float **buffer = new float*[pH]; + for (int i=0; iciecamfloat) ipf.ciecam_02float (ncie, begh, endh, pW, nprevl, ¶ms, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1, (float**)buffer, true); + else ipf.ciecam_02 (ncie, begh, endh, pW, nprevl, ¶ms, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1, (float**)buffer, true); + for (int i=0; idelImage (previmg); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 25e1efdf9..c12d5db23 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -237,7 +237,7 @@ void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* par } // Copyright (c) 2012 Jacques Desmis -void ImProcFunctions::ciecam_02 (CieImage* ncie, int begh, int endh, int pW, LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2,const ColorAppearance & customColCurve3, LUTu & histLCAM, LUTu & histCCAM, int Iterates, int scale ) +void ImProcFunctions::ciecam_02 (CieImage* ncie, int begh, int endh, int pW, LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2,const ColorAppearance & customColCurve3, LUTu & histLCAM, LUTu & histCCAM, int Iterates, int scale, float** buffer, bool execsharp) { if(params->colorappearance.enabled) { @@ -654,18 +654,22 @@ if(params->colorappearance.enabled) { h=hpro; s=spro; - if(params->colorappearance.tonecie){//use pointer for tonemapping with CIECAM + if(params->colorappearance.tonecie || settings->autocielab){//use pointer for tonemapping with CIECAM and also sharpening , defringe, contrast detail + // if(params->colorappearance.tonecie || params->colorappearance.sharpcie){//use pointer for tonemapping with CIECAM and also sharpening , defringe, contrast detail + float Qred= ( 4.0 / c) * ( aw + 4.0 );//estimate Q max if J=100.0 ncie->Q_p[i][j]=(float)Q+epsil;//epsil to avoid Q=0 ncie->M_p[i][j]=(float)M+epsil; ncie->J_p[i][j]=(float)J+epsil; ncie->h_p[i][j]=(float)h; ncie->C_p[i][j]=(float)C+epsil; - // ciec->s_p[i][j]=(float)s; - + // ncie->s_p[i][j]=(float)s; + ncie->sh_p[i][j]=(float) 32768.*(( 4.0 / c )*sqrt( J / 100.0 ) * ( aw + 4.0 ))/Qred ; + // ncie->ch_p[i][j]=(float) 327.68*C; if(ncie->Q_p[i][j]Q_p[i][j];//minima if(ncie->Q_p[i][j]>maxQ) maxQ=ncie->Q_p[i][j];//maxima } - if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.tonecie){ + if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.tonecie || !settings->autocielab){ + // if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.tonecie || !params->colorappearance.sharpcie){ int posl, posc; double brli=327.; double chsacol=327.; @@ -736,7 +740,8 @@ if(params->colorappearance.enabled) { } } // End of parallelization -if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.tonecie){//normal +if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.tonecie || !settings->autocielab){//normal +//if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.tonecie || !params->colorappearance.sharpcie){//normal if(ciedata) { //update histogram J @@ -769,10 +774,44 @@ if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.to // printf("minc=%f maxc=%f minj=%f maxj=%f\n",minc,maxc,minj,maxj); } #endif -//select here tonemapping with Q -if(params->colorappearance.tonecie && params->edgePreservingDecompositionUI.enabled) { - //EPDToneMapCIE adated to CIECAM - ImProcFunctions::EPDToneMapCIE(ncie, a_w, c_, w_h, width, height, begh, endh, minQ, maxQ, Iterates, scale ); + +if(settings->autocielab) { +//if(params->colorappearance.sharpcie) { + +//all this treatments reduce artefacts, but can leed to slighty different results +if(params->defringe.enabled) if(execsharp) ImProcFunctions::defringecam (ncie);//defringe adapted to CIECAM + +if (params->sharpenMicro.enabled)if(execsharp) ImProcFunctions::MLmicrocontrastcam(ncie); + +if(params->sharpening.enabled) if(execsharp) {ImProcFunctions::sharpeningcam (ncie, (float**)buffer);} //sharpening adapted to CIECAM + +if(params->dirpyrequalizer.enabled) if(execsharp) dirpyr_equalizercam(ncie, ncie->sh_p, ncie->sh_p, ncie->W, ncie->H, params->dirpyrequalizer.mult, true);//contrast by detail adapted to CIECAM + + float Qredi= ( 4.0 / c_) * ( a_w + 4.0 ); + float co_e=(pow(f_l,0.25)); + +#ifndef _DEBUG +#pragma omp parallel default(shared) firstprivate(height,width, Qredi,a_w,c_) +#endif +{ +#ifndef _DEBUG + #pragma omp for schedule(dynamic, 10) +#endif + for (int i=0; ish_p[i][j]/(32768.f); + ncie->J_p[i][j]=100.0* interm*interm/((a_w+4.)*(a_w+4.)*(4./c_)*(4./c_)); + ncie->Q_p[i][j]=( 4.0 / c_) * ( a_w + 4.0 ) * sqrt(ncie->J_p[i][j]/100.f); + ncie->M_p[i][j]=ncie->C_p[i][j]*co_e; + } + } +} +if((params->colorappearance.tonecie || params->colorappearance.tonecie && (params->edgePreservingDecompositionUI.enabled)) || (params->sharpening.enabled && settings->autocielab) + || (params->dirpyrequalizer.enabled && settings->autocielab) ||(params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab)) { + + if(params->edgePreservingDecompositionUI.enabled && params->colorappearance.tonecie) ImProcFunctions::EPDToneMapCIE(ncie, a_w, c_, w_h, width, height, begh, endh, minQ, maxQ, Iterates, scale ); + //EPDToneMapCIE adated to CIECAM + #ifndef _DEBUG #pragma omp parallel default(shared) firstprivate(lab,xw2,yw2,zw2,chr,yb,la2,yb2, height,width,begh, endh,doneinit2, nc2,f2,c2, gamu, highlight,pW) @@ -790,14 +829,13 @@ if(params->colorappearance.tonecie && params->edgePreservingDecompositionUI.enab #pragma omp for schedule(dynamic, 10) #endif for (int i=0; iJ_p[i][j]=(100.0* ncie->Q_p[i][j]*ncie->Q_p[i][j]) /(w_h*w_h); + if(params->edgePreservingDecompositionUI.enabled) ncie->J_p[i][j]=(100.0* ncie->Q_p[i][j]*ncie->Q_p[i][j])/(w_h*w_h); ncie->C_p[i][j] =(ncie->M_p[i][j])/co_e; //show histogram in CIECAM mode (Q,J, M,s,C) int posl, posc; @@ -902,6 +940,721 @@ if(params->colorappearance.tonecie && params->edgePreservingDecompositionUI.enab //end CIECAM +// Copyright (c) 2012 Jacques Desmis +void ImProcFunctions::ciecam_02float (CieImage* ncie, int begh, int endh, int pW, LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2,const ColorAppearance & customColCurve3, LUTu & histLCAM, LUTu & histCCAM, int Iterates, int scale, float** buffer, bool execsharp) +{ +if(params->colorappearance.enabled) { +//printf("ciecam float\n"); + +#ifdef _DEBUG + MyTime t1e,t2e; + t1e.set(); +#endif + LUTf dLcurve(65536,0); + LUTu hist16JCAM(65536); + bool jp=false; + float val; + //preparate for histograms CIECAM + if(pW!=1){//only with improccoordinator + for (int i=0; i<32768; i++) { //# 32768*1.414 approximation maxi for chroma + val = (double)i / 32767.0; + dLcurve[i] = CLIPD(val); + } + hist16JCAM.clear(); + } + LUTf dCcurve(65536,0); + LUTu hist16_CCAM(65536); + bool chropC=false; + float valc; + if(pW!=1){//only with improccoordinator + for (int i=0; i<48000; i++) { //# 32768*1.414 approximation maxi for chroma + valc = (double)i / 47999.0; + dCcurve[i] = CLIPD(valc); + } + hist16_CCAM.clear(); + } + //end preparate histogram + int width = lab->W, height = lab->H; + int Np=width*height; + float minQ=10000.f; + float minM=10000.f; + float maxQ= -1000.f; + float maxM= -1000.f; + float w_h; + float a_w; + float c_; + float f_l; + float Yw; + Yw=1.0; + double Xw, Zw; + float f,c,nc,yb,la,xw,yw,zw,f2,c2,nc2,yb2,la2; + float z,fl,n,nbb,ncb,d,aw; + float xwd,ywd,zwd; + int alg=0; + float sum=0.f; + float mean; + //LUTf for sliders J and Q + LUTf bright_curve (65536,0);//init curve + LUTf bright_curveQ (65536,0);//init curve + + LUTu hist16J (65536); + LUTu hist16Q (65536); + float koef=1.0f;//rough correspondence between L and J + hist16J.clear();hist16Q.clear(); + for (int i=0; iL[i][j])/327.68f)>95.) koef=1.f; + else if(((lab->L[i][j])/327.68f)>85.) koef=0.97f; + else if(((lab->L[i][j])/327.68f)>80.) koef=0.93f; + else if(((lab->L[i][j])/327.68f)>70.) koef=0.87f; + else if(((lab->L[i][j])/327.68f)>60.) koef=0.85f; + else if(((lab->L[i][j])/327.68f)>50.) koef=0.8f; + else if(((lab->L[i][j])/327.68f)>40.) koef=0.75f; + else if(((lab->L[i][j])/327.68f)>30.) koef=0.7f; + else if(((lab->L[i][j])/327.68f)>20.) koef=0.7f; + else if(((lab->L[i][j])/327.68f)>10.) koef=0.9f; + else if(((lab->L[i][j])/327.68f)>0.) koef=1.0f; + + hist16J[CLIP((int)((koef*lab->L[i][j])))]++;//evaluate histogram luminance L # J + sum+=koef*lab->L[i][j];//evaluate mean J to calcualte Yb + hist16Q[CLIP((int) (32768.f*sqrt((koef*(lab->L[i][j]))/32768.f)))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L + } + //mean=(sum/((endh-begh)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone + mean=(sum/((height)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone + if (mean<15.f) yb=3.0; + else if(mean<30.f) yb=5.0; + else if(mean<40.f) yb=10.0; + else if(mean<45.f) yb=15.0; + else if(mean<50.f) yb=18.0; + else if(mean<55.f) yb=23.0; + else if(mean<60.f) yb=30.0; + else if(mean<70.f) yb=40.0; + else if(mean<80.f) yb=60.0; + else if(mean<90.f) yb=80.0; + else yb=90.0; + + bool ciedata=params->colorappearance.datacie; + + ColorTemp::temp2mulxyz (params->wb.temperature, params->wb.green, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB + //viewing condition for surround + if(params->colorappearance.surround=="Average") { f = 1.00; c = 0.69; nc = 1.00;f2=1.0,c2=0.69,nc2=1.0;} + else if(params->colorappearance.surround=="Dim"){ f2 = 0.9; c2 = 0.59; nc2 = 0.9;f=1.0,c=0.69,nc=1.0;} + else if(params->colorappearance.surround=="Dark"){f2 = 0.8; c2 = 0.525;nc2 = 0.8;f=1.0,c=0.69,nc=1.0;} + else if(params->colorappearance.surround=="ExtremelyDark"){f2 = 0.8; c2 = 0.41;nc2 = 0.8;f=1.0,c=0.69,nc=1.0;} + + //scene condition for surround + if(params->colorappearance.surrsource==true) {f = 0.85; c = 0.55; nc = 0.85;}// if user => source image has surround very dark + //with which algorithme + if (params->colorappearance.algo=="JC") alg=0; + else if(params->colorappearance.algo=="JS") alg=1; + else if(params->colorappearance.algo=="QM") alg=2; + else if(params->colorappearance.algo=="ALL") alg=3; + //settings white point of output device - or illuminant viewing + if(settings->viewingdevice==0) {xwd=96.42;ywd=100.0;zwd=82.52;}//5000K + else if(settings->viewingdevice==1) {xwd=95.68;ywd=100.0;zwd=92.15;}//5500 + else if(settings->viewingdevice==2) {xwd=95.24;ywd=100.0;zwd=100.81;}//6000 + else if(settings->viewingdevice==3) {xwd=95.04;ywd=100.0;zwd=108.88;}//6500 + else if(settings->viewingdevice==4) {xwd=109.85;ywd=100.0;zwd=35.58;}//tungsten + else if(settings->viewingdevice==5) {xwd=99.18;ywd=100.0;zwd=67.39;}//fluo F2 + else if(settings->viewingdevice==6) {xwd=95.04;ywd=100.0;zwd=108.75;}//fluo F7 + else if(settings->viewingdevice==7) {xwd=100.96;ywd=100.0;zwd=64.35;}//fluo F11 + + + //settings mean Luminance Y of output device or viewing + if(settings->viewingdevicegrey==0) {yb2=5.0;} + else if(settings->viewingdevicegrey==1) {yb2=10.0;} + else if(settings->viewingdevicegrey==2) {yb2=15.0;} + else if(settings->viewingdevicegrey==3) {yb2=18.0;} + else if(settings->viewingdevicegrey==4) {yb2=23.0;} + else if(settings->viewingdevicegrey==5) {yb2=30.0;} + else if(settings->viewingdevicegrey==6) {yb2=40.0;} + + //La and la2 = ambiant luminosity scene and viewing + la=float(params->colorappearance.adapscen); + la2=float(params->colorappearance.adaplum); + + // level of adaptation + float deg=(params->colorappearance.degree)/100.0; + float pilot=params->colorappearance.autodegree ? 2.0 : deg; + + //algoritm's params + float jli=params->colorappearance.jlight; + float chr=params->colorappearance.chroma; + float contra=params->colorappearance.contrast; + float qbri=params->colorappearance.qbright; + float schr=params->colorappearance.schroma; + float mchr=params->colorappearance.mchroma; + float qcontra=params->colorappearance.qcontrast; + float hue=params->colorappearance.colorh; + float rstprotection = 100.-params->colorappearance.rstprotection; + if(schr>0.0) schr=schr/2.0f;//divide sensibility for saturation + + // extracting datas from 'params' to avoid cache flush (to be confirmed) + ColorAppearanceParams::eTCModeId curveMode = params->colorappearance.curveMode; + ColorAppearanceParams::eTCModeId curveMode2 = params->colorappearance.curveMode2; + bool hasColCurve1 = bool(customColCurve1); + bool hasColCurve2 = bool(customColCurve2); + ColorAppearanceParams::eCTCModeId curveMode3 = params->colorappearance.curveMode3; + bool hasColCurve3 = bool(customColCurve3); + + + + //evaluate lightness, contrast + ColorTemp::curveJfloat (jli, contra, 1, bright_curve,hist16J);//lightness and contrast J + ColorTemp::curveJfloat (qbri, qcontra, 1, bright_curveQ, hist16Q);//brightness and contrast Q + int gamu=0; + bool highlight = params->hlrecovery.enabled; //Get the value if "highlight reconstruction" is activated + + if(params->colorappearance.gamut==true) gamu=1;//enabled gamut control + xw=100.0*Xw; + yw=100.0*Yw; + zw=100.0*Zw; + float xw1,yw1,zw1,xw2,yw2,zw2; + // settings of WB: scene and viewing + if(params->colorappearance.wbmodel=="RawT") {xw1=96.46;yw1=100.0;zw1=82.445;xw2=xwd;yw2=ywd;zw2=zwd;} //use RT WB; CAT 02 is used for output device (see prefreneces) + else if(params->colorappearance.wbmodel=="RawTCAT02") {xw1=xw;yw1=yw;zw1=zw;xw2=xwd;yw2=ywd;zw2=zwd;} // Settings RT WB are used for CAT02 => mix , CAT02 is use for output device (screen: D50 D65, projector: lamp, LED) see preferences + bool doneinit=true; + bool doneinit2=true; +#ifndef _DEBUG +#pragma omp parallel default(shared) firstprivate(lab,xw1,xw2,yw1,yw2,zw1,zw2,pilot,jli,chr,yb,la,yb2,la2,fl,nc,f,c, height,width,begh, endh, doneinit,doneinit2, nc2,f2,c2, alg, gamu, highlight, rstprotection, pW) +#endif +{ //matrix for current working space + 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]} + }; + +#ifndef _DEBUG +#pragma omp for schedule(dynamic, 10) +#endif + for (int i=0; iL[i][j]; + float a=lab->a[i][j]; + float b=lab->b[i][j]; + float x1,y1,z1; + float x,y,z; + float epsil=0.0001; + //convert Lab => XYZ + Color::Lab2XYZ(L, a, b, x1, y1, z1); + float J, C, h, Q, M, s, aw, fl, wh; + float Jp,Cpr; + float Jpro,Cpro, hpro, Qpro, Mpro, spro; + bool t1L=false; + bool t1B=false; + bool t2L=false; + bool t2B=false; + int c1C=0; + int c1s=0; + int c1co=0; + + x=(float)x1/655.35f; + y=(float)y1/655.35f; + z=(float)z1/655.35f; + //process source==> normal + ColorTemp::xyz2jchqms_ciecam02float( J, C, h, + Q, M, s, aw, fl, wh, + x, y, z, + xw1, yw1, zw1, + yb, la, + f, c, nc, pilot, doneinit, gamu ); + Jpro=J; + Cpro=C; + hpro=h; + Qpro=Q; + Mpro=M; + spro=s; + w_h=wh+epsil; + a_w=aw; + c_=c; + f_l=fl; + // we cannot have all algoritms with all chroma curves + if(alg==1) { + // Lightness saturation + Jpro=(bright_curve[(float)(Jpro*327.68f)])/327.68f;//ligthness CIECAM02 + contrast + float sres; + float Sp=spro/100.0f; + float parsat=1.5f; + parsat=1.5f;//parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation) + if(schr==-100.0f) schr=-99.8f; + ColorTemp::curvecolorfloat(schr, Sp , sres, parsat); + float coe=pow_F(fl,0.25f); + float dred=100.f;// in C mode + float protect_red=80.0f; // in C mode + dred = 100.0f * sqrt((dred*coe)/Qpro); + protect_red=100.0 * sqrt((protect_red*coe)/Qpro); + int sk=0; + float ko=100.f; + Color::skinredfloat(Jpro, hpro, sres, Sp, dred, protect_red,sk,rstprotection,ko, spro); + Qpro= ( 4.0f / c ) * sqrt( Jpro / 100.0f ) * ( aw + 4.0f ) ; + Cpro=(spro*spro*Qpro)/(10000.0f); + } + else if(alg==3 || alg==0 || alg==2) { + float coef=32760.f/wh; + if(alg==3 || alg==2) Qpro=(bright_curveQ[(float)(Qpro*coef)])/coef;//brightness and contrast + float Mp, sres; + float coe=pow_F(fl,0.25f); + Mp=Mpro/100.0f; + float parsat=2.5f; + if(mchr==-100.0f) mchr=-99.8f ; + if(mchr==100.0f) mchr=99.9f; + if(alg==3 || alg==2) ColorTemp::curvecolorfloat(mchr, Mp , sres, parsat); else ColorTemp::curvecolorfloat(0.0, Mp , sres, parsat);//colorfullness + float dred=100.f;//in C mode + float protect_red=80.0f;// in C mode + dred *=coe;//in M mode + protect_red *=coe;//M mode + int sk=0; + float ko=100.f; + Color::skinredfloat(Jpro, hpro, sres, Mp, dred, protect_red,sk,rstprotection,ko, Mpro); + Jpro=(100.0f* Qpro*Qpro) /(wh*wh); + Cpro= Mpro/coe; + spro = 100.0f * sqrt( Mpro / Qpro ); + if(alg!=2) Jpro=(bright_curve[(float)(Jpro*327.68f)])/327.68f;//ligthness CIECAM02 + contrast + float Cp; + float Sp=spro/100.0f; + parsat=1.5; + if(schr==-100.0f) schr=-99.f; + if(schr==100.0f) schr=98.f; + if(alg==3) ColorTemp::curvecolorfloat(schr, Sp , sres, parsat); else ColorTemp::curvecolorfloat(0.0, Sp , sres, parsat); //saturation + dred=100.f;// in C mode + protect_red=80.0f; // in C mode + dred = 100.0 * sqrt((dred*coe)/Q); + protect_red=100.0f * sqrt((protect_red*coe)/Q); + sk=0; + Color::skinredfloat(Jpro, hpro, sres, Sp, dred, protect_red,sk,rstprotection,ko, spro); + Qpro= ( 4.0f / c ) * sqrt( Jpro / 100.0f ) * ( aw + 4.0f ) ; + Cpro=(spro*spro*Qpro)/(10000.0f); + Cp=Cpro/100.0f; + parsat=1.8f;//parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation : for not) + if(chr==-100.0f) chr=-99.8f; + if(alg!=2) ColorTemp::curvecolorfloat(chr, Cp , sres, parsat);else ColorTemp::curvecolorfloat(0.0, Cp , sres, parsat); //chroma + dred=55.f; + protect_red=30.0f; + sk=1; + Color::skinredfloat(Jpro, hpro, sres, Cp, dred, protect_red,sk,rstprotection, ko, Cpro); + + hpro=hpro+hue;if( hpro < 0.0f ) hpro += 360.0f;//hue + } + + if (hasColCurve1) {//curve 1 with Lightness and Brightness + if (curveMode==ColorAppearanceParams::TC_MODE_LIGHT){ + float Jj=(float) Jpro*327.68f; + float Jold=Jj; + const Lightcurve& userColCurve = static_cast(customColCurve1); + userColCurve.Apply(Jj); + Jj=0.7f*(Jj-Jold)+Jold;//divide sensibility + Jpro=(float)(Jj/327.68f); + t1L=true; + } + else if (curveMode==ColorAppearanceParams::TC_MODE_BRIGHT){ + float coef=32760.f/wh; + float Qq=(float) Qpro*coef; + float Qold=Qq; + const Brightcurve& userColCurve = static_cast(customColCurve1); + userColCurve.Apply(Qq); + Qq=0.5f*(Qq-Qold)+Qold;//divide sensibility + Qpro=(float)(Qq/coef); + Jpro=(100.0f* Qpro*Qpro) /(wh*wh); + t1B=true; + } + } + + if (hasColCurve2) {//curve 2 with Lightness and Brightness + if (curveMode2==ColorAppearanceParams::TC_MODE_LIGHT){ + float Jj=(float) Jpro*327.68f; + float Jold=Jj; + const Lightcurve& userColCurve = static_cast(customColCurve2); + userColCurve.Apply(Jj); + Jj=0.7f*(Jj-Jold)+Jold;//divide sensibility + Jpro=(float)(Jj/327.68f); + t2L=true; + } + else if (curveMode2==ColorAppearanceParams::TC_MODE_BRIGHT){ // + float coef=32760.f/wh; + float Qq=(float) Qpro*coef; + float Qold = Qq; + const Brightcurve& userColCurve = static_cast(customColCurve2); + userColCurve.Apply(Qq); + Qq=0.5f*(Qq-Qold)+Qold;//divide sensibility + Qpro=(float)(Qq/coef); + Jpro=(100.0f* Qpro*Qpro) /(wh*wh); + t2B=true; + } + } + + if (hasColCurve3) {//curve 3 with chroma saturation colorfullness + if (curveMode3==ColorAppearanceParams::TC_MODE_CHROMA){ + float parsat=0.8f;//0.68; + float coef=327.68f/parsat; + float Cc=(float) Cpro*coef; + float Ccold=Cc; + const Chromacurve& userColCurve = static_cast(customColCurve3); + userColCurve.Apply(Cc); + float dred=55.f; + float protect_red=30.0f; + float sk=1; + float ko=1.f/coef; + Color::skinredfloat(Jpro, hpro, Cc, Ccold, dred, protect_red,sk,rstprotection,ko, Cpro); + // Cpro=Cc/coef; + c1C=1; + } + else if (curveMode3==ColorAppearanceParams::TC_MODE_SATUR){ // + float parsat=0.8f;//0.6 + float coef=327.68f/parsat; + float Ss=(float) spro*coef; + float Sold=Ss; + const Saturcurve& userColCurve = static_cast(customColCurve3); + userColCurve.Apply(Ss); + Ss=0.6f*(Ss-Sold)+Sold;//divide sensibility saturation + float coe=pow_F(fl,0.25f); + float dred=100.f;// in C mode + float protect_red=80.0f; // in C mode + dred = 100.0 * sqrt((dred*coe)/Qpro); + protect_red=100.0 * sqrt((protect_red*coe)/Qpro); + int sk=0; + float ko=1.f/coef; + Color::skinredfloat(Jpro, hpro, Ss, Sold, dred, protect_red,sk,rstprotection,ko, spro); + Qpro= ( 4.0 / c ) * sqrt( Jpro / 100.0 ) * ( aw + 4.0 ) ; + Cpro=(spro*spro*Qpro)/(10000.0f); + c1s=1; + + } + else if (curveMode3==ColorAppearanceParams::TC_MODE_COLORF){ // + float parsat=0.8f;//0.68; + float coef=327.68f/parsat; + float Mm=(float) Mpro*coef; + float Mold=Mm; + const Colorfcurve& userColCurve = static_cast(customColCurve3); + userColCurve.Apply(Mm); + float coe=pow_F(fl,0.25f); + float dred=100.f;//in C mode + float protect_red=80.0f;// in C mode + dred *=coe;//in M mode + protect_red *=coe; + int sk=0; + float ko=1.f/coef; + Color::skinredfloat(Jpro, hpro, Mm, Mold, dred, protect_red,sk,rstprotection,ko, Mpro); + Cpro= Mpro/coe; + c1co=1; + } + } + //to retrieve the correct values of variables + if(t2B && t1B) Jpro=(100.0* Qpro*Qpro) /(wh*wh);// for brightness curve + if(c1s==1) { + Qpro= ( 4.0f / c ) * sqrt( Jpro / 100.0f ) * ( aw + 4.0f ) ;//for saturation curve + Cpro=(spro*spro*Qpro)/(10000.0); + } + if(c1co==1) { float coe=pow_F(fl,0.25f);Cpro= Mpro/coe;} // for colorfullness curve + //retrieve values C,J...s + C=Cpro; + J=Jpro; + Q=Qpro; + M=Mpro; + h=hpro; + s=spro; + + if(params->colorappearance.tonecie || settings->autocielab){//use pointer for tonemapping with CIECAM and also sharpening , defringe, contrast detail + // if(params->colorappearance.tonecie || params->colorappearance.sharpcie){//use pointer for tonemapping with CIECAM and also sharpening , defringe, contrast detail + float Qred= ( 4.0f / c) * ( aw + 4.0f );//estimate Q max if J=100.0 + ncie->Q_p[i][j]=(float)Q+epsil;//epsil to avoid Q=0 + ncie->M_p[i][j]=(float)M+epsil; + ncie->J_p[i][j]=(float)J+epsil; + ncie->h_p[i][j]=(float)h; + ncie->C_p[i][j]=(float)C+epsil; + // ncie->s_p[i][j]=(float)s; + ncie->sh_p[i][j]=(float) 32768.f*(( 4.0f / c )*sqrt( J / 100.0f ) * ( aw + 4.0f ))/Qred ; + // ncie->ch_p[i][j]=(float) 327.68*C; + if(ncie->Q_p[i][j]Q_p[i][j];//minima + if(ncie->Q_p[i][j]>maxQ) maxQ=ncie->Q_p[i][j];//maxima + } + if(!params->colorappearance.tonecie || !settings->autocielab){ + // if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.tonecie || !settings->autocielab){ + // if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.tonecie || !params->colorappearance.sharpcie){ + int posl, posc; + float brli=327.f; + float chsacol=327.f; + int libr=0; + int colch=0; + if(curveMode==ColorAppearanceParams::TC_MODE_BRIGHT) {brli=70.0f; libr=1;} + else if(curveMode==ColorAppearanceParams::TC_MODE_LIGHT) {brli=327.f;libr=0;} + if (curveMode3==ColorAppearanceParams::TC_MODE_CHROMA) {chsacol=327.f;colch=0;} + else if(curveMode3==ColorAppearanceParams::TC_MODE_SATUR) {chsacol=450.0f;colch=1;} + else if(curveMode3==ColorAppearanceParams::TC_MODE_COLORF) {chsacol=327.0f;colch=2;} + if(ciedata) { + // Data for J Q M s and C histograms + //update histogram + jp=true; + if(pW!=1){//only with improccoordinator + if(libr==1) posl=CLIP((int)(Q*brli));//40.0 to 100.0 approximative factor for Q - 327 for J + else if(libr==0) posl=CLIP((int)(J*brli));//327 for J + hist16JCAM[posl]++; + } + chropC=true; + if(pW!=1){//only with improccoordinator + if(colch==0) posc=CLIP((int)(C*chsacol));//450.0 approximative factor for s 320 for M + else if(colch==1) posc=CLIP((int)(s*chsacol)); + else if(colch==2) posc=CLIP((int)(M*chsacol)); + hist16_CCAM[posc]++; + } + } + float xx,yy,zz; + //process normal==> viewing + ColorTemp::jch2xyz_ciecam02float( xx, yy, zz, + J, C, h, + xw2, yw2, zw2, + yb2, la2, + f2, c2, nc2, doneinit2, gamu); + x=(float)xx*655.35f; + y=(float)yy*655.35f; + z=(float)zz*655.35f; + float Ll,aa,bb; + //convert xyz=>lab + Color::XYZ2Lab(x, y, z, Ll, aa, bb); + lab->L[i][j]=Ll; + lab->a[i][j]=aa; + lab->b[i][j]=bb; + // gamut control in Lab mode; I must study how to do with cIECAM only + if(gamu==1) { + float R,G,B; + float HH, Lprov1, Chprov1; + Lprov1=lab->L[i][j]/327.68f; + Chprov1=sqrt(SQR(lab->a[i][j]/327.68f) + SQR(lab->b[i][j]/327.68f)); + HH=atan2(lab->b[i][j],lab->a[i][j]); + +#ifdef _DEBUG + bool neg=false; + bool more_rgb=false; + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH,Lprov1,Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); +#else + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH,Lprov1,Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); +#endif + + lab->L[i][j]=Lprov1*327.68f; + lab->a[i][j]=327.68f*Chprov1*cos(HH); + lab->b[i][j]=327.68f*Chprov1*sin(HH); + + } + } + } + } + // End of parallelization +if(!params->colorappearance.tonecie || !settings->autocielab){//normal + +//if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.tonecie || !settings->autocielab){//normal +//if(!params->edgePreservingDecompositionUI.enabled || !params->colorappearance.tonecie || !params->colorappearance.sharpcie){//normal + + if(ciedata) { + //update histogram J + if(pW!=1){//only with improccoordinator + for (int i=0; i<=32768; i++) {// + float val; + if (jp) { + float hval = dLcurve[i]; + int hi = (int)(255.0f*CLIPD(hval)); // + histLCAM[hi] += hist16JCAM[i] ; + } + } + } + if(pW!=1){//only with improccoordinator + for (int i=0; i<=48000; i++) {// + float valc; + if (chropC) { + float hvalc = dCcurve[i]; + int hic = (int)(255.0f*CLIPD(hvalc)); // + histCCAM[hic] += hist16_CCAM[i] ; + } + } + } + } +} +#ifdef _DEBUG + if (settings->verbose) { + t2e.set(); + printf("CIECAM02 performed in %d usec:\n", t2e.etime(t1e)); + // printf("minc=%f maxc=%f minj=%f maxj=%f\n",minc,maxc,minj,maxj); + } +#endif + +if(settings->autocielab) { +//if(params->colorappearance.sharpcie) { + +//all this treatments reduce artefacts, but can leed to slighty different results +if(params->defringe.enabled) if(execsharp) ImProcFunctions::defringecam (ncie);//defringe adapted to CIECAM + +if (params->sharpenMicro.enabled)if(execsharp) ImProcFunctions::MLmicrocontrastcam(ncie); + +if(params->sharpening.enabled) if(execsharp) {ImProcFunctions::sharpeningcam (ncie, (float**)buffer);} //sharpening adapted to CIECAM + +if(params->dirpyrequalizer.enabled) if(execsharp) dirpyr_equalizercam(ncie, ncie->sh_p, ncie->sh_p, ncie->W, ncie->H, params->dirpyrequalizer.mult, true);//contrast by detail adapted to CIECAM + + float Qredi= ( 4.0f / c_) * ( a_w + 4.0f ); + float co_e=(pow_F(f_l,0.25f)); + +#ifndef _DEBUG +#pragma omp parallel default(shared) firstprivate(height,width, Qredi,a_w,c_) +#endif +{ +#ifndef _DEBUG + #pragma omp for schedule(dynamic, 10) +#endif + for (int i=0; ish_p[i][j]/(32768.f); + ncie->J_p[i][j]=100.0f* interm*interm/((a_w+4.f)*(a_w+4.f)*(4.f/c_)*(4.f/c_)); + ncie->Q_p[i][j]=( 4.0f / c_) * ( a_w + 4.0f ) * sqrt(ncie->J_p[i][j]/100.f); + ncie->M_p[i][j]=ncie->C_p[i][j]*co_e; + } + } +} +if((params->colorappearance.tonecie && (params->edgePreservingDecompositionUI.enabled)) || (params->sharpening.enabled && settings->autocielab) + || (params->dirpyrequalizer.enabled && settings->autocielab) ||(params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab)) { + + if(params->edgePreservingDecompositionUI.enabled && params->colorappearance.tonecie) ImProcFunctions::EPDToneMapCIE(ncie, a_w, c_, w_h, width, height, begh, endh, minQ, maxQ, Iterates, scale ); + //EPDToneMapCIE adated to CIECAM + + +#ifndef _DEBUG +#pragma omp parallel default(shared) firstprivate(lab,xw2,yw2,zw2,chr,yb,la2,yb2, height,width,begh, endh,doneinit2, nc2,f2,c2, gamu, highlight,pW) +#endif +{ + TMatrix wiprofa = iccStore->workingSpaceInverseMatrix (params->icm.working); + double wipa[3][3] = { + {wiprofa[0][0],wiprofa[0][1],wiprofa[0][2]}, + {wiprofa[1][0],wiprofa[1][1],wiprofa[1][2]}, + {wiprofa[2][0],wiprofa[2][1],wiprofa[2][2]} + }; + + +#ifndef _DEBUG + #pragma omp for schedule(dynamic, 10) +#endif + for (int i=0; iedgePreservingDecompositionUI.enabled) ncie->J_p[i][j]=(100.0f* ncie->Q_p[i][j]*ncie->Q_p[i][j])/(w_h*w_h); + ncie->C_p[i][j] =(ncie->M_p[i][j])/co_e; + //show histogram in CIECAM mode (Q,J, M,s,C) + int posl, posc; + float brli=327.; + float chsacol=327.; + int libr=0; + int colch=0; + float sa_t; + if(curveMode==ColorAppearanceParams::TC_MODE_BRIGHT) {brli=70.0f; libr=1;} + else if(curveMode==ColorAppearanceParams::TC_MODE_LIGHT) {brli=327.f;libr=0;} + if (curveMode3==ColorAppearanceParams::TC_MODE_CHROMA) {chsacol=327.f;colch=0;} + else if(curveMode3==ColorAppearanceParams::TC_MODE_SATUR) {chsacol=450.0f;colch=1;} + else if(curveMode3==ColorAppearanceParams::TC_MODE_COLORF) {chsacol=327.0f;colch=2;} + if(ciedata) { + // Data for J Q M s and C histograms + //update histogram + jp=true; + if(pW!=1){//only with improccoordinator + if(libr==1) posl=CLIP((int)(ncie->Q_p[i][j]*brli));//40.0 to 100.0 approximative factor for Q - 327 for J + else if(libr==0) posl=CLIP((int)(ncie->J_p[i][j]*brli));//327 for J + hist16JCAM[posl]++; + } + chropC=true; + if(pW!=1){//only with improccoordinator + if(colch==0) posc=CLIP((int)(ncie->C_p[i][j]*chsacol));//450.0 approximative factor for s 320 for M + else if(colch==1) {sa_t=100.f*sqrt(ncie->C_p[i][j]/ncie->Q_p[i][j]); posc=CLIP((int)(sa_t*chsacol));}//Q_p always > 0 + else if(colch==2) posc=CLIP((int)(ncie->M_p[i][j]*chsacol)); + hist16_CCAM[posc]++; + } + } + //end histograms + ColorTemp::jch2xyz_ciecam02float( xx, yy, zz, + ncie->J_p[i][j], ncie->C_p[i][j], ncie->h_p[i][j], + xw2, yw2, zw2, + yb2, la2, + f2, c2, nc2, doneinit2, gamu); + x=(float)xx*655.35f; + y=(float)yy*655.35f; + z=(float)zz*655.35f; + float Ll,aa,bb; + //convert xyz=>lab + Color::XYZ2Lab(x, y, z, Ll, aa, bb); + lab->L[i][j]=Ll; + lab->a[i][j]=aa; + lab->b[i][j]=bb; + if(gamu==1) { + float R,G,B; + float HH, Lprov1, Chprov1; + Lprov1=lab->L[i][j]/327.68f; + Chprov1=sqrt(SQR(lab->a[i][j]/327.68f) + SQR(lab->b[i][j]/327.68f)); + HH=atan2(lab->b[i][j],lab->a[i][j]); + +#ifdef _DEBUG + bool neg=false; + bool more_rgb=false; + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH,Lprov1,Chprov1, R, G, B, wipa, highlight, 0.15f, 0.96f, neg, more_rgb); +#else + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH,Lprov1,Chprov1, R, G, B, wipa, highlight, 0.15f, 0.96f); +#endif + + lab->L[i][j]=Lprov1*327.68f; + lab->a[i][j]=327.68f*Chprov1*cos(HH); + lab->b[i][j]=327.68f*Chprov1*sin(HH); + } + } + + + } + //end parallelization + //show CIECAM histograms + if(ciedata) { + //update histogram J and Q + if(pW!=1){//only with improccoordinator + for (int i=0; i<=32768; i++) {// + float val; + if (jp) { + float hval = dLcurve[i]; + int hi = (int)(255.0f*CLIPD(hval)); // + histLCAM[hi] += hist16JCAM[i] ; + } + } + } + //update color histogram M,s,C + if(pW!=1){//only with improccoordinator + for (int i=0; i<=48000; i++) {// + float valc; + if (chropC) { + float hvalc = dCcurve[i]; + int hic = (int)(255.0f*CLIPD(hvalc)); // + histCCAM[hic] += hist16_CCAM[i] ; + } + } + } + } + + } + hist16JCAM.reset(); + hist16_CCAM.reset(); + dLcurve.reset(); + dCcurve.reset(); + bright_curve.reset(); + bright_curveQ.reset(); + hist16J.reset(); + hist16Q.reset(); + +} +} +//end CIECAM + + @@ -1187,6 +1940,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone } } + if (hasToneCurve2) { if (curveMode2==ToneCurveParams::TC_MODE_STD){ // Standard #ifdef _OPENMP @@ -1432,6 +2186,7 @@ void ImProcFunctions::chromiLuminanceCurve (int pW, LabImage* lold, LabImage* ln LUTu hist16Clad(65536); bool chrop=false; float val; + //preparate for histograms CIECAM if(pW!=1){//only with improccoordinator for (int i=0; i<48000; i++) { //# 32768*1.414 approximation maxi for chroma val = (double)i / 47999.0; @@ -1877,14 +2632,19 @@ void ImProcFunctions::colorCurve (LabImage* lold, LabImage* lnew) { PF_correct_RT(lab, lab, params->defringe.radius, params->defringe.threshold); } + void ImProcFunctions::defringecam (CieImage* ncie) { + + if (params->defringe.enabled && ncie->W>=8 && ncie->H>=8) + + PF_correct_RTcam(ncie, ncie, params->defringe.radius, params->defringe.threshold); + } void ImProcFunctions::dirpyrequalizer (LabImage* lab) { if (params->dirpyrequalizer.enabled && lab->W>=8 && lab->H>=8) { //dirpyrLab_equalizer(lab, lab, params->dirpyrequalizer.mult); - dirpyr_equalizer(lab->L, lab->L, lab->W, lab->H, params->dirpyrequalizer.mult); - + dirpyr_equalizer(lab->L, lab->L, lab->W, lab->H, params->dirpyrequalizer.mult); } } void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, float w_h, int Wid, int Hei, int begh, int endh, float minQ, float maxQ, unsigned int Iterates, int skip){ diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index c3480288d..92ef0c675 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -55,6 +55,7 @@ class ImProcFunctions { void transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap, bool fullImage); void sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H); + void sharpenHaloCtrlcam (CieImage* ncie, float** blurmap, float** base, int W, int H); void firstAnalysisThread(Imagefloat* original, Glib::ustring wprofile, unsigned int* histogram, int row_from, int row_to); void dcdamping (float** aI, float** aO, float damping, int W, int H); @@ -93,18 +94,22 @@ class ImProcFunctions { SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, double expcomp, int hlcompr, int hlcomprthresh); void luminanceCurve (LabImage* lold, LabImage* lnew, LUTf &curve); - void ciecam_02 (CieImage* ncie, int begh, int endh, int pW, LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3, LUTu &histLCAM, LUTu &histCCAM,int Iterates, int scale ); + void ciecam_02float (CieImage* ncie, int begh, int endh, int pW, LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3, LUTu &histLCAM, LUTu &histCCAM,int Iterates, int scale, float** buffer, bool execsharp ); + void ciecam_02 (CieImage* ncie, int begh, int endh, int pW, LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3, LUTu &histLCAM, LUTu &histCCAM,int Iterates, int scale, float** buffer, bool execsharp ); void chromiLuminanceCurve (int pW, LabImage* lold, LabImage* lnew, LUTf &acurve, LUTf &bcurve, LUTf & satcurve,LUTf & satclcurve, LUTf &curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, LUTu &histCCurve); void vibrance (LabImage* lab);//Jacques' vibrance void colorCurve (LabImage* lold, LabImage* lnew); void sharpening (LabImage* lab, float** buffer); + void sharpeningcam (CieImage* ncie, float** buffer); void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, double focalLen, double focalLen35mm, float focusDist, int rawRotationDeg, bool fullImage); void lab2monitorRgb (LabImage* lab, Image8* image); void resize (Image16* src, Image16* dst, float dScale); void deconvsharpening (LabImage* lab, float** buffer); + void deconvsharpeningcam (CieImage* ncie, float** buffer); void MLsharpen (LabImage* lab);// Manuel's clarity / sharpening void MLmicrocontrast(LabImage* lab ); //Manuel's microcontrast + void MLmicrocontrastcam(CieImage* ncie ); //Manuel's microcontrast void impulsedenoise (LabImage* lab);//Emil's impulse denoise void impulse_nr (LabImage* lab, double thresh); @@ -144,12 +149,15 @@ class ImProcFunctions { float MadMax(float * HH_Coeffs, int &max, int datalen); // pyramid equalizer - void dirpyr_equalizer (float ** src, float ** dst, int srcwidth, int srcheight, const double * mult );//Emil's directional pyramid equalizer + void dirpyr_equalizer (float ** src, float ** dst, int srcwidth, int srcheight, const double * mult);//Emil's directional pyramid equalizer + void dirpyr_equalizercam (CieImage* ncie, float ** src, float ** dst, int srcwidth, int srcheight, const double * mult, bool execdir );//Emil's directional pyramid equalizer void dirpyr_channel (float ** data_fine, float ** data_coarse, int width, int height, LUTf & rangefn, int level, int scale, const double * mult ); void idirpyr_eq_channel (float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, const double * mult ); void defringe (LabImage* lab); + void defringecam (CieImage* ncie); void PF_correct_RT (LabImage * src, LabImage * dst, double radius, int thresh); + void PF_correct_RTcam (CieImage * src, CieImage * dst, double radius, int thresh); Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile); Image16* lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6);// for gamma output diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index f71c8e3be..f6a78d899 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -404,7 +404,9 @@ void ImProcFunctions::MLsharpen (LabImage* lab) { if ((wH!=0.0f)&&(wV!=0.0f)&&(wD1!=0.0f)&&(wD2!=0.0f)) { iii = offset/width; kkk = offset-iii*width; - templab = v*(1-s)+(lumH*wH+lumV*wV+lumD1*wD1+lumD2*wD2)/(wH+wV+wD1+wD2)*s; + float provL=lab->L[iii][kkk]/327.68f; + if(c==0){ if(provL < 92.f) templab = v*(1-s)+(lumH*wH+lumV*wV+lumD1*wD1+lumD2*wD2)/(wH+wV+wD1+wD2)*s; else templab=provL;} + else templab = v*(1-s)+(lumH*wH+lumV*wV+lumD1*wD1+lumD2*wD2)/(wH+wV+wD1+wD2)*s; if (c==0) lab->L[iii][kkk] = fabs(327.68f*templab); // fabs because lab->L always >0 else if (c==1) lab->a[iii][kkk] = 327.68f*templab ; else if (c==2) lab->b[iii][kkk] = 327.68f*templab ; @@ -618,4 +620,385 @@ void ImProcFunctions::MLmicrocontrast(LabImage* lab) { } +void ImProcFunctions::MLmicrocontrastcam(CieImage* ncie) { + if (params->sharpenMicro.enabled==false) + return; + MyTime t1e,t2e; + t1e.set(); + int k; + if (params->sharpenMicro.matrix == false) k=2; else k=1; + // k=2 matrix 5x5 k=1 matrix 3x3 + int offset,offset2,i,j,col,row,n; + float temp,temp2,temp3,temp4,tempL; + float *LM,v,s,contrast; + int signs[25]; + int width = ncie->W, height = ncie->H; + float uniform = params->sharpenMicro.uniformity;//between 0 to 100 + int unif; + unif = (int)(uniform/10.0f); //put unif between 0 to 10 + float amount = params->sharpenMicro.amount/1500.0f; //amount 2000.0 quasi no artefacts ==> 1500 = maximum, after artefacts + if (amount < 0.000001f) + return; + if (k==1) + amount *= 2.7f; //25/9 if 3x3 + if (settings->verbose) + printf ("Micro-contrast amount %f\n", amount); + if (settings->verbose) + printf ("Micro-contrast uniformity %i\n",unif); + //modulation uniformity in function of luminance + float L98[11] = {0.001f,0.0015f,0.002f,0.004f,0.006f,0.008f,0.01f,0.03f,0.05f,0.1f,0.1f}; + float L95[11] = {0.0012f,0.002f,0.005f,0.01f,0.02f,0.05f,0.1f,0.12f,0.15f,0.2f,0.25f}; + float L92[11] = {0.01f,0.015f,0.02f,0.06f,0.10f,0.13f,0.17f,0.25f,0.3f,0.32f,0.35f}; + float L90[11] = {0.015f,0.02f,0.04f,0.08f,0.12f,0.15f,0.2f,0.3f,0.4f,0.5f,0.6f}; + float L87[11] = {0.025f,0.03f,0.05f,0.1f,0.15f,0.25f,0.3f,0.4f,0.5f,0.63f,0.75f}; + float L83[11] = {0.055f,0.08f,0.1f,0.15f,0.2f,0.3f,0.4f,0.5f,0.6f,0.75f,0.85f}; + float L80[11] = {0.15f,0.2f,0.25f,0.3f,0.35f,0.4f,0.5f,0.6f,0.7f,0.8f,0.9f}; + float L75[11] = {0.22f,0.25f,0.3f,0.4f,0.5f,0.6f,0.7f,0.8f,0.85f,0.9f,0.95f}; + float L70[11] = {0.35f,0.4f,0.5f,0.6f,0.7f,0.8f,0.97f,1.0f,1.0f,1.0f,1.0f}; + float L63[11] = {0.55f,0.6f,0.7f,0.8f,0.85f,0.9f,1.0f,1.0f,1.0f,1.0f,1.0f}; + float L58[11] = {0.75f,0.77f,0.8f,0.9f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f}; + //default 5 + //modulation contrast + float Cont0[11] = {0.05f,0.1f,0.2f,0.25f,0.3f,0.4f,0.5f,0.6f,0.7f,0.8f,0.9f}; + float Cont1[11] = {0.1f,0.2f,0.3f,0.4f,0.5f,0.6f,0.7f,0.8f,0.9f,0.95f,1.0f}; + float Cont2[11] = {0.2f,0.40f,0.6f,0.7f,0.8f,0.85f,0.90f,0.95f,1.0f,1.05f,1.10f}; + float Cont3[11] = {0.5f,0.6f,0.7f,0.8f,0.85f,0.9f,1.0f,1.0f,1.05f,1.10f,1.20f}; + float Cont4[11] = {0.8f,0.85f,0.9f,0.95f,1.0f,1.05f,1.10f,1.150f,1.2f,1.25f,1.40f}; + float Cont5[11] = {1.0f,1.1f,1.2f,1.25f,1.3f,1.4f,1.45f,1.50f,1.6f,1.65f,1.80f}; + + float chmax=8.0f; + LM = new float[width*height];//allocation for Luminance +#pragma omp parallel for private(offset, i,j) shared(LM) + for(j=0; jsh_p[j][i]/327.68f;// adjust to 0.100 and to RT variables + } + +#pragma omp parallel for private(j,i,offset,s,signs,v,n,row,col,offset2,contrast,temp,temp2,temp3,tempL,temp4) shared(ncie,LM,amount,chmax,unif,k,L98,L95,L92,L90,L87,L83,L80,L75,L70,L63,L58,Cont0,Cont1,Cont2,Cont3,Cont4,Cont5) + for(j=k; jLM[offset2]) signs[n]=1; + n++; + } + if (k==1) contrast = sqrt(fabs(LM[offset+1]-LM[offset-1])*fabs(LM[offset+1]-LM[offset-1])+fabs(LM[offset+width]-LM[offset-width])*fabs(LM[offset+width]-LM[offset-width]))/chmax; //for 3x3 + else if (k==2) contrast = sqrt(fabs(LM[offset+1]-LM[offset-1])*fabs(LM[offset+1]-LM[offset-1])+fabs(LM[offset+width]-LM[offset-width])*fabs(LM[offset+width]-LM[offset-width]) + +fabs(LM[offset+2]-LM[offset-2])*fabs(LM[offset+2]-LM[offset-2])+fabs(LM[offset+2*width]-LM[offset-2*width])*fabs(LM[offset+2*width]-LM[offset-2*width]))/(2*chmax); //for 5x5 + + if (contrast>1.0f) + contrast=1.0f; + //matrix 5x5 + temp=ncie->sh_p[j][i]/327.68f; //begin 3x3 + temp += CLIREF(v-LM[offset-width-1])*sqrtf(2.0f)*s; + temp += CLIREF(v-LM[offset-width])*s; + temp += CLIREF(v-LM[offset-width+1])*sqrtf(2.0f)*s; + temp += CLIREF(v-LM[offset-1])*s; + temp += CLIREF(v-LM[offset+1])*s; + temp += CLIREF(v-LM[offset+width-1])*sqrtf(2.0f)*s; + temp += CLIREF(v-LM[offset+width])*s; + temp += CLIREF(v-LM[offset+width+1])*sqrtf(2.0f)*s;//end 3x3 + + // add JD continue 5x5 + if (k==2) { + temp += 2.0f*CLIREF(v-LM[offset+2*width])*s; + temp += 2.0f*CLIREF(v-LM[offset-2*width])*s; + temp += 2.0f*CLIREF(v-LM[offset-2 ])*s; + temp += 2.0f*CLIREF(v-LM[offset+2 ])*s; + + temp += 2.0f*CLIREF(v-LM[offset+2*width-1])*s*sqrtf(1.25f);// 1.25 = 1*1 + 0.5*0.5 + temp += 2.0f*CLIREF(v-LM[offset+2*width-2])*s*sqrtf(2.00f); + temp += 2.0f*CLIREF(v-LM[offset+2*width+1])*s*sqrtf(1.25f); + temp += 2.0f*CLIREF(v-LM[offset+2*width+2])*s*sqrtf(2.00f); + temp += 2.0f*CLIREF(v-LM[offset+ width+2])*s*sqrtf(1.25f); + temp += 2.0f*CLIREF(v-LM[offset+ width-2])*s*sqrtf(1.25f); + temp += 2.0f*CLIREF(v-LM[offset-2*width-1])*s*sqrtf(1.25f); + temp += 2.0f*CLIREF(v-LM[offset-2*width-2])*s*sqrtf(2.00f); + temp += 2.0f*CLIREF(v-LM[offset-2*width+1])*s*sqrtf(1.25f); + temp += 2.0f*CLIREF(v-LM[offset-2*width+2])*s*sqrtf(2.00f); + temp += 2.0f*CLIREF(v-LM[offset- width+2])*s*sqrtf(1.25f); + temp += 2.0f*CLIREF(v-LM[offset- width-2])*s*sqrtf(1.25f); + } + if (temp <0.0f) temp = 0.0f; + v=temp; + + n=0; + + for(row=j-k; row<=j+k; row++) + for(col=i-k,offset2=row*width+col; col<=i+k; col++,offset2++){ + if (((v0))||((v>LM[offset2])&&(signs[n]<0))) { + temp = v*0.75f+LM[offset2]*0.25f;// 0.75 0.25 + n++; + } + } + if (LM[offset]>95.0f || LM[offset]<5.0f) + contrast *= Cont0[unif]; //+ JD : luminance pyramid to adjust contrast by evaluation of LM[offset] + else if (LM[offset]>90.0f || LM[offset]<10.0f) + contrast *= Cont1[unif]; + else if (LM[offset]>80.0f || LM[offset]<20.0f) + contrast *= Cont2[unif]; + else if (LM[offset]>70.0f || LM[offset]<30.0f) + contrast *= Cont3[unif]; + else if (LM[offset]>60.0f || LM[offset]<40.0f) + contrast *= Cont4[unif]; + else + contrast *= Cont5[unif];//(2.0f/k)*Cont5[unif]; + + if (contrast>1.0f) + contrast=1.0f; + tempL = 327.68f*(temp*(1.0f-contrast)+LM[offset]*contrast); + // JD: modulation of microcontrast in function of original Luminance and modulation of luminance + temp2 = tempL/(327.68f*LM[offset]);//for highlights + if (temp2>1.0f) { + if (temp2>1.70f) temp2=1.70f;//limit action + if (LM[offset]>98.0f) { ncie->sh_p[j][i]=LM[offset]*327.68f; } + else if (LM[offset]>95.0f) { temp3=temp2-1.0f; temp=(L95[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>92.0f) { temp3=temp2-1.0f; temp=(L92[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>90.0f) { temp3=temp2-1.0f; temp=(L90[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>87.0f) { temp3=temp2-1.0f; temp=(L87[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>83.0f) { temp3=temp2-1.0f; temp=(L83[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>80.0f) { temp3=temp2-1.0f; temp=(L80[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>75.0f) { temp3=temp2-1.0f; temp=(L75[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>70.0f) { temp3=temp2-1.0f; temp=(L70[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>63.0f) { temp3=temp2-1.0f; temp=(L63[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>58.0f) { temp3=temp2-1.0f; temp=(L58[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>42.0f) { temp3=temp2-1.0f; temp=(L58[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>37.0f) { temp3=temp2-1.0f; temp=(L63[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>30.0f) { temp3=temp2-1.0f; temp=(L70[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>25.0f) { temp3=temp2-1.0f; temp=(L75[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>20.0f) { temp3=temp2-1.0f; temp=(L80[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>17.0f) { temp3=temp2-1.0f; temp=(L83[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>13.0f) { temp3=temp2-1.0f; temp=(L87[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]>10.0f) { temp3=temp2-1.0f; temp=(L90[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]> 5.0f) { temp3=temp2-1.0f; temp=(L95[unif]*temp3)+1.0f; ncie->sh_p[j][i]=temp*LM[offset]*327.68f; } + else if (LM[offset]> 0.0f) { ncie->sh_p[j][i]=LM[offset]*327.68f;} + } + temp4 = (327.68f*LM[offset])/tempL;// + if (temp4>1.0f) { + if (temp4>1.7f) + temp4 = 1.7f;//limit action + if (LM[offset]< 2.0f) { temp3=temp4-1.0f; temp=(L98[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]< 5.0f) { temp3=temp4-1.0f; temp=(L95[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]< 8.0f) { temp3=temp4-1.0f; temp=(L92[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<10.0f) { temp3=temp4-1.0f; temp=(L90[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<13.0f) { temp3=temp4-1.0f; temp=(L87[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<17.0f) { temp3=temp4-1.0f; temp=(L83[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<20.0f) { temp3=temp4-1.0f; temp=(L80[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<25.0f) { temp3=temp4-1.0f; temp=(L75[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<30.0f) { temp3=temp4-1.0f; temp=(L70[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<37.0f) { temp3=temp4-1.0f; temp=(L63[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<42.0f) { temp3=temp4-1.0f; temp=(L58[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<58.0f) { temp3=temp4-1.0f; temp=(L58[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<63.0f) { temp3=temp4-1.0f; temp=(L63[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<70.0f) { temp3=temp4-1.0f; temp=(L70[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<75.0f) { temp3=temp4-1.0f; temp=(L75[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<80.0f) { temp3=temp4-1.0f; temp=(L80[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<83.0f) { temp3=temp4-1.0f; temp=(L83[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<87.0f) { temp3=temp4-1.0f; temp=(L87[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<90.0f) { temp3=temp4-1.0f; temp=(L90[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<95.0f) { temp3=temp4-1.0f; temp=(L95[unif]*temp3)+1.0f; ncie->sh_p[j][i]=(LM[offset]*327.68f)/temp; } + else if (LM[offset]<100.0f) { ncie->sh_p[j][i]=LM[offset]*327.68f; } + } + + } + delete [] LM; + t2e.set(); + if (settings->verbose) + printf("Micro-contrast %d usec\n", t2e.etime(t1e)); + +} + + + + +void ImProcFunctions::deconvsharpeningcam (CieImage* ncie, float** b2) { + + if (params->sharpening.enabled==false || params->sharpening.deconvamount<1) + return; + + int W = ncie->W, H = ncie->H; + + float** tmpI = new float*[H]; + for (int i=0; ish_p[i][j]; + } + + float** tmp = (float**)b2; + +#ifdef _OPENMP +#pragma omp parallel +#endif + { + AlignedBufferMP buffer(max(W,H)); + + float damping = params->sharpening.deconvdamping / 5.0; + bool needdamp = params->sharpening.deconvdamping > 0; + for (int k=0; ksharpening.deconviter; k++) { + + // apply blur function (gaussian blur) + gaussHorizontal (tmpI, tmp, buffer, W, H, params->sharpening.deconvradius / scale); + gaussVertical (tmp, tmp, buffer, W, H, params->sharpening.deconvradius / scale); + + if (!needdamp) { +#ifdef _OPENMP +#pragma omp for +#endif + for (int i=0; i0) + tmp[i][j] = (float)ncie->sh_p[i][j] / tmp[i][j]; + } + else + dcdamping (tmp, ncie->sh_p, damping, W, H); + + gaussHorizontal (tmp, tmp, buffer, W, H, params->sharpening.deconvradius / scale); + gaussVertical (tmp, tmp, buffer, W, H, params->sharpening.deconvradius / scale); + +#ifdef _OPENMP +#pragma omp for +#endif + for (int i=0; isharpening.deconvamount / 100.0; + float p2 = params->sharpening.deconvamount / 100.0; + float p1 = 1.0 - p2; + +#ifdef _OPENMP +#pragma omp for +#endif + for (int i=0; iJ_p[i][j] > 8.0f && ncie->J_p[i][j] < 92.0f) ncie->sh_p[i][j] = ncie->sh_p[i][j]*p1 + max(tmpI[i][j],0.0f)*p2; + + } // end parallel + + for (int i=0; isharpening.method=="rld") { + deconvsharpeningcam (ncie, b2); + return; + } + + // Rest is UNSHARP MASK + if (params->sharpening.enabled==false || params->sharpening.amount<1 || ncie->W<8 || ncie->H<8) + return; + + int W = ncie->W, H = ncie->H; + float** b3; + if (params->sharpening.edgesonly) { + b3 = new float*[H]; + for (int i=0; i buffer(max(W,H)); + + if (params->sharpening.edgesonly==false) { + + gaussHorizontal (ncie->sh_p, b2, buffer, W, H, params->sharpening.radius / scale); + gaussVertical (b2, b2, buffer, W, H, params->sharpening.radius / scale); + } + else { + bilateral (ncie->sh_p, (float**)b3, b2, W, H, params->sharpening.edges_radius / scale, params->sharpening.edges_tolerance, multiThread); + gaussHorizontal (b3, b2, buffer, W, H, params->sharpening.radius / scale); + gaussVertical (b2, b2, buffer, W, H, params->sharpening.radius / scale); + } + + float** base = ncie->sh_p; + if (params->sharpening.edgesonly) + base = b3; + + if (params->sharpening.halocontrol==false) { + #pragma omp for + for (int i=0; isharpening.threshold.multiply( + min(ABS(diff), upperBound), // X axis value = absolute value of the difference, truncated to the max value of this field + params->sharpening.amount * diff * 0.01f // Y axis max value + ); + if(ncie->J_p[i][j] > 8.0f && ncie->J_p[i][j] < 92.0f) ncie->sh_p[i][j] = ncie->sh_p[i][j] + delta; + } + } + else + sharpenHaloCtrlcam (ncie, b2, base, W, H); + + } // end parallel + + if (params->sharpening.edgesonly) { + for (int i=0; isharpening.halocontrol_amount) * 0.01f; + float sharpFac = params->sharpening.amount * 0.01f; + float** nL = base; + +#pragma omp parallel for if (multiThread) + for (int i=2; ish_p[i][j]; + if (max_ < labL) max_ = labL; + if (min_ > labL) min_ = labL; + + // deviation from the environment as measurement + float diff = nL[i][j] - blurmap[i][j]; + + const float upperBound = 2000.f; // WARNING: Duplicated value, it's baaaaaad ! + float delta = params->sharpening.threshold.multiply( + min(ABS(diff), upperBound), // X axis value = absolute value of the difference + sharpFac * diff // Y axis max value = sharpening.amount * signed difference + ); + float newL = labL + delta; + // applying halo control + if (newL > max_) + newL = max_ + (newL-max_) * scale; + else if (newL < min_) + newL = min_ - (min_-newL) * scale; + + ncie->sh_p[i][j] = newL; + } + } +} + } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 226cfa62b..febfb1d42 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -222,6 +222,7 @@ enum ProcEvent { EvCATCurveMode3=197, EvCATdatacie=198, EvCATtonecie=199, +// EvCATsharpcie=200, NUMOFEVENTS=200 }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 4abf1c21f..9ef9dcc44 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -232,6 +232,7 @@ void ProcParams::setDefaults () { colorappearance.gamut = true; colorappearance.datacie = false; colorappearance.tonecie = false; + // colorappearance.sharpcie = false; colorappearance.curve.clear (); colorappearance.curve.push_back(DCT_Linear); colorappearance.curve2.clear (); @@ -595,6 +596,7 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, ParamsEdited* p if (!pedited || pedited->colorappearance.gamut) keyFile.set_boolean ("Color appearance", "Gamut", colorappearance.gamut); if (!pedited || pedited->colorappearance.datacie) keyFile.set_boolean ("Color appearance", "Datacie", colorappearance.datacie); if (!pedited || pedited->colorappearance.tonecie) keyFile.set_boolean ("Color appearance", "Tonecie", colorappearance.tonecie); +// if (!pedited || pedited->colorappearance.sharpcie) keyFile.set_boolean ("Color appearance", "Sharpcie", colorappearance.sharpcie); if (!pedited || pedited->colorappearance.curveMode) { Glib::ustring method; switch (colorappearance.curveMode) { @@ -1114,6 +1116,7 @@ if (keyFile.has_group ("Color appearance")) { if (keyFile.has_key ("Color appearance", "Gamut")) {colorappearance.gamut = keyFile.get_boolean ("Color appearance", "Gamut"); if (pedited) pedited->colorappearance.gamut = true; } if (keyFile.has_key ("Color appearance", "Datacie")) {colorappearance.datacie = keyFile.get_boolean ("Color appearance", "Datacie"); if (pedited) pedited->colorappearance.datacie = true; } if (keyFile.has_key ("Color appearance", "Tonecie")) {colorappearance.tonecie = keyFile.get_boolean ("Color appearance", "Tonecie"); if (pedited) pedited->colorappearance.tonecie = true; } +// if (keyFile.has_key ("Color appearance", "Sharpcie")) {colorappearance.sharpcie = keyFile.get_boolean ("Color appearance", "Sharpcie"); if (pedited) pedited->colorappearance.sharpcie = true; } if (keyFile.has_key ("Color appearance", "CurveMode")) { Glib::ustring sMode = keyFile.get_string ("Color appearance", "CurveMode"); if (sMode == "Lightness") colorappearance.curveMode = ColorAppearanceParams::TC_MODE_LIGHT; diff --git a/rtengine/procparams.h b/rtengine/procparams.h index a7a7f0da9..6872bd448 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -390,6 +390,7 @@ class WBParams { bool gamut; bool datacie; bool tonecie; + // bool sharpcie; }; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index f1882bcb8..5a22d365b 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -220,6 +220,7 @@ LUMINANCECURVE, // EvCATcurve3 LUMINANCECURVE, // EvCATcurvemode3 LUMINANCECURVE, // EvCATdatacie LUMINANCECURVE // EvCATtonecie +//LUMINANCECURVE // EvCATsharpcie }; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 627d700b3..33fd52c96 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -791,15 +791,15 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei params.labCurve.acurve, params.labCurve.bcurve,params.labCurve.cccurve,params.labCurve.lccurve, curve1, curve2, satcurve,lhskcurve, hist16C, hist16C, dummy, 16); - //ipf.luminanceCurve (labView, labView, curve); + // ipf.luminanceCurve (labView, labView, curve); ipf.chromiLuminanceCurve (1,labView, labView, curve1, curve2, satcurve,lhskcurve, curve, utili, autili, butili, ccutili,cclutili, dummy); ipf.vibrance(labView); int begh = 0, endh = labView->H; - if(params.colorappearance.enabled && !params.colorappearance.tonecie) ipf.EPDToneMap(labView,5,6); + if((params.colorappearance.enabled && !params.colorappearance.tonecie) || !params.colorappearance.enabled) ipf.EPDToneMap(labView,5,6); - if(!params.colorappearance.enabled){ipf.EPDToneMap(labView,5,6);} +// if(!params.colorappearance.enabled){ipf.EPDToneMap(labView,5,6);} CurveFactory::curveLightBrightColor ( params.colorappearance.curveMode, params.colorappearance.curve, @@ -811,8 +811,16 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei customColCurve2, customColCurve3, 16); - - ipf.ciecam_02 (cieView, begh, endh, 1, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 6); + + int f_h=2,f_w=2; + float** buffer = new float*[fh]; + for (int i=0; iwidth / fh; diff --git a/rtengine/settings.h b/rtengine/settings.h index c0f067f0e..0fd851f2c 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -31,7 +31,7 @@ namespace rtengine { Glib::ustring monitorProfile; ///< ICC profile of the monitor (full path recommended) bool autoMonitorProfile; ///< Try to auto-determine the correct monitor color profile - + bool autocielab; bool verbose; Glib::ustring darkFramesPath; ///< The default directory for dark frames Glib::ustring flatFieldsPath; ///< The default directory for flat fields @@ -48,6 +48,7 @@ namespace rtengine { bool gamutICC; bool gamutLch; + bool ciecamfloat; int protectred; double protectredh; int CRI_color; // N° for display Lab value ; 0 disabled diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 097b79ee4..7251c6550 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -29,6 +29,9 @@ #include "rawimagesource.h" #include "../rtgui/ppversion.h" #undef THREAD_PRIORITY_NORMAL +#ifdef _OPENMP +#include +#endif namespace rtengine { extern const Settings* settings; @@ -167,7 +170,8 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p LUTf curve (65536,0); LUTf satcurve (65536,0); LUTf lhskcurve (65536,0); - + LUTf lumacurve(65536,0); + LUTf rCurve (65536,0); LUTf gCurve (65536,0); LUTf bCurve (65536,0); @@ -204,47 +208,68 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // start tile processing...??? hist16.clear(); hist16C.clear(); + if(params.labCurve.contrast !=0) {//only use hist16 for contrast + +#ifdef _OPENMP +#pragma omp parallel shared(hist16,labView, fh, fw) +#endif +{ +#ifdef _OPENMP +#pragma omp for schedule(static) +#endif + for (int i=0; iL[i][j])))]++; + } +} + + + } bool utili=false; bool autili=false; bool butili=false; bool ccutili=false; bool cclutili=false; - CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, hist16, hist16, curve, dummy, 1, utili); + CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve,hist16, hist16, lumacurve, dummy, 1, utili); CurveFactory::complexsgnCurve (autili, butili, ccutili, cclutili, params.labCurve.chromaticity, params.labCurve.rstprotection, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve,params.labCurve.lccurve,curve1, curve2, satcurve,lhskcurve, hist16C, hist16C,dummy, 1); - ipf.chromiLuminanceCurve (1,labView, labView, curve1, curve2, satcurve,lhskcurve,curve, utili, autili, butili, ccutili,cclutili,dummy); + + ipf.chromiLuminanceCurve (1,labView, labView, curve1, curve2, satcurve,lhskcurve,lumacurve, utili, autili, butili, ccutili,cclutili,dummy); - if(params.colorappearance.enabled && !params.colorappearance.tonecie)ipf.EPDToneMap(labView,5,1); + if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled))ipf.EPDToneMap(labView,5,1); - if(!params.colorappearance.enabled){ipf.EPDToneMap(labView,5,1);} ipf.vibrance(labView); ipf.impulsedenoise (labView); - ipf.defringe (labView); + // for all treatments Defringe, Sharpening, Contrast detail ,Microcontrast they are activated if "CIECAM" function are disabled + + if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) ipf.defringe (labView); + if (params.sharpenEdge.enabled) { ipf.MLsharpen(labView); } if (params.sharpenMicro.enabled) { - ipf.MLmicrocontrast (labView); + if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) ipf.MLmicrocontrast (labView);//!params.colorappearance.sharpcie } - if (params.sharpening.enabled) { - float** buffer = new float*[fh]; - for (int i=0; iautocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) { + + float **buffer = new float*[fh]; + for (int i=0; iautocielab) || !params.colorappearance.enabled) ipf.dirpyrequalizer (labView);//TODO: this is the luminance tonecurve, not the RGB one //Colorappearance and tone-mapping associated @@ -264,9 +289,30 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p customColCurve2, customColCurve3, 1); - - ipf.ciecam_02 (cieView, begh, endh,1, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 1); - + if (params.sharpening.enabled) { + float** buffer = new float*[fh]; + for (int i=0; iciecamfloat) ipf.ciecam_02float (cieView, begh, endh,1, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 1, (float**)buffer, true); + else ipf.ciecam_02 (cieView, begh, endh,1, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 1, (float**)buffer, true); + + for (int i=0; iciecamfloat) ipf.ciecam_02float (cieView, begh, endh,1, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 1, (float**)buffer, true); +else ipf.ciecam_02 (cieView, begh, endh,1, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 1, (float**)buffer, true); + + for (int i=0; isetProgress (0.75); - +/* curve1.reset();curve2.reset(); + curve.reset(); + satcurve.reset(); + lhskcurve.reset(); + + rCurve.reset(); + gCurve.reset(); + bCurve.reset(); + hist16.reset(); + hist16C.reset(); +*/ return readyImg; } diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index 89274c791..58fd51a67 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -181,7 +181,12 @@ ColorAppearance::ColorAppearance () : Gtk::VBox(), FoldableToolPanel(this) { tonecie->set_tooltip_markup (M("TP_COLORAPP_TONECIE_TOOLTIP")); tonecieconn = tonecie->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::tonecie_toggled) ); p2VBox->pack_start (*tonecie); - +/* + sharpcie = Gtk::manage (new Gtk::CheckButton (M("TP_COLORAPP_SHARPCIE"))); + sharpcie->set_tooltip_markup (M("TP_COLORAPP_SHARPCIE_TOOLTIP")); + sharpcieconn = sharpcie->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::sharpcie_toggled) ); + p2VBox->pack_start (*sharpcie); +*/ p2VBox->pack_start (*Gtk::manage (new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET, 4); toneCurveMode = Gtk::manage (new MyComboBoxText ()); @@ -337,12 +342,6 @@ ColorAppearance::ColorAppearance () : Gtk::VBox(), FoldableToolPanel(this) { gamut->set_tooltip_markup (M("TP_COLORAPP_GAMUT_TOOLTIP")); gamutconn = gamut->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::gamut_toggled) ); pack_start (*gamut, Gtk::PACK_SHRINK); -/* - tonecie = Gtk::manage (new Gtk::CheckButton (M("TP_COLORAPP_TONECIE"))); - tonecie->set_tooltip_markup (M("TP_COLORAPP_TONECIE_TOOLTIP")); - tonecieconn = tonecie->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::tonecie_toggled) ); - pack_start (*tonecie, Gtk::PACK_SHRINK); -*/ // ------------------------ Listening events @@ -415,6 +414,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) { gamut->set_inconsistent (!pedited->colorappearance.gamut); datacie->set_inconsistent (!pedited->colorappearance.datacie); tonecie->set_inconsistent (!pedited->colorappearance.tonecie); + // sharpcie->set_inconsistent (!pedited->colorappearance.sharpcie); degree->setAutoInconsistent (multiImage && !pedited->colorappearance.autodegree); enabled->set_inconsistent (multiImage && !pedited->colorappearance.enabled); @@ -491,11 +491,15 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) { tonecieconn.block (true); tonecie->set_active (pp->colorappearance.tonecie); tonecieconn.block (false); +// sharpcieconn.block (true); +// sharpcie->set_active (pp->colorappearance.sharpcie); +// sharpcieconn.block (false); lastsurr=pp->colorappearance.surrsource; lastgamut=pp->colorappearance.gamut; lastdatacie=pp->colorappearance.datacie; lasttonecie=pp->colorappearance.tonecie; +// lastsharpcie=pp->colorappearance.sharpcie; lastEnabled = pp->colorappearance.enabled; lastAutoDegree = pp->colorappearance.autodegree; @@ -547,6 +551,7 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) { pp->colorappearance.gamut = gamut->get_active(); pp->colorappearance.datacie = datacie->get_active(); pp->colorappearance.tonecie = tonecie->get_active(); +// pp->colorappearance.sharpcie = sharpcie->get_active(); pp->colorappearance.curve = shape->getCurve (); pp->colorappearance.curve2 = shape2->getCurve (); pp->colorappearance.curve3 = shape3->getCurve (); @@ -586,6 +591,7 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) { pedited->colorappearance.gamut = !gamut->get_inconsistent(); pedited->colorappearance.datacie = !datacie->get_inconsistent(); pedited->colorappearance.tonecie = !tonecie->get_inconsistent(); + // pedited->colorappearance.sharpcie = !sharpcie->get_inconsistent(); pedited->colorappearance.curve = !shape->isUnChanged (); pedited->colorappearance.curve2 = !shape2->isUnChanged (); pedited->colorappearance.curve3 = !shape3->isUnChanged (); @@ -753,7 +759,30 @@ void ColorAppearance::tonecie_toggled () { } } +/* +void ColorAppearance::sharpcie_toggled () { + if (batchMode) { + if (sharpcie->get_inconsistent()) { + sharpcie->set_inconsistent (false); + sharpcieconn.block (true); + sharpcie->set_active (false); + sharpcieconn.block (false); + } + else if (lastsharpcie) + sharpcie->set_inconsistent (true); + + lastsharpcie = sharpcie->get_active (); + } + if (listener) { + if (sharpcie->get_active ()) + listener->panelChanged (EvCATsharpcie, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvCATsharpcie, M("GENERAL_DISABLED")); + } + +} +*/ void ColorAppearance::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { @@ -929,6 +958,7 @@ void ColorAppearance::algoChanged () { qbright->hide(); colorh->hide(); tonecie->hide(); + // sharpcie->hide(); curveEditorG->show(); curveEditorG2->show(); curveEditorG3->show(); @@ -944,6 +974,7 @@ void ColorAppearance::algoChanged () { qbright->hide(); colorh->hide(); tonecie->hide(); +// sharpcie->hide(); curveEditorG->show(); curveEditorG2->show(); curveEditorG3->show(); @@ -959,6 +990,8 @@ void ColorAppearance::algoChanged () { qbright->show(); colorh->hide(); tonecie->show(); + // sharpcie->show(); + // sharpcie->hide(); curveEditorG->show(); curveEditorG2->show(); curveEditorG3->show(); @@ -974,6 +1007,8 @@ void ColorAppearance::algoChanged () { qbright->show(); colorh->show(); tonecie->show(); +// sharpcie->show(); +// sharpcie->hide(); curveEditorG->show(); curveEditorG2->show(); curveEditorG3->show(); diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h index abcc8354f..0b69002a0 100644 --- a/rtgui/colorappearance.h +++ b/rtgui/colorappearance.h @@ -57,6 +57,7 @@ class ColorAppearance : public Gtk::VBox, public AdjusterListener, public Foldab Gtk::CheckButton* gamut; Gtk::CheckButton* datacie; Gtk::CheckButton* tonecie; + // Gtk::CheckButton* sharpcie; Gtk::CheckButton* enabled; MyComboBoxText* surround; @@ -66,7 +67,7 @@ class ColorAppearance : public Gtk::VBox, public AdjusterListener, public Foldab MyComboBoxText* algo; sigc::connection algoconn; sigc::connection surrconn; - sigc::connection gamutconn, datacieconn, tonecieconn; + sigc::connection gamutconn, datacieconn, tonecieconn /*, sharpcieconn*/; sigc::connection tcmodeconn, tcmode2conn, tcmode3conn; CurveEditorGroup* curveEditorG; CurveEditorGroup* curveEditorG2; @@ -83,7 +84,8 @@ class ColorAppearance : public Gtk::VBox, public AdjusterListener, public Foldab bool lastgamut; bool lastdatacie; bool lasttonecie; - bool bgTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip); + // bool lastsharpcie; + bool bgTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip); bool srTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip); public: @@ -106,6 +108,7 @@ class ColorAppearance : public Gtk::VBox, public AdjusterListener, public Foldab void gamut_toggled (); void datacie_toggled (); void tonecie_toggled (); +// void sharpcie_toggled (); void curveChanged (CurveEditor* ce); void curveMode1Changed (); diff --git a/rtgui/defringe.cc b/rtgui/defringe.cc index 0a4142299..3fc98d497 100644 --- a/rtgui/defringe.cc +++ b/rtgui/defringe.cc @@ -29,6 +29,8 @@ Defringe::Defringe () : Gtk::VBox(), FoldableToolPanel(this) { enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); enabled->set_active (false); + enabled->set_tooltip_markup (M("TP_SHARPENING_TOOLTIP")); + enabled->show (); pack_start (*enabled); diff --git a/rtgui/dirpyrequalizer.cc b/rtgui/dirpyrequalizer.cc index 57ca3b8bb..edfb1fcd7 100644 --- a/rtgui/dirpyrequalizer.cc +++ b/rtgui/dirpyrequalizer.cc @@ -30,6 +30,7 @@ DirPyrEqualizer::DirPyrEqualizer () : Gtk::VBox(), FoldableToolPanel(this) { enabled->set_active (true); pack_start(*enabled); enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &DirPyrEqualizer::enabledToggled) ); + enabled->set_tooltip_markup (M("TP_SHARPENING_TOOLTIP")); Gtk::HSeparator *separator1 = Gtk::manage (new Gtk::HSeparator()); pack_start(*separator1, Gtk::PACK_SHRINK, 2); diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc index 4cc81855f..2208886c6 100644 --- a/rtgui/labcurve.cc +++ b/rtgui/labcurve.cc @@ -239,6 +239,7 @@ void LCurve::autoOpenCurve () { if (!active) ccshape->openIfNonlinear(); if (!active) chshape->openIfNonlinear(); if (!active) lcshape->openIfNonlinear(); + } void LCurve::write (ProcParams* pp, ParamsEdited* pedited) { diff --git a/rtgui/options.cc b/rtgui/options.cc index d4fc3002d..4f924a2a9 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -438,10 +438,11 @@ void Options::setDefaults () { rtSettings.verbose = false; rtSettings.gamutICC = true; rtSettings.gamutLch = true; + rtSettings.ciecamfloat = true; rtSettings.protectred = 60; rtSettings.protectredh = 0.3; rtSettings.CRI_color =0; - + rtSettings.autocielab=true; lastIccDir = rtSettings.iccDirectory; lastDarkframeDir = rtSettings.darkFramesPath; lastFlatfieldDir = rtSettings.flatFieldsPath; @@ -647,6 +648,8 @@ if (keyFile.has_group ("Color Management")) { if (keyFile.has_key ("Color Management", "ICCDirectory")) rtSettings.iccDirectory = keyFile.get_string ("Color Management", "ICCDirectory"); if (keyFile.has_key ("Color Management", "MonitorProfile")) rtSettings.monitorProfile = keyFile.get_string ("Color Management", "MonitorProfile"); if (keyFile.has_key ("Color Management", "AutoMonitorProfile")) rtSettings.autoMonitorProfile = keyFile.get_boolean ("Color Management", "AutoMonitorProfile"); + if (keyFile.has_key ("Color Management", "Autocielab")) rtSettings.autocielab = keyFile.get_boolean ("Color Management", "Autocielab"); + if (keyFile.has_key ("Color Management", "Ciencamfloat")) rtSettings.ciecamfloat = keyFile.get_boolean ("Color Management", "Ciecamfloat"); if (keyFile.has_key ("Color Management", "Intent")) rtSettings.colorimetricIntent = keyFile.get_integer("Color Management", "Intent"); if (keyFile.has_key ("Color Management", "CRI")) rtSettings.CRI_color = keyFile.get_integer("Color Management", "CRI"); @@ -655,6 +658,7 @@ if (keyFile.has_group ("Color Management")) { if (keyFile.has_key ("Color Management", "WhiteBalanceSpotSize")) whiteBalanceSpotSize = keyFile.get_integer("Color Management", "WhiteBalanceSpotSize"); if( keyFile.has_key ("Color Management", "GamutICC")) rtSettings.gamutICC = keyFile.get_boolean("Color Management", "GamutICC"); + if( keyFile.has_key ("Color Management", "Ciecamfloat")) rtSettings.ciecamfloat = keyFile.get_boolean("Color Management", "Ciecamfloat"); if( keyFile.has_key ("Color Management", "AdobeRGB")) rtSettings.adobe = keyFile.get_string("Color Management", "AdobeRGB"); if( keyFile.has_key ("Color Management", "ProPhoto")) rtSettings.prophoto = keyFile.get_string("Color Management", "ProPhoto"); if( keyFile.has_key ("Color Management", "ProPhoto10")) rtSettings.prophoto10 = keyFile.get_string("Color Management", "ProPhoto10"); @@ -894,6 +898,7 @@ int Options::saveToFile (Glib::ustring fname) { keyFile.set_string ("Color Management", "ICCDirectory", rtSettings.iccDirectory); keyFile.set_string ("Color Management", "MonitorProfile", rtSettings.monitorProfile); keyFile.set_boolean ("Color Management", "AutoMonitorProfile", rtSettings.autoMonitorProfile); + keyFile.set_boolean ("Color Management", "Autocielab", rtSettings.autocielab); keyFile.set_integer ("Color Management", "Intent", rtSettings.colorimetricIntent); keyFile.set_integer ("Color Management", "view", rtSettings.viewingdevice); keyFile.set_integer ("Color Management", "grey", rtSettings.viewingdevice); @@ -909,6 +914,7 @@ int Options::saveToFile (Glib::ustring fname) { keyFile.set_string ("Color Management", "Bruce", rtSettings.bruce); keyFile.set_integer ("Color Management", "WhiteBalanceSpotSize", whiteBalanceSpotSize); keyFile.set_boolean ("Color Management", "GamutICC", rtSettings.gamutICC); + keyFile.set_boolean ("Color Management", "Ciecamfloat", rtSettings.ciecamfloat); keyFile.set_boolean ("Color Management", "GamutLch", rtSettings.gamutLch); keyFile.set_integer ("Color Management", "ProtectRed", rtSettings.protectred); keyFile.set_double ("Color Management", "ProtectRedH", rtSettings.protectredh); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index e03324c0a..1e95c0a86 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -114,6 +114,7 @@ void ParamsEdited::set (bool v) { colorappearance.gamut = v; colorappearance.datacie = v; colorappearance.tonecie = v; +// colorappearance.sharpcie = v; colorappearance.curve = v; colorappearance.curve2 = v; colorappearance.curve3 = v; @@ -345,6 +346,7 @@ void ParamsEdited::initFrom (const std::vector colorappearance.gamut = colorappearance.gamut && p.colorappearance.gamut == other.colorappearance.gamut; colorappearance.datacie = colorappearance.datacie && p.colorappearance.datacie == other.colorappearance.datacie; colorappearance.tonecie = colorappearance.tonecie && p.colorappearance.tonecie == other.colorappearance.tonecie; + // colorappearance.sharpcie = colorappearance.sharpcie && p.colorappearance.sharpcie == other.colorappearance.sharpcie; colorappearance.curve = colorappearance.curve && p.colorappearance.curve == other.colorappearance.curve; colorappearance.curve3 = colorappearance.curve3 && p.colorappearance.curve3 == other.colorappearance.curve3; colorappearance.curve2 = colorappearance.curve2 && p.colorappearance.curve2 == other.colorappearance.curve2; @@ -612,6 +614,7 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (colorappearance.gamut) toEdit.colorappearance.gamut = mods.colorappearance.gamut; if (colorappearance.datacie) toEdit.colorappearance.datacie = mods.colorappearance.datacie; if (colorappearance.tonecie) toEdit.colorappearance.tonecie = mods.colorappearance.tonecie; +// if (colorappearance.sharpcie) toEdit.colorappearance.sharpcie = mods.colorappearance.sharpcie; if (impulseDenoise.enabled) toEdit.impulseDenoise.enabled = mods.impulseDenoise.enabled; if (impulseDenoise.thresh) toEdit.impulseDenoise.thresh = mods.impulseDenoise.thresh; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index cf8f3902a..3b3472ffc 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -211,6 +211,7 @@ public: bool gamut; bool datacie; bool tonecie; +// bool sharpcie; }; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 036263202..a331bf4a6 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -195,7 +195,6 @@ Gtk::Widget* Preferences::getBatchProcPanel () { mi->set_value (behavColumns.label, M("TP_COLORAPP_LABEL")); appendBehavList (mi, M("TP_COLORAPP_CIECAT_DEGREE"),ADDSET_CAT_DEGREE, true); appendBehavList (mi, M("TP_COLORAPP_ADAPTSCENE"),ADDSET_CAT_ADAPTSCENE, true); - appendBehavList (mi, M("TP_COLORAPP_ADAPTVIEWING"),ADDSET_CAT_ADAPTVIEWING, true); appendBehavList (mi, M("TP_COLORAPP_LIGHT"),ADDSET_CAT_LIGHT, true); appendBehavList (mi, M("TP_COLORAPP_BRIGHT"),ADDSET_CAT_BRIGHT, true); appendBehavList (mi, M("TP_COLORAPP_CHROMA"),ADDSET_CAT_CHROMA, true); @@ -205,6 +204,7 @@ Gtk::Widget* Preferences::getBatchProcPanel () { appendBehavList (mi, M("TP_COLORAPP_CHROMA_S"),ADDSET_CAT_CHROMA_S, true); appendBehavList (mi, M("TP_COLORAPP_CHROMA_M"),ADDSET_CAT_CHROMA_M, true); appendBehavList (mi, M("TP_COLORAPP_HUE"),ADDSET_CAT_HUE, true); + appendBehavList (mi, M("TP_COLORAPP_ADAPTVIEWING"),ADDSET_CAT_ADAPTVIEWING, true); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_VIBRANCE_LABEL")); @@ -460,9 +460,21 @@ Gtk::Widget* Preferences::getColorManagementPanel () { colo->attach (*greylab, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); colo->attach (*grey, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); colo->attach (*restartNeeded2, 2, 3, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - mvbcm->pack_start (*colo, Gtk::PACK_SHRINK, 4); + Gtk::Label* cielab = Gtk::manage (new Gtk::Label (M("PREFERENCES_CIEART")+":", Gtk::ALIGN_LEFT)); + cbciecamfloat = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_CIEART_LABEL"))); + //autocielabConn = cbAutocielab->signal_toggled().connect (sigc::mem_fun(*this, &Preferences::autocielabToggled)); + Gtk::Table* coltcie = Gtk::manage (new Gtk::Table (1, 2)); + coltcie->attach (*cielab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + // coltcie->attach (*cbAutocielab, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + //cbAutocielab->set_tooltip_markup (M("PREFERENCES_CIEART_TOOLTIP")); + coltcie->attach (*cbciecamfloat, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + cbciecamfloat->set_tooltip_markup (M("PREFERENCES_CIEART_TOOLTIP")); + + mvbcm->pack_start (*coltcie, Gtk::PACK_SHRINK, 4); + // autocielabToggled(); + return mvbcm; } @@ -1077,6 +1089,8 @@ void Preferences::storePreferences () { moptions.rtSettings.colorimetricIntent = intent->get_active_row_number (); moptions.rtSettings.viewingdevice = view->get_active_row_number (); moptions.rtSettings.viewingdevicegrey = grey->get_active_row_number (); + // moptions.rtSettings.autocielab = cbAutocielab->get_active (); + moptions.rtSettings.ciecamfloat = cbciecamfloat->get_active (); if (sdcurrent->get_active ()) moptions.startupDir = STARTUPDIR_CURRENT; @@ -1165,7 +1179,8 @@ void Preferences::fillPreferences () { intent->set_active (moptions.rtSettings.colorimetricIntent); view->set_active (moptions.rtSettings.viewingdevice); grey->set_active (moptions.rtSettings.viewingdevicegrey); - +// cbAutocielab->set_active (moptions.rtSettings.autocielab); + cbciecamfloat->set_active (moptions.rtSettings.ciecamfloat); languages->set_active_text (moptions.language); ckbLangAutoDetect->set_active (moptions.languageAutoDetect); theme->set_active_text (moptions.theme); @@ -1312,7 +1327,11 @@ void Preferences::savePressed () { void Preferences::autoMonProfileToggled () { monProfile->set_sensitive(!cbAutoMonProfile->get_active()); } - +/* +void Preferences::autocielabToggled () { +// cbAutocielab->set_sensitive(cbAutocielab->get_active()); +} +*/ void Preferences::sndEnableToggled () { txtSndBatchQueueDone->set_sensitive(ckbSndEnable->get_active()); txtSndLngEditProcDone->set_sensitive(ckbSndEnable->get_active()); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 3ee715847..d0cd991e7 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -80,6 +80,8 @@ class Preferences : public Gtk::Dialog { Gtk::FileChooserButton* iccDir; Gtk::FileChooserButton* monProfile; Gtk::CheckButton* cbAutoMonProfile; + //Gtk::CheckButton* cbAutocielab; + Gtk::CheckButton* cbciecamfloat; Gtk::CheckButton* blinkClipped; Gtk::SpinButton* hlThresh; @@ -144,7 +146,7 @@ class Preferences : public Gtk::Dialog { Options moptions; sigc::connection tconn, sconn, fconn, usethcon, addc, setc, dfconn, ffconn; - sigc::connection autoMonProfileConn, sndEnableConn, langAutoDetectConn; + sigc::connection autoMonProfileConn, sndEnableConn, langAutoDetectConn, autocielabConn; Glib::ustring initialTheme; Glib::ustring initialFont; @@ -186,6 +188,7 @@ class Preferences : public Gtk::Dialog { void autoMonProfileToggled (); void sndEnableToggled (); void langAutoDetectToggled (); + void autocielabToggled (); void selectStartupDir (); void addExtPressed (); diff --git a/rtgui/sharpening.cc b/rtgui/sharpening.cc index 0d257f074..0555bc609 100644 --- a/rtgui/sharpening.cc +++ b/rtgui/sharpening.cc @@ -33,6 +33,8 @@ Sharpening::Sharpening () : Gtk::VBox(), FoldableToolPanel(this) { milestones.push_back( GradientMilestone(1.0, 1.0, 1.0, 1.0) ); enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + enabled->set_tooltip_markup (M("TP_SHARPENING_TOOLTIP")); + enabled->set_active (true); pack_start(*enabled); enabled->show (); diff --git a/rtgui/sharpenmicro.cc b/rtgui/sharpenmicro.cc index 9e9978abd..7d20822e4 100644 --- a/rtgui/sharpenmicro.cc +++ b/rtgui/sharpenmicro.cc @@ -33,6 +33,8 @@ SharpenMicro::SharpenMicro () : Gtk::VBox(), FoldableToolPanel(this) { enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); enabled->set_active (true); + enabled->set_tooltip_markup (M("TP_SHARPENING_TOOLTIP")); + pack_start(*enabled, Gtk::PACK_SHRINK, 0); enabled->show (); diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index e35c4018f..69a819f77 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -212,8 +212,8 @@ void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { } void ToneCurve::autoOpenCurve () { - shape->openIfNonlinear(); - shape2->openIfNonlinear(); + shape->openIfNonlinear(); + shape2->openIfNonlinear(); } void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) {