From 1d8beefb91fb818b35a4bed6748b1317113e34ab Mon Sep 17 00:00:00 2001 From: jdc Date: Thu, 15 Nov 2012 07:53:14 +0100 Subject: [PATCH] three curves for CIECAM - see issue1620 and issue1623 --- rtdata/languages/Francais | 27 +- rtdata/languages/default | 34 +- rtdata/profiles/BW-1.pp3 | 8 +- rtdata/profiles/BW-2.pp3 | 8 +- rtdata/profiles/BW-3.pp3 | 8 +- rtdata/profiles/BW-4.pp3 | 8 +- rtdata/profiles/Default-ISO-High.pp3 | 8 +- rtdata/profiles/Default-ISO-Medium.pp3 | 8 +- rtdata/profiles/Default.pp3 | 9 +- rtdata/profiles/Highkey-1.pp3 | 8 +- rtdata/profiles/Natural-1.pp3 | 8 +- rtdata/profiles/Natural-2.pp3 | 8 +- rtdata/profiles/Neutral.pp3 | 8 +- rtdata/profiles/Punchy-1.pp3 | 8 +- rtdata/profiles/Punchy-2.pp3 | 8 +- rtengine/color.cc | 127 ++++--- rtengine/color.h | 1 + rtengine/colortemp.cc | 388 +--------------------- rtengine/colortemp.h | 40 ++- rtengine/curves.cc | 80 ++++- rtengine/curves.h | 88 ++++- rtengine/dcrop.cc | 15 +- rtengine/improccoordinator.cc | 12 +- rtengine/improccoordinator.h | 3 + rtengine/improcfun.cc | 437 ++++++++++++++++++++++++- rtengine/improcfun.h | 2 + rtengine/procevents.h | 8 +- rtengine/procparams.cc | 100 +++++- rtengine/procparams.h | 34 +- rtengine/refreshmap.cc | 8 +- rtengine/rtthumbnail.cc | 15 +- rtengine/simpleprocess.cc | 14 +- rtgui/colorappearance.cc | 340 +++++++++++++++---- rtgui/colorappearance.h | 73 +++-- rtgui/paramsedited.cc | 19 ++ rtgui/paramsedited.h | 10 +- rtgui/preferences.cc | 3 + rtgui/toolpanelcoord.cc | 2 +- rtgui/toolpanelcoord.h | 2 +- 39 files changed, 1424 insertions(+), 563 deletions(-) diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 6403a3ab6..56553b07d 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -416,6 +416,12 @@ HISTORY_MSG_189;CAM02 - Contraste (Q) HISTORY_MSG_190;CAM02 - Saturation (S) HISTORY_MSG_191;CAM02 - Niveau de couleur (M) HISTORY_MSG_192;CAM02 - Teinte (angle) +HISTORY_MSG_193;CAM02 - Courbe tonale 1 +HISTORY_MSG_194;CAM02 - Courbe tonale 2 +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_NEWSNAPSHOTAS;Sous... HISTORY_NEWSNAPSHOT;Ajouter HISTORY_NEWSSDIALOGLABEL;Label de la capture: @@ -912,8 +918,8 @@ TP_COLORAPP_DEGREE_TOOLTIP;Niveau d'adaptation chromatique CIE CAT 2002\nSi vous TP_COLORAPP_EQUAL;Préservé TP_COLORAPP_GAMUT;Contrôle du gamut (Lab & CIECAM) TP_COLORAPP_GAMUT_TOOLTIP;Permet le controle du gamut en mode Lab -TP_COLORAPP_HUE;Teinte (H) -TP_COLORAPP_HUE_TOOLTIP;Teinte (H) - angle entre 0° et 360° +TP_COLORAPP_HUE;Teinte (h) +TP_COLORAPP_HUE_TOOLTIP;Teinte (h) - angle entre 0° et 360° TP_COLORAPP_LABEL;Modèle CIE d'Apparence de la Couleur (CAM02) TP_COLORAPP_LABEL_CAM02;Édition de l'image avec CIECAM TP_COLORAPP_LABEL_SCENE;Conditions de la scène @@ -922,8 +928,8 @@ TP_COLORAPP_LIGHT;Luminosité (J) TP_COLORAPP_LIGHT_TOOLTIP;Luminosité dans CIECAM02 est différent de Lab et RVB TP_COLORAPP_MODEL;Modèle de Point Blanc TP_COLORAPP_MODEL_TOOLTIP;BB [RT] + [sortie]:\nLa BB de RT est utilisée pour la scène, CIECAM est réglé sur D50, le blanc du périphérique de sortie utilise la valeur réglé dans Préférences\n\nBB [RT+CAT02] + [sortie]:\nLes réglages de BB de RT sont utilisés par CAT02 et le blanc du périphérique de sortie utilise la valeur réglé dans Préférences -TP_COLORAPP_RSTPRO;Protection des tons chairs et rouges (C) -TP_COLORAPP_RSTPRO_TOOLTIP;Protection par le curseur (C) des tons chairs et rouges +TP_COLORAPP_RSTPRO;Protection des tons chairs et rouges +TP_COLORAPP_RSTPRO_TOOLTIP;Protection des tons chairs et rouges (curseurs et courbes) TP_COLORAPP_SURROUND;Entourage TP_COLORAPP_SURROUND_AVER;Moyen TP_COLORAPP_SURROUND_DARK;Sombre @@ -934,6 +940,19 @@ TP_COLORAPP_SURSOURCE;Entourage sombre TP_COLORAPP_SURSOURCE_TOOLTIP;Peut être utilisé si l'image source a un bord noir. TP_COLORAPP_WBCAM;BB [RT+CAT02] + [sortie] TP_COLORAPP_WBRT;BB [RT] + [sortie] +TP_COLORAPP_CURVEEDITOR1;Courbe tonale 1 +TP_COLORAPP_CURVEEDITOR2;Courbe tonale 2 +TP_COLORAPP_CURVEEDITOR3;Courbes chroma +TP_COLORAPP_TCMODE_CHROMA;Chroma +TP_COLORAPP_TCMODE_SATUR;Saturation +TP_COLORAPP_TCMODE_COLORF;Niveau de couleurs +TP_COLORAPP_TCMODE_BRIGHTNESS;Brillance +TP_COLORAPP_TCMODE_LIGHTNESS;Luminosité +TP_COLORAPP_TCMODE_LABEL1;Courbe mode 1 +TP_COLORAPP_TCMODE_LABEL2;Courbe mode 2 +TP_COLORAPP_TCMODE_LABEL3;Courbe chroma mode +TP_COLORAPP_CURVEEDITOR2_TOOLTIP;usage similaire aux courbes tonales exposition +TP_COLORAPP_CURVEEDITOR3_TOOLTIP;Vous pouvez choisir entre chroma -saturation- niveau couleurs TP_CROP_FIXRATIO;Ratio fixe: TP_CROP_GTDIAGONALS;Règle des diagonales TP_CROP_GTEPASSPORT;Passeport biométrique diff --git a/rtdata/languages/default b/rtdata/languages/default index f8f83849f..95ca96208 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -416,6 +416,12 @@ HISTORY_MSG_189;CAM02 - Contrast (Q) HISTORY_MSG_190;CAM02 - Saturation (S) HISTORY_MSG_191;CAM02 - Colorfullness (M) HISTORY_MSG_192;CAM02 - Hue (angle) +HISTORY_MSG_193;CAM02 - Tone curve 1 +HISTORY_MSG_194;CAM02 - Tone curve 2 +HISTORY_MSG_195;CAM02 - Tone curve +HISTORY_MSG_196;CAM02 - Tone curve 2 +HISTORY_MSG_197;CAM02 - Color curve +HISTORY_MSG_198;CAM02 - Color curve HISTORY_NEWSNAPSHOTAS;As... HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s @@ -667,12 +673,15 @@ PREFERENCES_CACHESTRAT;Cache Strategy PREFERENCES_CACHETHUMBFORM;Cache thumbnail format PREFERENCES_CACHETHUMBHEIGHT;Maximal thumbnail height PREFERENCES_CLIPPINGIND;Clipping Indication -PREFERENCES_VIEW;Output device's white balance setting (monitor, TV, projector,...) +PREFERENCES_VIEW;Output device's white balance setting (monitor, TV, projector,viewing...) PREFERENCES_D65;6500K PREFERENCES_D60;6000K PREFERENCES_D55;5500K PREFERENCES_D50;5000K PREFERENCES_BLACKBODY;Tungsten +PREFERENCES_FLUOF2;Fluorescent F2 +PREFERENCES_FLUOF7;Fluorescent F7 +PREFERENCES_FLUOF11;Fluorescent F11 PREFERENCES_GREY;Output device's Yb luminance (%) PREFERENCES_GREY05;Yb=05 CIE L#30 PREFERENCES_GREY10;Yb=10 CIE L#40 @@ -887,7 +896,7 @@ TP_COLORAPP_ADAPTVIEWING_TOOLTIP;Absolute luminance of the viewing environnement TP_COLORAPP_ALGO;Algorithm TP_COLORAPP_ALGO_ALL;All TP_COLORAPP_ALGO_JC;Lightness + Chroma (JC) -TP_COLORAPP_ALGO_JS;Lightnes + Saturation (JS) +TP_COLORAPP_ALGO_JS;Lightness + Saturation (JS) TP_COLORAPP_ALGO_QM;Brightness + Colorfullness (QM) TP_COLORAPP_ALGO_TOOLTIP;Lets you chose between parameters subsets or all parameters TP_COLORAPP_BRIGHT;Brightness (Q) @@ -907,8 +916,8 @@ TP_COLORAPP_DEGREE_TOOLTIP;Amount of CIE Chromatic Adaptation Transform 2002\nIf TP_COLORAPP_EQUAL;Equal TP_COLORAPP_GAMUT;Gamut control (Lab & CIECAM) TP_COLORAPP_GAMUT_TOOLTIP;Allow gamut control in Lab mode -TP_COLORAPP_HUE;Hue (H) -TP_COLORAPP_HUE_TOOLTIP;Hue (H) - angle between 0° and 360° +TP_COLORAPP_HUE;Hue (h) +TP_COLORAPP_HUE_TOOLTIP;Hue (h) - angle between 0° and 360° TP_COLORAPP_LABEL;CIE Color Appearance Model 2002 TP_COLORAPP_LABEL_CAM02;Modifying image with CIECAM TP_COLORAPP_LABEL_SCENE;Scene conditions @@ -917,8 +926,8 @@ TP_COLORAPP_LIGHT;Lightness (J) TP_COLORAPP_LIGHT_TOOLTIP;Lightness in CIECAM02 is different from Lab and RGB TP_COLORAPP_MODEL;White-Point Model TP_COLORAPP_MODEL_TOOLTIP;WB [RT] + [output]:\nRT's WB is used for the scene, CIECAM is set to D50, the output device's white uses the value set in Preferences\n\nWB [RT+CAT02] + [output]:\nRT's WB settings are used by CAT02 and the output device's white uses the value set in Preferences -TP_COLORAPP_RSTPRO;Red & skin tones protection (C) -TP_COLORAPP_RSTPRO_TOOLTIP;Red and skin tones protection by the (C) slider +TP_COLORAPP_RSTPRO;Red & skin tones protection +TP_COLORAPP_RSTPRO_TOOLTIP;Red and skin tones protection (sliders and curves) TP_COLORAPP_SURROUND;Surround TP_COLORAPP_SURROUND_AVER;Average TP_COLORAPP_SURROUND_DARK;Dark @@ -929,6 +938,19 @@ TP_COLORAPP_SURSOURCE;Dark surround TP_COLORAPP_SURSOURCE_TOOLTIP;Can be used if source image has a dark border TP_COLORAPP_WBCAM;WB [RT+CAT02] + [output] TP_COLORAPP_WBRT;WB [RT] + [output] +TP_COLORAPP_CURVEEDITOR1;Tone curve 1 +TP_COLORAPP_CURVEEDITOR2;Tone curve 2 +TP_COLORAPP_CURVEEDITOR3;Chroma curve +TP_COLORAPP_TCMODE_CHROMA;Chroma +TP_COLORAPP_TCMODE_SATUR;Saturation +TP_COLORAPP_TCMODE_COLORF;Colorfullness +TP_COLORAPP_TCMODE_BRIGHTNESS;Brightness +TP_COLORAPP_TCMODE_LIGHTNESS;Lightness +TP_COLORAPP_TCMODE_LABEL1;Curve mode 1 +TP_COLORAPP_TCMODE_LABEL2;Curve mode 2 +TP_COLORAPP_TCMODE_LABEL3;Curve chroma mode +TP_COLORAPP_CURVEEDITOR2_TOOLTIP;Same usage as exposure tone curve +TP_COLORAPP_CURVEEDITOR3_TOOLTIP;You can select between chroma saturation colorfullness TP_CROP_FIXRATIO;Fix ratio: TP_CROP_GTDIAGONALS;Rule of Diagonals TP_CROP_GTEPASSPORT;Biometric Passport diff --git a/rtdata/profiles/BW-1.pp3 b/rtdata/profiles/BW-1.pp3 index 96d721cf8..ffeab7fd0 100644 --- a/rtdata/profiles/BW-1.pp3 +++ b/rtdata/profiles/BW-1.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/BW-2.pp3 b/rtdata/profiles/BW-2.pp3 index 765f106f4..279125605 100644 --- a/rtdata/profiles/BW-2.pp3 +++ b/rtdata/profiles/BW-2.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/BW-3.pp3 b/rtdata/profiles/BW-3.pp3 index f8cb16b67..86eaed06e 100644 --- a/rtdata/profiles/BW-3.pp3 +++ b/rtdata/profiles/BW-3.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/BW-4.pp3 b/rtdata/profiles/BW-4.pp3 index 42c8aefe8..35d552397 100644 --- a/rtdata/profiles/BW-4.pp3 +++ b/rtdata/profiles/BW-4.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/Default-ISO-High.pp3 b/rtdata/profiles/Default-ISO-High.pp3 index d2462794b..0d12bcd76 100644 --- a/rtdata/profiles/Default-ISO-High.pp3 +++ b/rtdata/profiles/Default-ISO-High.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/Default-ISO-Medium.pp3 b/rtdata/profiles/Default-ISO-Medium.pp3 index 694212683..791f37c84 100644 --- a/rtdata/profiles/Default-ISO-Medium.pp3 +++ b/rtdata/profiles/Default-ISO-Medium.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/Default.pp3 b/rtdata/profiles/Default.pp3 index 36ac1bbb9..8c77e006a 100644 --- a/rtdata/profiles/Default.pp3 +++ b/rtdata/profiles/Default.pp3 @@ -106,7 +106,14 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; + [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/Highkey-1.pp3 b/rtdata/profiles/Highkey-1.pp3 index cd8332ccd..172054215 100644 --- a/rtdata/profiles/Highkey-1.pp3 +++ b/rtdata/profiles/Highkey-1.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/Natural-1.pp3 b/rtdata/profiles/Natural-1.pp3 index 08521855a..571a0aa75 100644 --- a/rtdata/profiles/Natural-1.pp3 +++ b/rtdata/profiles/Natural-1.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/Natural-2.pp3 b/rtdata/profiles/Natural-2.pp3 index 866fc0d1c..6af558fd3 100644 --- a/rtdata/profiles/Natural-2.pp3 +++ b/rtdata/profiles/Natural-2.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/Neutral.pp3 b/rtdata/profiles/Neutral.pp3 index 0cf2ad992..a72420069 100644 --- a/rtdata/profiles/Neutral.pp3 +++ b/rtdata/profiles/Neutral.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/Punchy-1.pp3 b/rtdata/profiles/Punchy-1.pp3 index bc051e165..269572028 100644 --- a/rtdata/profiles/Punchy-1.pp3 +++ b/rtdata/profiles/Punchy-1.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtdata/profiles/Punchy-2.pp3 b/rtdata/profiles/Punchy-2.pp3 index 678f4d18a..5dfb270a9 100644 --- a/rtdata/profiles/Punchy-2.pp3 +++ b/rtdata/profiles/Punchy-2.pp3 @@ -106,7 +106,13 @@ H-Hue=0 RSTProtection=0 AdaptScene=2000 SurrSource=false -Gamut=false +Gamut=true +CurveMode=Lightness +CurveMode2=Lightness +CurveMode3=Chroma +Curve=0; +Curve2=0; +Curve3=0; [Impulse Denoising] Enabled=false diff --git a/rtengine/color.cc b/rtengine/color.cc index c071fa87b..4db2bcce8 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -48,7 +48,7 @@ namespace rtengine { const float Color::D50z=0.82521; const double Color::u0=4.0*D50x/(D50x+15+3*D50z); const double Color::v0=9.0/(D50x+15+3*D50z); - const double Color::epskap=8.0; + const double Color::epskap=8.0; /* * Munsell Lch correction * Copyright (c) 2011 Jacques Desmis @@ -201,9 +201,9 @@ namespace rtengine { r = g = b = 65535.0f * l; // achromatic else { double m2; - double h_ = double(h); + double h_ = double(h); double s_ = double(s); - double l_ = double(l); + double l_ = double(l); if (l <= 0.5f) m2 = l_ * (1.0 + s_); @@ -520,33 +520,76 @@ namespace rtengine { Z = (12 - 3*u - 20*v)*Y/(4*v); } + void Color::skinred ( double J, double h, double sres, double Sp, float dred, float protect_red, int sk, float rstprotection, float ko, double &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) - { - if(rstprotection<99.9999) { - if(param > limit) - scale = rstprotection/100.1f; - if((HH< (1.3f+deltaHH) && HH >=1.3f)) - scaleext=HH*(1.0f-scale)/deltaHH + 1.0f - (1.3f+deltaHH)*(1.0f-scale)/deltaHH; //transition for Hue (red - yellow) - else if((HH< 0.15f && HH >(0.15f-deltaHH))) - scaleext=HH*(scale-1.0f)/deltaHH + 1.0f - (0.15f-deltaHH)*(scale-1.0f)/deltaHH; //transition for hue (red purple) - } + { + if(rstprotection<99.9999) { + if(param > limit) + scale = rstprotection/100.1f; + if((HH< (1.3f+deltaHH) && HH >=1.3f)) + scaleext=HH*(1.0f-scale)/deltaHH + 1.0f - (1.3f+deltaHH)*(1.0f-scale)/deltaHH; //transition for Hue (red - yellow) + else if((HH< 0.15f && HH >(0.15f-deltaHH))) + scaleext=HH*(scale-1.0f)/deltaHH + 1.0f - (0.15f-deltaHH)*(scale-1.0f)/deltaHH; //transition for hue (red purple) + } } void Color::transitred (float HH, float Chprov1, float dred, float factorskin, float protect_red, float factorskinext, float deltaHH, float factorsat, float &factor) { - if(HH>=0.15f && HH<1.3f) { - if (Chprov1(0.15f-deltaHH) || HH<(1.3f+deltaHH) ) { - if (Chprov1 < dred) - factor = factorskinext;// C=dred=55 => real max of skin tones - else if (Chprov1 < (dred+protect_red))// transition - factor = (factorsat-factorskinext)/protect_red*Chprov1+factorsat-(dred+protect_red)*(factorsat-factorskinext)/protect_red; - } + if(HH>=0.15f && HH<1.3f) { + if (Chprov1(0.15f-deltaHH) || HH<(1.3f+deltaHH) ) { + if (Chprov1 < dred) + factor = factorskinext;// C=dred=55 => real max of skin tones + else if (Chprov1 < (dred+protect_red))// transition + factor = (factorsat-factorskinext)/protect_red*Chprov1+factorsat-(dred+protect_red)*(factorsat-factorskinext)/protect_red; + } } /* @@ -588,17 +631,17 @@ namespace rtengine { correctL=false; MunsellLch (Lprov1, HH,Chprov1, CC, correctionHue, zo, correctionHueLum, correctL); //munsell chroma correction #ifdef _DEBUG - float absCorrectionHue = fabs(correctionHue); + float absCorrectionHue = fabs(correctionHue); if(correctionHue !=0.0) { - int idx=zo-1; + int idx=zo-1; #pragma omp critical (maxdhue) { - munsDbgInfo->maxdhue[idx] = MAX(munsDbgInfo->maxdhue[idx], absCorrectionHue); +munsDbgInfo->maxdhue[idx] = MAX(munsDbgInfo->maxdhue[idx], absCorrectionHue); } } if(absCorrectionHue > 0.45) #pragma omp atomic - munsDbgInfo->depass++; //verify if no bug in calculation + munsDbgInfo->depass++; //verify if no bug in calculation #endif correctionHuechroma=correctionHue; //preserve if(lumaMuns) { @@ -624,17 +667,17 @@ namespace rtengine { if(contin1==true && contin2==true) correctlum=correctlumprov2-correctlumprov; #ifdef _DEBUG - float absCorrectLum = fabs(correctlum); + float absCorrectLum = fabs(correctlum); if(correctlum !=0.0) { - int idx=zo-1; + int idx=zo-1; #pragma omp critical (maxdhuelum) { - munsDbgInfo->maxdhuelum[idx] = MAX(munsDbgInfo->maxdhuelum[idx],absCorrectLum); + munsDbgInfo->maxdhuelum[idx] = MAX(munsDbgInfo->maxdhuelum[idx],absCorrectLum); } } if(absCorrectLum > 0.35) #pragma omp atomic - munsDbgInfo->depassLum++; //verify if no bug in calculation + munsDbgInfo->depassLum++; //verify if no bug in calculation #endif } } @@ -675,7 +718,7 @@ namespace rtengine { #endif { const float ClipLevel = 65535.0f; - bool inGamut; + bool inGamut; #ifdef _DEBUG neg=false, more_rgb=false; #endif @@ -694,7 +737,7 @@ namespace rtengine { float x_ = 65535.0f * f2xyz(fx)*D50x; // float y_ = 65535.0f * f2xyz(fy); float z_ = 65535.0f * f2xyz(fz)*D50z; - float y_=(Lprov1>epskap) ? 65535.0*fy*fy*fy : 65535.0*Lprov1/kappa; + float y_=(Lprov1>epskap) ? 65535.0*fy*fy*fy : 65535.0*Lprov1/kappa; xyz2rgb(x_,y_,z_,R,G,B,wip); @@ -706,9 +749,9 @@ namespace rtengine { if (Lprov1 < 0.01f) Lprov1 = 0.01f; Chprov1 *= higherCoef; // decrease the chromaticity value if (Chprov1 <= 3.0f) Lprov1 += lowerCoef; - inGamut = false; + inGamut = false; } else - // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut + // if "highlight reconstruction" is enabled or the point is completely white (clipped, no color), don't control Gamut if (!isHLEnabled && (R>ClipLevel || G>ClipLevel || B>ClipLevel)) { #ifdef _DEBUG more_rgb=true; @@ -716,7 +759,7 @@ namespace rtengine { if (Lprov1 > 99.999f) Lprov1 = 99.98f; Chprov1 *= higherCoef; if (Chprov1 <= 3.0f) Lprov1 -= lowerCoef; - inGamut = false; + inGamut = false; } } while (!inGamut); @@ -752,7 +795,7 @@ namespace rtengine { int negat=0, moreRGB=0; MunsellDebugInfo* MunsDebugInfo=NULL; if (corMunsell) - MunsDebugInfo = new MunsellDebugInfo(); + MunsDebugInfo = new MunsellDebugInfo(); #pragma omp parallel default(shared) firstprivate(MunsDebugInfo) reduction(+: negat, moreRGB) if (multiThread) #else @@ -822,11 +865,11 @@ namespace rtengine { #ifdef _DEBUG t2e.set(); if (settings->verbose) { - printf("Color::LabGamutMunsell (correction performed in %d usec):\n", t2e.etime(t1e)); + printf("Color::LabGamutMunsell (correction performed in %d usec):\n", t2e.etime(t1e)); printf(" Gamut : G1negat=%iiter G165535=%iiter \n",negat,moreRGB); if (MunsDebugInfo) { - printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); - printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhuelum[0] ,MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); + printf(" Munsell chrominance: MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhue[0], MunsDebugInfo->maxdhue[1], MunsDebugInfo->maxdhue[2], MunsDebugInfo->maxdhue[3], MunsDebugInfo->depass); + printf(" Munsell luminance : MaxBP=%1.2frad MaxRY=%1.2frad MaxGY=%1.2frad MaxRP=%1.2frad depass=%i\n", MunsDebugInfo->maxdhuelum[0] ,MunsDebugInfo->maxdhuelum[1], MunsDebugInfo->maxdhuelum[2], MunsDebugInfo->maxdhuelum[3], MunsDebugInfo->depassLum); } else { printf(" Munsell correction wasn't requested\n"); diff --git a/rtengine/color.h b/rtengine/color.h index e3834a7cb..b0836f1a2 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -164,6 +164,7 @@ public: // end Munsell 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); //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 27221eeeb..510ba86ab 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -893,15 +893,15 @@ int ColorTemp::XYZtoCorColorTemp(double x0, double y0, double z0, double &temp) return 0; /* success */ } -void ColorTemp::curvecolor(double satind, double satval, double &sres, double parsat){ - if (satind >=0.0) { - sres = (1.-(satind)/100.)*satval+(satind)/100.*(1.-SQR(SQR(1.-min(satval,1.0)))); - if (sres>parsat) sres=parsat; - if (sres<0.) sres=0.; - } else { - if (satind < -0.1) - sres = satval*(1.+(satind)/100.); - } +void ColorTemp::curvecolor(double satind, double satval, double &sres, double parsat) { + if (satind >=0.0) { + sres = (1.-(satind)/100.)*satval+(satind)/100.*(1.-SQR(SQR(1.-min(satval,1.0)))); + if (sres>parsat) sres=parsat; + if (sres<0.) sres=0.; + } else { + if (satind < -0.1) + sres = satval*(1.+(satind)/100.); + } } @@ -1002,374 +1002,6 @@ void ColorTemp::curveJ (double br, double contr, int db, LUTf & outCurve, LUTu & for (int i=0; i<(db*32768); i++) outCurve[i] = db*32768.0*dcurve[i]; } - -// * Copyright (c) October 2012 Jacques Desmis -void ColorTemp::ciecam_02 (LabImage* lab, const ProcParams* params ) -{ -if(params->colorappearance.enabled) { - -#ifdef _DEBUG - MyTime t1e,t2e; - t1e.set(); -#endif - - int width = lab->W, height = lab->H; - double Yw; - Yw=1.0; - double Xw, Zw; - double f,c,nc,yb,la,xw,yw,zw,f2,c2,nc2,yb2,la2; - double z,fl,n,nbb,ncb,d,aw; - double xwd,ywd,zwd; - int alg=0; - LUTf bright_curve (65536,0);//init curve - LUTf bright_curveQ (65536,0);//init curve - - LUTu hist16 (65536); - LUTu hist16Q (65536); - float koef=1.0f;//rough correspondence between L and J - hist16.clear();hist16Q.clear(); - float sum=0.f; - float mean; - 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; - - hist16[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/(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; - - 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) {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 - 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 - //settings mean Luminance Y of output device - 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=double(params->colorappearance.adapscen); - la2=double(params->colorappearance.adaplum); - - // level of adaptation - double deg=(params->colorappearance.degree)/100.0; - double 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; - double rstprotection = 100.-params->colorappearance.rstprotection; - //evaluate lightness, contrast - curveJ (jli, contra, 1, bright_curve, hist16);//lightness and contrast J - curveJ (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; - double 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 - - /* double maxj=-100.0; - double minj= 500.0; - double minc=500.0; - double maxc=-100.0; -*/ - 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,fl,nc,f,c, height,width,doneinit,doneinit2, nc2,f2,c2, alg, gamu, highlight, rstprotection) -#endif -{ - 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; - double x,y,z; - //convert Lab => XYZ - Color::Lab2XYZ(L, a, b, x1, y1, z1); - double J, C, h, Q, M, s, aw, fl, wh; - - x=(double)x1/655.35; - y=(double)y1/655.35; - z=(double)z1/655.35; - //process source==> normal - ColorTemp::xyz2jchqms_ciecam02( J, C, h, - Q, M, s, aw, fl, wh, - x, y, z, - xw1, yw1, zw1, - yb, la, - f, c, nc, pilot, doneinit, gamu ); - - if(alg==0) { - //lightness J + chroma C - J=(bright_curve[(float)(J*327.68)])/327.68;//ligthness CIECAM02 + contrast - double Cp,sres; - Cp=C/100.0; - double parsat=1.8;//parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation : for not) - curvecolor(chr, Cp , sres, parsat); - 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_red,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 of 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.f)*(float)h-7.96f;doskin=true;}//H>-0.15 <-0.04 - else if((float)h>74.f && (float)h<95.f) {HH=(0.3f/21.f)*(float)h+0.24285f;doskin=true;}//H>1.3 H<1.6 - if(doskin){ - float chromapro=sres/Cp; - float dred=55.0f;//Skin max - 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; - - float protect_red=30.f; //==> 90=60+30 transition - 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, C, dred, factorskin, protect_red, factorskinext, deltaHH, factorsat, factor); //transition - C*=factor; - } - else C=100.0*sres; - } - else if(alg==2) { - //Brightness Q Colorfullness M - double coef=32760./wh; - Q=(bright_curveQ[(float)(Q*coef)])/coef;//brightness and contrast - double Mp, sres; - double coe=pow(fl,0.25); - Mp=M/100.0; - double parsat=2.5; - curvecolor(mchr, Mp , sres, parsat); - M=100.0*sres; - J=(100.0* Q*Q) /(wh*wh); - C= M/coe; - } - else if(alg==1) { - // Lightness saturation - J=(bright_curve[(float)(J*327.68)])/327.68;//ligthness CIECAM02 + contrast - double sres; - double Sp=s/100.0; - double parsat=1.5; - curvecolor(schr, Sp , sres, parsat); - s=100.*sres; - double Q1; - Q1= ( 4.0 / c ) * sqrt( J / 100.0 ) * ( aw + 4.0 ) ; - C=(s*s*Q1)/(10000.0); - } - else if(alg==3) { - double coef=32760./wh; - Q=(bright_curveQ[(float)(Q*coef)])/coef;//brightness and contrast - double Mp, sres; - double coe=pow(fl,0.25); - Mp=M/100.0; - double parsat=2.5; - if(mchr==-100.0) mchr=-99.8 ; - if(mchr==100.0) mchr=99.9; - curvecolor(mchr, Mp , sres, parsat);//colorfullness - M=100.0*sres; - J=(100.0* Q*Q) /(wh*wh); - C= M/coe; - s = 100.0 * sqrt( M / Q ); - J=(bright_curve[(float)(J*327.68)])/327.68;//ligthness CIECAM02 + contrast - double Cp; - double Sp=s/100.0; - parsat=1.5; - if(schr==-100.0) schr=-99.; - if(schr==100.0) schr=98.; - curvecolor(schr, Sp , sres, parsat); //saturation - s=100.*sres; - double Q1; - Q1= ( 4.0 / c ) * sqrt( J / 100.0 ) * ( aw + 4.0 ) ; - C=(s*s*Q1)/(10000.0); - Cp=C/100.0; - parsat=1.8;//parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation : for not) - curvecolor(chr, Cp , sres, parsat); //chroma - 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_red,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 of 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.f)*(float)h-7.96f;doskin=true;}//H>-0.15 <-0.04 - else if((float)h>74.f && (float)h<95.f) {HH=(0.3f/21.f)*(float)h+0.24285f;doskin=true;}//H>1.3 H<1.6 - if(doskin){ - float chromapro=sres/Cp; - float dred=55.0f;//Skin max - 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; - - float protect_red=30.f; //==> 90=60+30 transition - 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, C, dred, factorskin, protect_red, factorskinext, deltaHH, factorsat, factor); //transition - C*=factor; - } - else C=100.0*sres; - h=h+hue;if( h < 0.0 ) h += 360.0;//hue - } - /* - if(J>maxj) maxj=J; - if(C>maxc) maxc=C; - if(Jmaxj) maxj=J; - if(C>maxc) maxc=C; - if(J viewing - ColorTemp::jch2xyz_ciecam02( xx, yy, zz, - J, C, h, - xw2, yw2, zw2, - yb2, la2, - f2, c2, nc2, doneinit2, gamu); - x=(float)xx*655.35; - y=(float)yy*655.35; - z=(float)zz*655.35; - 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 - -#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 -} -} - - 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 ) { // CIECAT02 - J.Desmis January 2012 review September 2012 @@ -2040,7 +1672,7 @@ void ColorTemp::xyz2jchqms_ciecam02( double &J, double &C, double &h, double &Q, gc = g * (((yw * d) / gw) + (1.0 - d)); bc = b * (((yw * d) / bw) + (1.0 - d)); - ColorTemp::cat02_to_hpe( rp, gp, bp, rc, gc, bc ); + ColorTemp::cat02_to_hpe( rp, gp, bp, rc, gc, bc, gamu ); if(gamu==1){//gamut correction M.H.Brill S.Susstrunk rp=MAXR(rp,0.0); gp=MAXR(gp,0.0); diff --git a/rtengine/colortemp.h b/rtengine/colortemp.h index f588d1833..5dc5b758e 100644 --- a/rtengine/colortemp.h +++ b/rtengine/colortemp.h @@ -61,7 +61,7 @@ class ColorTemp { int XYZtoCorColorTemp(double x0,double y0 ,double z0, double &temp); static void 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 ); //static void CAT02 (Imagefloat* baseImg, const ProcParams* params); - static void ciecam_02 (LabImage* lab, const ProcParams* params); + //static void ciecam_02 (LabImage* lab, const ProcParams* params); static double d_factor( double f, double la ) { return f * (1.0 - ((1.0 / 3.6) * exp((-la - 42.0) / 92.0))); @@ -90,7 +90,7 @@ class ColorTemp { gc = g * (((y * d) / g) + (1.0 - d)); bc = b * (((y * d) / b) + (1.0 - d)); - cat02_to_hpe( rp, gp, bp, rc, gc, bc ); + cat02_to_hpe( rp, gp, bp, rc, gc, bc, gamu ); if(gamu==1){//gamut correction M.H.Brill S.Susstrunk rp=MAXR(rp,0.0); gp=MAXR(gp,0.0); @@ -105,7 +105,7 @@ class ColorTemp { } 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 ); + 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 ); @@ -253,11 +253,13 @@ if(gamu==0){ 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); + //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); - - + } } @@ -269,9 +271,13 @@ if(gamu==0) { 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); + //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); + } } @@ -280,16 +286,24 @@ inline void ColorTemp::hpe_to_xyz( double &x, double &y, double &z, double r, do 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 ) -{ + + + +inline void ColorTemp::cat02_to_hpe( double &rh, double &gh, double &bh, double r, double g, double b, int gamu ) +{ 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 4c42146c5..17e1a62d8 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -153,6 +153,71 @@ namespace rtengine { } } +void CurveFactory::curveLightBrightColor ( + ColorAppearanceParams::eTCModeId curveMode1, const std::vector& curvePoints1, + ColorAppearanceParams::eTCModeId curveMode2, const std::vector& curvePoints2, + ColorAppearanceParams::eCTCModeId curveMode3, const std::vector& curvePoints3, + + ColorAppearance & customColCurve1, + ColorAppearance & customColCurve2, + ColorAppearance & customColCurve3, + + int skip) +{ + + DiagonalCurve* tcurve = NULL; + customColCurve3.Reset(); + + if (!curvePoints3.empty() && curvePoints3[0]>DCT_Linear && curvePoints3[0]isIdentity()) { + delete tcurve; + tcurve = NULL; + } + else + customColCurve3.Set(tcurve); + delete tcurve; + tcurve = NULL; + } + + customColCurve2.Reset(); + + if (!curvePoints2.empty() && curvePoints2[0]>DCT_Linear && curvePoints2[0]isIdentity()) { + delete tcurve; + tcurve = NULL; + } + else + customColCurve2.Set(tcurve); + delete tcurve; + tcurve = NULL; + } + // create first curve if needed + customColCurve1.Reset(); + + if (!curvePoints1.empty() && curvePoints1[0]>DCT_Linear && curvePoints1[0]isIdentity()) { + delete tcurve; + tcurve = NULL; + } + else { + customColCurve1.Set(tcurve); + delete tcurve; + tcurve = NULL; + } + } + if (tcurve) delete tcurve; + +} + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void CurveFactory::complexsgnCurve ( bool & autili, bool & butili, bool & ccutili, bool & cclutili, double saturation, double rstprotection, const std::vector& acurvePoints, const std::vector& bcurvePoints,const std::vector& cccurvePoints, @@ -769,8 +834,17 @@ namespace rtengine { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - + +void ColorAppearance::Reset() { + lutColCurve.reset(); +} + +// Fill a LUT with X/Y, ranged 0xffff +void ColorAppearance::Set(Curve *pCurve) { + lutColCurve(65536); + for (int i=0; i<65536; i++) lutColCurve[i] = pCurve->getVal(double(i)/65535.) * 65535.; +} + void ToneCurve::Reset() { lutToneCurve.reset(); } @@ -778,7 +852,7 @@ void ToneCurve::Reset() { // Fill a LUT with X/Y, ranged 0xffff void ToneCurve::Set(Curve *pCurve) { lutToneCurve(65536); - for (int i=0;i<65536;i++) lutToneCurve[i] = pCurve->getVal(i/(double)65535) * 65535; + for (int i=0; i<65536; i++) lutToneCurve[i] = pCurve->getVal(double(i)/65535.) * 65535.; } } diff --git a/rtengine/curves.h b/rtengine/curves.h index 00019985e..91a1eb164 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -40,6 +40,7 @@ using namespace std; namespace rtengine { class ToneCurve; + class ColorAppearance; class CurveFactory { @@ -184,6 +185,14 @@ class CurveFactory { const std::vector& bcurvePoints,const std::vector& cccurvePoints,const std::vector& cclurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, int skip=1); static void complexLCurve (double br, double contr, const std::vector& curvePoints, LUTu & histogram, LUTu & histogramCropped, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili); + static void curveLightBrightColor ( + ColorAppearanceParams::eTCModeId curveMode, const std::vector& curvePoints, + ColorAppearanceParams::eTCModeId curveMode2, const std::vector& curvePoints2, + ColorAppearanceParams::eCTCModeId curveMode3, const std::vector& curvePoints3, + ColorAppearance & outColCurve1, + ColorAppearance & outColCurve2, + ColorAppearance & outColCurve3, + int skip=1); static void RGBCurve (const std::vector& curvePoints, LUTf & outCurve, int skip); }; @@ -283,6 +292,82 @@ class ToneCurve { operator bool (void) const { return lutToneCurve; } }; +class ColorAppearance { + public: + LUTf lutColCurve; // 0xffff range + + virtual ~ColorAppearance() {}; + + void Reset(); + void Set(Curve *pCurve); + operator bool (void) const { return lutColCurve; } +}; + +class Lightcurve : public ColorAppearance { + public: + void Apply(float& Li) const; +}; + +//lightness curve +inline void Lightcurve::Apply (float& Li) const { + + assert (lutColCurve); + + Li = lutColCurve[Li]; +} + +class Brightcurve : public ColorAppearance { + public: + void Apply(float& Br) const; +}; + +//brightness curve +inline void Brightcurve::Apply (float& Br) const { + + assert (lutColCurve); + + Br = lutColCurve[Br]; +} + +class Chromacurve : public ColorAppearance { + public: + void Apply(float& Cr) const; +}; + +//Chroma curve +inline void Chromacurve::Apply (float& Cr) const { + + assert (lutColCurve); + + Cr = lutColCurve[Cr]; +} +class Saturcurve : public ColorAppearance { + public: + void Apply(float& Sa) const; +}; + +//Saturation curve +inline void Saturcurve::Apply (float& Sa) const { + + assert (lutColCurve); + + Sa = lutColCurve[Sa]; +} + +class Colorfcurve : public ColorAppearance { + public: + void Apply(float& Cf) const; +}; + +//Colorfullness curve +inline void Colorfcurve::Apply (float& Cf) const { + + assert (lutColCurve); + + Cf = lutColCurve[Cf]; +} + + class StandardToneCurve : public ToneCurve { public: void Apply(float& r, float& g, float& b) const; @@ -324,9 +409,8 @@ inline void StandardToneCurve::Apply (float& r, float& g, float& b) const { // inlined to make sure there will be no cache flush when used inline void AdobeToneCurve::Apply (float& r, float& g, float& b) const { -#ifdef _DEBUG assert (lutToneCurve); -#endif + if (r >= g) { if (g > b) RGBTone (r, g, b); // Case 1: r >= g > b else if (b > r) RGBTone (b, r, g); // Case 2: b > r >= g diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 980c612e5..a0074761b 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -201,7 +201,20 @@ void Crop::update (int todo) { parent->ipf.dirpyrequalizer (labnCrop); } } - ColorTemp::ciecam_02 (labnCrop, ¶ms); + ColorAppearance customColCurve1; + ColorAppearance customColCurve2; + ColorAppearance customColCurve3; + + CurveFactory::curveLightBrightColor ( + params.colorappearance.curveMode, params.colorappearance.curve, + params.colorappearance.curveMode2, params.colorappearance.curve2, + params.colorappearance.curveMode3, params.colorappearance.curve3, + customColCurve1, + customColCurve2, + customColCurve3, + 1); + + parent->ipf.ciecam_02 (labnCrop, ¶ms,customColCurve1,customColCurve2,customColCurve3); // switch back to rgb parent->ipf.lab2monitorRgb (labnCrop, cropImg); diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 383aefcf5..0eb162a02 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -344,7 +344,6 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { ipf.chromiLuminanceCurve (nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve,lhskcurve, lumacurve, utili, autili, butili, ccutili,cclutili); //ipf.colorCurve (nprevl, nprevl); ipf.vibrance(nprevl); - // ColorTemp::ciecam_02 (nprevl, ¶ms); readyphase++; if (scale==1) { @@ -384,7 +383,16 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { readyphase++; } } - ColorTemp::ciecam_02 (nprevl, ¶ms); + CurveFactory::curveLightBrightColor ( + params.colorappearance.curveMode, params.colorappearance.curve, + params.colorappearance.curveMode2, params.colorappearance.curve2, + params.colorappearance.curveMode3, params.colorappearance.curve3, + customColCurve1, + customColCurve2, + customColCurve3, + scale==1 ? 1 : 1); + + ipf.ciecam_02 (nprevl, ¶ms, customColCurve1,customColCurve2,customColCurve3); // process crop, if needed for (size_t i=0; icolorappearance.enabled) { + +#ifdef _DEBUG + MyTime t1e,t2e; + t1e.set(); +#endif + + int width = lab->W, height = lab->H; + double Yw; + Yw=1.0; + double Xw, Zw; + double f,c,nc,yb,la,xw,yw,zw,f2,c2,nc2,yb2,la2; + double z,fl,n,nbb,ncb,d,aw; + double xwd,ywd,zwd; + int alg=0; + float sum=0.f; + float mean; + + LUTf bright_curve (65536,0);//init curve + LUTf bright_curveQ (65536,0);//init curve + + LUTu hist16 (65536); + LUTu hist16Q (65536); + float koef=1.0f;//rough correspondence between L and J + hist16.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; + + hist16[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/(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; + + + 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=double(params->colorappearance.adapscen); + la2=double(params->colorappearance.adaplum); + + // level of adaptation + double deg=(params->colorappearance.degree)/100.0; + double 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; + double 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::curveJ (jli, contra, 1, bright_curve, hist16);//lightness and contrast J + ColorTemp::curveJ (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; + double 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,fl,nc,f,c, height,width,doneinit,doneinit2, nc2,f2,c2, alg, gamu, highlight, rstprotection) +#endif +{ + 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; + double x,y,z; + //convert Lab => XYZ + Color::Lab2XYZ(L, a, b, x1, y1, z1); + double J, C, h, Q, M, s, aw, fl, wh; + double Jp,Cpr; + double 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=(double)x1/655.35; + y=(double)y1/655.35; + z=(double)z1/655.35; + //process source==> normal + ColorTemp::xyz2jchqms_ciecam02( 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; + // we cannot have all algoritms with all chroma curves + if(alg==1) { + // Lightness saturation + Jpro=(bright_curve[(float)(Jpro*327.68)])/327.68;//ligthness CIECAM02 + contrast + double sres; + double Sp=spro/100.0; + double parsat=1.5; + parsat=1.5;//parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation) + if(schr==-100.0) schr=-99.8; + ColorTemp::curvecolor(schr, Sp , sres, parsat); + double coe=pow(fl,0.25); + 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=100.f; + Color::skinred(Jpro, hpro, sres, Sp, dred, protect_red,sk,rstprotection,ko, spro); + Qpro= ( 4.0 / c ) * sqrt( Jpro / 100.0 ) * ( aw + 4.0 ) ; + Cpro=(spro*spro*Qpro)/(10000.0); + } + else if(alg==3 || alg==0 || alg==2) { + double coef=32760./wh; + if(alg==3 || alg==2) Qpro=(bright_curveQ[(float)(Qpro*coef)])/coef;//brightness and contrast + double Mp, sres; + double coe=pow(fl,0.25); + Mp=Mpro/100.0; + double parsat=2.5; + if(mchr==-100.0) mchr=-99.8 ; + if(mchr==100.0) mchr=99.9; + ColorTemp::curvecolor(mchr, 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::skinred(Jpro, hpro, sres, Mp, dred, protect_red,sk,rstprotection,ko, Mpro); + Jpro=(100.0* Qpro*Qpro) /(wh*wh); + Cpro= Mpro/coe; + spro = 100.0 * sqrt( Mpro / Qpro ); + if(alg!=2) Jpro=(bright_curve[(float)(Jpro*327.68)])/327.68;//ligthness CIECAM02 + contrast + double Cp; + double Sp=spro/100.0; + parsat=1.5; + if(schr==-100.0) schr=-99.; + if(schr==100.0) schr=98.; + ColorTemp::curvecolor(schr, 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.0 * sqrt((protect_red*coe)/Q); + sk=0; + Color::skinred(Jpro, hpro, sres, Sp, dred, protect_red,sk,rstprotection,ko, spro); + //double Q1; + Qpro= ( 4.0 / c ) * sqrt( Jpro / 100.0 ) * ( aw + 4.0 ) ; + Cpro=(spro*spro*Qpro)/(10000.0); + Cp=Cpro/100.0; + parsat=1.8;//parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation : for not) + if(chr==-100.0) chr=-99.8; + ColorTemp::curvecolor(chr, Cp , sres, parsat); //chroma + dred=55.f; + protect_red=30.0f; + sk=1; + Color::skinred(Jpro, hpro, sres, Cp, dred, protect_red,sk,rstprotection, ko, Cpro); + + hpro=hpro+hue;if( hpro < 0.0 ) hpro += 360.0;//hue + } + + if (hasColCurve1) {//curve 1 with Lightness and Brightness + if (curveMode==ColorAppearanceParams::TC_MODE_LIGHT){ + float Jj=(float) Jpro*327.68; + float Jold=Jj; + const Lightcurve& userColCurve = static_cast(customColCurve1); + userColCurve.Apply(Jj); + Jj=0.7f*(Jj-Jold)+Jold;//divide sensibility + Jpro=(double)(Jj/327.68f); + t1L=true; + } + else if (curveMode==ColorAppearanceParams::TC_MODE_BRIGHT){ + double coef=32760./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=(double)(Qq/coef); + Jpro=(100.0* 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.68; + float Jold=Jj; + const Lightcurve& userColCurve = static_cast(customColCurve2); + userColCurve.Apply(Jj); + Jj=0.7f*(Jj-Jold)+Jold;//divide sensibility + Jpro=(double)(Jj/327.68f); + t2L=true; + } + else if (curveMode2==ColorAppearanceParams::TC_MODE_BRIGHT){ // + double coef=32760./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=(double)(Qq/coef); + Jpro=(100.0* Qpro*Qpro) /(wh*wh); + t2B=true; + } + } + + if (hasColCurve3) {//curve 3 with chroma saturation colorfullness + if (curveMode3==ColorAppearanceParams::TC_MODE_CHROMA){ + double parsat=1.; + double coef=327.68/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::skinred(Jpro, hpro, Cc, Ccold, dred, protect_red,sk,rstprotection,ko, Cpro); + c1C=1; + } + else if (curveMode3==ColorAppearanceParams::TC_MODE_SATUR){ // + double parsat=0.8; + double coef=327.68/parsat; + float Ss=(float) spro*coef; + float Sold=Ss; + const Saturcurve& userColCurve = static_cast(customColCurve3); + userColCurve.Apply(Ss); + Ss=0.7f*(Ss-Sold)+Sold;//divide sensibility saturation + double coe=pow(fl,0.25); + 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::skinred(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.0); + c1s=1; + + } + else if (curveMode3==ColorAppearanceParams::TC_MODE_COLORF){ // + double parsat=1.; + double coef=327.68/parsat; + float Mm=(float) Mpro*coef; + float Mold=Mm; + const Colorfcurve& userColCurve = static_cast(customColCurve3); + userColCurve.Apply(Mm); + double coe=pow(fl,0.25); + 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::skinred(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.0 / c ) * sqrt( Jpro / 100.0 ) * ( aw + 4.0 ) ;//for saturation curve + Cpro=(spro*spro*Qpro)/(10000.0); + } + if(c1co==1) { double coe=pow(fl,0.25);Cpro= Mpro/coe;} // for colorfullness curve + //retrieve values C,J...s + C=Cpro; + J=Jpro; + Q=Qpro; + M=Mpro; + h=hpro; + s=spro; + double xx,yy,zz; + //process normal==> viewing + ColorTemp::jch2xyz_ciecam02( xx, yy, zz, + J, C, h, + xw2, yw2, zw2, + yb2, la2, + f2, c2, nc2, doneinit2, gamu); + x=(float)xx*655.35; + y=(float)yy*655.35; + z=(float)zz*655.35; + 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 + +#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 +} +} + + + + + + + void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const ToneCurve & customToneCurve1,const ToneCurve & customToneCurve2 ) { @@ -800,8 +1233,8 @@ void ImProcFunctions::chromiLuminanceCurve (LabImage* lold, LabImage* lnew, LUTf bool LCredsk = params->labCurve.lcredsk; bool ccut = ccutili; double rstprotection = 100.-params->labCurve.rstprotection; // Red and Skin Tones Protection - // avoid color shift is disabled when bwToning is activated - bool avoidColorShift = params->labCurve.avoidcolorshift && !bwToning; + // avoid color shift is disabled when bwToning is activated and enabled if gamut is true in colorappearanace + bool avoidColorShift = (params->labCurve.avoidcolorshift && !bwToning) || params->colorappearance.gamut; int protectRed = settings->protectred; double protectRedH = settings->protectredh; bool gamutLch = settings->gamutLch; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 2ef9a70ff..16849857b 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -92,6 +92,8 @@ 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 (LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3); + void chromiLuminanceCurve (LabImage* lold, LabImage* lnew, LUTf &acurve, LUTf &bcurve, LUTf & satcurve,LUTf & satclcurve, LUTf &curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili); void vibrance (LabImage* lab);//Jacques' vibrance diff --git a/rtengine/procevents.h b/rtengine/procevents.h index d6020cf58..78f68aa91 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -214,8 +214,14 @@ enum ProcEvent { EvCATSChroma=189, EvCATMChroma=190, EvCAThue=191, + EvCATCurve1=192, + EvCATCurve2=193, + EvCATCurveMode1=194, + EvCATCurveMode2=195, + EvCATCurve3=196, + EvCATCurveMode3=197, - NUMOFEVENTS=192 + NUMOFEVENTS=198 }; } #endif diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index f27225a9e..3968c8b77 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -215,7 +215,6 @@ void ProcParams::setDefaults () { colorappearance.degree = 90; colorappearance.autodegree = true; colorappearance.surround = "Average"; -// colorappearance.backgrd = 20; colorappearance.adaplum = 16; colorappearance.adapscen = 2000.0; colorappearance.algo = "JC"; @@ -230,7 +229,16 @@ void ProcParams::setDefaults () { colorappearance.qcontrast = 0.0; colorappearance.colorh = 0.0; colorappearance.surrsource = false; - colorappearance.gamut = false; + colorappearance.gamut = true; + colorappearance.curve.clear (); + colorappearance.curve.push_back(DCT_Linear); + colorappearance.curve2.clear (); + colorappearance.curve2.push_back(DCT_Linear); + colorappearance.curveMode =ColorAppearanceParams::TC_MODE_LIGHT; + colorappearance.curveMode2 = ColorAppearanceParams::TC_MODE_LIGHT; + colorappearance.curve3.clear (); + colorappearance.curve3.push_back(DCT_Linear); + colorappearance.curveMode3 = ColorAppearanceParams::TC_MODE_CHROMA; impulseDenoise.enabled = false; impulseDenoise.thresh = 50; @@ -583,7 +591,62 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, ParamsEdited* p if (!pedited || pedited->colorappearance.adapscen) keyFile.set_double ("Color appearance", "AdaptScene", colorappearance.adapscen); if (!pedited || pedited->colorappearance.surrsource) keyFile.set_boolean ("Color appearance", "SurrSource", colorappearance.surrsource); if (!pedited || pedited->colorappearance.gamut) keyFile.set_boolean ("Color appearance", "Gamut", colorappearance.gamut); + if (!pedited || pedited->colorappearance.curveMode) { + Glib::ustring method; + switch (colorappearance.curveMode) { + case (ColorAppearanceParams::TC_MODE_LIGHT): + method = "Lightness"; + break; + case (ColorAppearanceParams::TC_MODE_BRIGHT): + method = "Brightness"; + break; + } + keyFile.set_string ("Color appearance", "CurveMode", method); + } + if (!pedited || pedited->colorappearance.curveMode2) { + Glib::ustring method; + switch (colorappearance.curveMode2) { + case (ColorAppearanceParams::TC_MODE_LIGHT): + method = "Lightness"; + break; + case (ColorAppearanceParams::TC_MODE_BRIGHT): + method = "Brightness"; + break; + } + keyFile.set_string ("Color appearance", "CurveMode2", method); + } + if (!pedited || pedited->colorappearance.curveMode3) { + Glib::ustring method; + switch (colorappearance.curveMode3) { + case (ColorAppearanceParams::TC_MODE_CHROMA): + method = "Chroma"; + break; + case (ColorAppearanceParams::TC_MODE_SATUR): + method = "Saturation"; + break; + case (ColorAppearanceParams::TC_MODE_COLORF): + method = "Colorfullness"; + break; + + } + keyFile.set_string ("Color appearance", "CurveMode3", method); + } + + if (!pedited || pedited->colorappearance.curve) { + Glib::ArrayHandle tcurve = colorappearance.curve; + keyFile.set_double_list("Color appearance", "Curve", tcurve); + } + if (!pedited || pedited->colorappearance.curve2) { + Glib::ArrayHandle tcurve = colorappearance.curve2; + keyFile.set_double_list("Color appearance", "Curve2", tcurve); + } + if (!pedited || pedited->colorappearance.curve3) { + Glib::ArrayHandle tcurve = colorappearance.curve3; + keyFile.set_double_list("Color appearance", "Curve3", tcurve); + } + + // save impulseDenoise if (!pedited || pedited->impulseDenoise.enabled) keyFile.set_boolean ("Impulse Denoising", "Enabled", impulseDenoise.enabled); if (!pedited || pedited->impulseDenoise.thresh) keyFile.set_integer ("Impulse Denoising", "Threshold", impulseDenoise.thresh); @@ -1045,7 +1108,34 @@ if (keyFile.has_group ("Color appearance")) { if (keyFile.has_key ("Color appearance", "AdaptScene")) {colorappearance.adapscen = keyFile.get_double ("Color appearance", "AdaptScene"); if (pedited) pedited->colorappearance.adapscen = true; } if (keyFile.has_key ("Color appearance", "SurrSource")) {colorappearance.surrsource = keyFile.get_boolean ("Color appearance", "SurrSource"); if (pedited) pedited->colorappearance.surrsource = true; } 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", "CurveMode")) { + Glib::ustring sMode = keyFile.get_string ("Color appearance", "CurveMode"); + if (sMode == "Lightness") colorappearance.curveMode = ColorAppearanceParams::TC_MODE_LIGHT; + else if (sMode == "Brightness") colorappearance.curveMode = ColorAppearanceParams::TC_MODE_BRIGHT; + if (pedited) pedited->colorappearance.curveMode = true; + } + if (keyFile.has_key ("Color appearance", "CurveMode2")) { + Glib::ustring sMode = keyFile.get_string ("Color appearance", "CurveMode2"); + if (sMode == "Lightness") colorappearance.curveMode2 = ColorAppearanceParams::TC_MODE_LIGHT; + else if (sMode == "Brightness") colorappearance.curveMode2 = ColorAppearanceParams::TC_MODE_BRIGHT; + if (pedited) pedited->colorappearance.curveMode2 = true; + } + if (keyFile.has_key ("Color appearance", "CurveMode3")) { + Glib::ustring sMode = keyFile.get_string ("Color appearance", "CurveMode3"); + if (sMode == "Chroma") colorappearance.curveMode3 = ColorAppearanceParams::TC_MODE_CHROMA; + else if (sMode == "Saturation") colorappearance.curveMode3 = ColorAppearanceParams::TC_MODE_SATUR; + else if (sMode == "Colorfullness") colorappearance.curveMode3 = ColorAppearanceParams::TC_MODE_COLORF; + + if (pedited) pedited->colorappearance.curveMode3 = true; + } + + if (ppVersion>200) { + if (keyFile.has_key ("Color appearance", "Curve")) { colorappearance.curve = keyFile.get_double_list ("Color appearance", "Curve"); if (pedited) pedited->colorappearance.curve = true; } + if (keyFile.has_key ("Color appearance", "Curve2")) { colorappearance.curve2 = keyFile.get_double_list ("Color appearance", "Curve2"); if (pedited) pedited->colorappearance.curve2 = true; } + if (keyFile.has_key ("Color appearance", "Curve3")) { colorappearance.curve3 = keyFile.get_double_list ("Color appearance", "Curve3"); if (pedited) pedited->colorappearance.curve3 = true; } + } + + } // load impulseDenoise if (keyFile.has_group ("Impulse Denoising")) { @@ -1415,7 +1505,9 @@ bool ProcParams::operator== (const ProcParams& other) { && colorappearance.adaplum == other.colorappearance.adaplum && colorappearance.wbmodel == other.colorappearance.wbmodel && colorappearance.algo == other.colorappearance.algo - + && colorappearance.curveMode == other.colorappearance.curveMode + && colorappearance.curveMode2 == other.colorappearance.curveMode2 + && colorappearance.curveMode3 == other.colorappearance.curveMode3 && colorappearance.jlight == other.colorappearance.jlight && colorappearance.qbright == other.colorappearance.qbright && colorappearance.chroma == other.colorappearance.chroma diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 97a8ec8b8..2f2567c30 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -348,19 +348,37 @@ class WBParams { /** * Parameters of colorappearance */ - class ColorappearanceParams { + class ColorAppearanceParams { public: + enum eTCModeId { + TC_MODE_LIGHT, // Lightness mode + TC_MODE_BRIGHT, // Brightness mode + }; + + enum eCTCModeId { + TC_MODE_CHROMA, // chroma mode + TC_MODE_SATUR, // saturation mode + TC_MODE_COLORF, // colorfullness mode + }; + bool enabled; int degree; bool autodegree; + std::vector curve; + std::vector curve2; + std::vector curve3; + eTCModeId curveMode; + eTCModeId curveMode2; + eCTCModeId curveMode3; + Glib::ustring surround; - double adapscen; - double adaplum; + double adapscen; + double adaplum; Glib::ustring wbmodel; Glib::ustring algo; - double contrast; - double qcontrast; + double contrast; + double qcontrast; double jlight; double qbright; double chroma; @@ -368,8 +386,8 @@ class WBParams { double mchroma; double colorh; double rstprotection; - bool surrsource; - bool gamut; + bool surrsource; + bool gamut; }; /** @@ -717,7 +735,7 @@ class ProcParams { VibranceParams vibrance; ///< Vibrance parameters //ColorBoostParams colorBoost; ///< Color boost parameters WBParams wb; ///< White balance parameters - ColorappearanceParams colorappearance; + ColorAppearanceParams colorappearance; //ColorShiftParams colorShift; ///< Color shift parameters //LumaDenoiseParams lumaDenoise; ///< Luminance denoising parameters //ColorDenoiseParams colorDenoise; ///< Color denoising parameters diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index bea100473..0e996e389 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -211,7 +211,13 @@ LUMINANCECURVE, // EvCATQbright LUMINANCECURVE, // EvCATQContrast LUMINANCECURVE, // EvCATSChroma LUMINANCECURVE, // EvCATMchroma -LUMINANCECURVE // EvCAThue +LUMINANCECURVE, // EvCAThue +LUMINANCECURVE, // EvCATcurve1 +LUMINANCECURVE, // EvCATcurve2 +LUMINANCECURVE, // EvCATcurvemode1 +LUMINANCECURVE, // EvCATcurvemode2 +LUMINANCECURVE, // EvCATcurve3 +LUMINANCECURVE // EvCATcurvemode3 }; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index f7e9d2475..16dedef75 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -744,6 +744,9 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei LUTu dummy; ToneCurve customToneCurve1, customToneCurve2; + ColorAppearance customColCurve1; + ColorAppearance customColCurve2; + ColorAppearance customColCurve3; ipf.g = gamma; ipf.iGamma = true; @@ -784,7 +787,17 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei //ipf.luminanceCurve (labView, labView, curve); ipf.chromiLuminanceCurve (labView, labView, curve1, curve2, satcurve,lhskcurve, curve, utili, autili, butili, ccutili,cclutili); ipf.vibrance(labView); - ColorTemp::ciecam_02 (labView, ¶ms); + CurveFactory::curveLightBrightColor ( + params.colorappearance.curveMode, params.colorappearance.curve, + params.colorappearance.curveMode2, params.colorappearance.curve2, + params.colorappearance.curveMode3, params.colorappearance.curve3, + + customColCurve1, + customColCurve2, + customColCurve3, + 16); + + ipf.ciecam_02 (labView, ¶ms,customColCurve1,customColCurve2,customColCurve3); // color processing //ipf.colorCurve (labView, labView); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index f86ddc49a..dc19077be 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -170,6 +170,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p LUTu dummy; ToneCurve customToneCurve1, customToneCurve2; + ColorAppearance customColCurve1, customColCurve2,customColCurve3 ; ipf.g = imgsrc->getGamma(); ipf.iGamma = true; @@ -219,7 +220,6 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p //ipf.luminanceCurve (labView, labView, curve); ipf.chromiLuminanceCurve (labView, labView, curve1, curve2, satcurve,lhskcurve,curve, utili, autili, butili, ccutili,cclutili); ipf.vibrance(labView); -// ColorTemp::ciecam_02 (labView, ¶ms); ipf.impulsedenoise (labView); ipf.defringe (labView); @@ -243,7 +243,17 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // directional pyramid equalizer ipf.dirpyrequalizer (labView);//TODO: this is the luminance tonecurve, not the RGB one - ColorTemp::ciecam_02 (labView, ¶ms); + + CurveFactory::curveLightBrightColor ( + params.colorappearance.curveMode, params.colorappearance.curve, + params.colorappearance.curveMode2, params.colorappearance.curve2, + params.colorappearance.curveMode3, params.colorappearance.curve3, + customColCurve1, + customColCurve2, + customColCurve3, + 1); + + ipf.ciecam_02 (labView, ¶ms,customColCurve1,customColCurve2,customColCurve2); // end tile processing...??? //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index 4158a1e1e..608c21724 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -1,4 +1,3 @@ -/* /* * This file is part of RawTherapee. * @@ -21,11 +20,16 @@ #include #include #include "guiutils.h" +#include "../rtengine/color.h" using namespace rtengine; using namespace rtengine::procparams; -Colorappearance::Colorappearance () : Gtk::VBox(), FoldableToolPanel(this) { +ColorAppearance::ColorAppearance () : Gtk::VBox(), FoldableToolPanel(this) { + CurveListener::setMulti(true); + std::vector milestones; + milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); + milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); set_border_width(4); @@ -135,11 +139,6 @@ Colorappearance::Colorappearance () : Gtk::VBox(), FoldableToolPanel(this) { chroma->set_tooltip_markup (M("TP_COLORAPP_CHROMA_TOOLTIP")); p2VBox->pack_start (*chroma); - rstprotection = Gtk::manage ( new Adjuster (M("TP_COLORAPP_RSTPRO"), 0., 100., 0.1, 0.) ); - if (rstprotection->delay < 1000) rstprotection->delay = 1000; - rstprotection->throwOnButtonRelease(); - rstprotection->set_tooltip_markup (M("TP_COLORAPP_RSTPRO_TOOLTIP")); - p2VBox->pack_start (*rstprotection); schroma = Gtk::manage (new Adjuster (M("TP_COLORAPP_CHROMA_S"), -100.0, 100.0, 0.1, 0.)); if (schroma->delay < 1000) schroma->delay = 1000; @@ -152,6 +151,12 @@ Colorappearance::Colorappearance () : Gtk::VBox(), FoldableToolPanel(this) { mchroma->throwOnButtonRelease(); mchroma->set_tooltip_markup (M("TP_COLORAPP_CHROMA_M_TOOLTIP")); p2VBox->pack_start (*mchroma); + + rstprotection = Gtk::manage ( new Adjuster (M("TP_COLORAPP_RSTPRO"), 0., 100., 0.1, 0.) ); + if (rstprotection->delay < 1000) rstprotection->delay = 1000; + rstprotection->throwOnButtonRelease(); + rstprotection->set_tooltip_markup (M("TP_COLORAPP_RSTPRO_TOOLTIP")); + p2VBox->pack_start (*rstprotection); contrast = Gtk::manage (new Adjuster (M("TP_COLORAPP_CONTRAST"), -100.0, 100.0, 0.1, 0.)); if (contrast->delay < 1000) contrast->delay = 1000; @@ -171,6 +176,92 @@ Colorappearance::Colorappearance () : Gtk::VBox(), FoldableToolPanel(this) { colorh->set_tooltip_markup (M("TP_COLORAPP_HUE_TOOLTIP")); p2VBox->pack_start (*colorh); + p2VBox->pack_start (*Gtk::manage (new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET, 4); + + toneCurveMode = Gtk::manage (new MyComboBoxText ()); + toneCurveMode->append_text (M("TP_COLORAPP_TCMODE_LIGHTNESS")); + toneCurveMode->append_text (M("TP_COLORAPP_TCMODE_BRIGHTNESS")); + toneCurveMode->set_active (0); + toneCurveMode->set_tooltip_text(M("TP_COLORAPP_TCMODE_LABEL1")); + + curveEditorG = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_COLORAPP_CURVEEDITOR1")); + curveEditorG->setCurveListener (this); + + shape = static_cast(curveEditorG->addCurve(CT_Diagonal, "", toneCurveMode)); + + + + tcmodeconn = toneCurveMode->signal_changed().connect( sigc::mem_fun(*this, &ColorAppearance::curveMode1Changed), true ); + + toneCurveMode2 = Gtk::manage (new MyComboBoxText ()); + toneCurveMode2->append_text (M("TP_COLORAPP_TCMODE_LIGHTNESS")); + toneCurveMode2->append_text (M("TP_COLORAPP_TCMODE_BRIGHTNESS")); + toneCurveMode2->set_active (0); + toneCurveMode2->set_tooltip_text(M("TP_COLORAPP_TCMODE_LABEL2")); + + curveEditorG2 = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_COLORAPP_CURVEEDITOR2")); + curveEditorG2->setCurveListener (this); + + shape2 = static_cast(curveEditorG2->addCurve(CT_Diagonal, "", toneCurveMode2)); + + tcmode2conn = toneCurveMode2->signal_changed().connect( sigc::mem_fun(*this, &ColorAppearance::curveMode2Changed), true ); + + toneCurveMode3 = Gtk::manage (new MyComboBoxText ()); + toneCurveMode3->append_text (M("TP_COLORAPP_TCMODE_CHROMA")); + toneCurveMode3->append_text (M("TP_COLORAPP_TCMODE_SATUR")); + toneCurveMode3->append_text (M("TP_COLORAPP_TCMODE_COLORF")); + toneCurveMode3->set_active (0); + toneCurveMode3->set_tooltip_text(M("TP_COLORAPP_TCMODE_LABEL3")); + + curveEditorG3 = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_COLORAPP_CURVEEDITOR3")); + curveEditorG3->setCurveListener (this); + + shape3 = static_cast(curveEditorG3->addCurve(CT_Diagonal, "", toneCurveMode3)); + shape3->setRangeLabels( + M("TP_LABCURVE_CURVEEDITOR_CC_RANGE1"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE2"), + M("TP_LABCURVE_CURVEEDITOR_CC_RANGE3"), M("TP_LABCURVE_CURVEEDITOR_CC_RANGE4") + ); + shape3->setBottomBarColorProvider(this, 1); + shape3->setLeftBarColorProvider(this, 1); + shape3->setRangeDefaultMilestones(0.05, 0.2, 0.58); + + +// shape3->setBottomBarColorProvider(this, 2); +// shape3->setLeftBarColorProvider(this, 2); +// shape3->setRangeDefaultMilestones(0.05, 0.2, 0.58); + + // The milestones are still the same than those define above + //milestones.push_back( GradientMilestone(0., 0., 0., 0.) ); + //milestones.push_back( GradientMilestone(1., 1., 1., 1.) ); + shape->setBottomBarBgGradient(milestones); + shape->setLeftBarBgGradient(milestones); + shape2->setBottomBarBgGradient(milestones); + shape2->setLeftBarBgGradient(milestones); + + std::vector shape3Milestones; + float R, G, B; + for (int i=0; i<7; i++) { + float x = float(i)*(1.0f/6.0); + Color::hsv2rgb01(x, 0.5f, 0.5f, R, G, B); + shape3Milestones.push_back( GradientMilestone(double(x), double(R), double(G), double(B)) ); + } + shape3->setBottomBarBgGradient(shape3Milestones); + shape3->setLeftBarBgGradient(shape3Milestones); + + shape3->setRangeDefaultMilestones(0.05, 0.2, 0.58); + + curveEditorG->curveListComplete(); + + curveEditorG2->curveListComplete(); + curveEditorG2->setTooltip(M("TP_COLORAPP_CURVEEDITOR2_TOOLTIP")); + + curveEditorG3->curveListComplete(); + curveEditorG3->setTooltip(M("TP_COLORAPP_CURVEEDITOR3_TOOLTIP")); + tcmode3conn = toneCurveMode3->signal_changed().connect( sigc::mem_fun(*this, &ColorAppearance::curveMode3Changed), true ); + + p2VBox->pack_start( *curveEditorG, Gtk::PACK_SHRINK, 2); + p2VBox->pack_start( *curveEditorG2, Gtk::PACK_SHRINK, 2); + p2VBox->pack_start( *curveEditorG3, Gtk::PACK_SHRINK, 2); p2Frame->add(*p2VBox); pack_start (*p2Frame, Gtk::PACK_EXPAND_WIDGET, 4); @@ -221,18 +312,18 @@ Colorappearance::Colorappearance () : Gtk::VBox(), FoldableToolPanel(this) { gamut = Gtk::manage (new Gtk::CheckButton (M("TP_COLORAPP_GAMUT"))); gamut->set_tooltip_markup (M("TP_COLORAPP_GAMUT_TOOLTIP")); - gamutconn = gamut->signal_toggled().connect( sigc::mem_fun(*this, &Colorappearance::gamut_toggled) ); + gamutconn = gamut->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::gamut_toggled) ); pack_start (*gamut, Gtk::PACK_SHRINK); // ------------------------ Listening events - surrconn = surrsource->signal_toggled().connect( sigc::mem_fun(*this, &Colorappearance::surrsource_toggled) ); - enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &Colorappearance::enabledChanged) ); - wbmodelconn = wbmodel->signal_changed().connect ( sigc::mem_fun(*this, &Colorappearance::wbmodelChanged) ); - algoconn = algo->signal_changed().connect ( sigc::mem_fun(*this, &Colorappearance::algoChanged) ); - surroundconn = surround->signal_changed().connect ( sigc::mem_fun(*this, &Colorappearance::surroundChanged) ); + surrconn = surrsource->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::surrsource_toggled) ); + enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::enabledChanged) ); + wbmodelconn = wbmodel->signal_changed().connect ( sigc::mem_fun(*this, &ColorAppearance::wbmodelChanged) ); + algoconn = algo->signal_changed().connect ( sigc::mem_fun(*this, &ColorAppearance::algoChanged) ); + surroundconn = surround->signal_changed().connect ( sigc::mem_fun(*this, &ColorAppearance::surroundChanged) ); degree->setAdjusterListener (this); adapscen->setAdjusterListener (this); @@ -250,17 +341,35 @@ Colorappearance::Colorappearance () : Gtk::VBox(), FoldableToolPanel(this) { show_all(); } -bool Colorappearance::bgTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) { +ColorAppearance::~ColorAppearance () { + delete curveEditorG; + delete curveEditorG2; + delete curveEditorG3; +} + + + +bool ColorAppearance::bgTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) { return true; } -bool Colorappearance::srTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) { +bool ColorAppearance::srTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr& tooltip) { return true; } -void Colorappearance::read (const ProcParams* pp, const ParamsEdited* pedited) { +void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) { disableListener (); + tcmodeconn.block(true); + tcmode2conn.block(true); + tcmode3conn.block(true); + shape->setCurve (pp->colorappearance.curve); + shape2->setCurve (pp->colorappearance.curve2); + shape3->setCurve (pp->colorappearance.curve3); + toneCurveMode->set_active(pp->colorappearance.curveMode); + toneCurveMode2->set_active(pp->colorappearance.curveMode2); + toneCurveMode3->set_active(pp->colorappearance.curveMode3); + curveMode3Changed(); // This will set the correct sensitive state of depending Adjusters if (pedited) { degree->setEditedState (pedited->colorappearance.degree ? Edited : UnEdited); @@ -280,7 +389,21 @@ void Colorappearance::read (const ProcParams* pp, const ParamsEdited* pedited) { degree->setAutoInconsistent (multiImage && !pedited->colorappearance.autodegree); enabled->set_inconsistent (multiImage && !pedited->colorappearance.enabled); - } + shape->setUnChanged (!pedited->colorappearance.curve); + shape2->setUnChanged (!pedited->colorappearance.curve2); + shape3->setUnChanged (!pedited->colorappearance.curve3); + if (!pedited->colorappearance.curveMode) { + toneCurveMode->set_active(2); + } + if (!pedited->colorappearance.curveMode2) { + toneCurveMode2->set_active(2); + } + if (!pedited->colorappearance.curveMode3) { + toneCurveMode3->set_active(3); + } + + + } enaConn.block (true); enabled->set_active (pp->colorappearance.enabled); @@ -304,8 +427,6 @@ void Colorappearance::read (const ProcParams* pp, const ParamsEdited* pedited) { wbmodelconn.block(true); if (pedited && !pedited->colorappearance.wbmodel) wbmodel->set_active (2); -// else if (pp->colorappearance.wbmodel=="Equal") -// wbmodel->set_active (0); else if (pp->colorappearance.wbmodel=="RawT") wbmodel->set_active (0); else if (pp->colorappearance.wbmodel=="RawTCAT02") @@ -356,28 +477,53 @@ void Colorappearance::read (const ProcParams* pp, const ParamsEdited* pedited) { qcontrast->setValue (pp->colorappearance.qcontrast); colorh->setValue (pp->colorappearance.colorh); + tcmode3conn.block(false); + tcmode2conn.block(false); + tcmodeconn.block(false); enableListener (); } +void ColorAppearance::autoOpenCurve () { + shape->openIfNonlinear(); + shape2->openIfNonlinear(); + shape3->openIfNonlinear(); -void Colorappearance::write (ProcParams* pp, ParamsEdited* pedited) { +} - pp->colorappearance.degree = degree->getValue (); - pp->colorappearance.autodegree = degree->getAutoValue (); - pp->colorappearance.enabled = enabled->get_active(); - pp->colorappearance.adapscen = adapscen->getValue (); - pp->colorappearance.adaplum = adaplum->getValue (); - pp->colorappearance.jlight = jlight->getValue (); - pp->colorappearance.qbright = qbright->getValue (); - pp->colorappearance.chroma = chroma->getValue (); - pp->colorappearance.schroma = schroma->getValue (); - pp->colorappearance.mchroma = mchroma->getValue (); - pp->colorappearance.contrast = contrast->getValue (); - pp->colorappearance.qcontrast = qcontrast->getValue (); - pp->colorappearance.colorh = colorh->getValue (); - pp->colorappearance.rstprotection = rstprotection->getValue (); +void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->colorappearance.degree = degree->getValue (); + pp->colorappearance.autodegree = degree->getAutoValue (); + pp->colorappearance.enabled = enabled->get_active(); + pp->colorappearance.adapscen = adapscen->getValue (); + pp->colorappearance.adaplum = adaplum->getValue (); + pp->colorappearance.jlight = jlight->getValue (); + pp->colorappearance.qbright = qbright->getValue (); + pp->colorappearance.chroma = chroma->getValue (); + pp->colorappearance.schroma = schroma->getValue (); + pp->colorappearance.mchroma = mchroma->getValue (); + pp->colorappearance.contrast = contrast->getValue (); + pp->colorappearance.qcontrast = qcontrast->getValue (); + pp->colorappearance.colorh = colorh->getValue (); + pp->colorappearance.rstprotection = rstprotection->getValue (); pp->colorappearance.surrsource = surrsource->get_active(); - pp->colorappearance.gamut = gamut->get_active(); + pp->colorappearance.gamut = gamut->get_active(); + pp->colorappearance.curve = shape->getCurve (); + pp->colorappearance.curve2 = shape2->getCurve (); + pp->colorappearance.curve3 = shape3->getCurve (); + + int tcMode = toneCurveMode->get_active_row_number(); + if (tcMode == 0) pp->colorappearance.curveMode = ColorAppearanceParams::TC_MODE_LIGHT; + else if (tcMode == 1) pp->colorappearance.curveMode = ColorAppearanceParams::TC_MODE_BRIGHT; + + tcMode = toneCurveMode2->get_active_row_number(); + if (tcMode == 0) pp->colorappearance.curveMode2 = ColorAppearanceParams::TC_MODE_LIGHT; + else if (tcMode == 1) pp->colorappearance.curveMode2 = ColorAppearanceParams::TC_MODE_BRIGHT; + + int tcMode3 = toneCurveMode3->get_active_row_number(); + if (tcMode3 == 0) pp->colorappearance.curveMode3 = ColorAppearanceParams::TC_MODE_CHROMA; + else if (tcMode3 == 1) pp->colorappearance.curveMode3 = ColorAppearanceParams::TC_MODE_SATUR; + else if (tcMode3 == 2) pp->colorappearance.curveMode3 = ColorAppearanceParams::TC_MODE_COLORF; if (pedited) { pedited->colorappearance.degree = degree->getEditedState (); @@ -399,6 +545,12 @@ void Colorappearance::write (ProcParams* pp, ParamsEdited* pedited) { pedited->colorappearance.algo = algo->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->colorappearance.surrsource = !surrsource->get_inconsistent(); pedited->colorappearance.gamut = !gamut->get_inconsistent(); + pedited->colorappearance.curve = !shape->isUnChanged (); + pedited->colorappearance.curve2 = !shape2->isUnChanged (); + pedited->colorappearance.curve3 = !shape3->isUnChanged (); + pedited->colorappearance.curveMode = toneCurveMode->get_active_row_number() != 2; + pedited->colorappearance.curveMode2 = toneCurveMode2->get_active_row_number() != 2; + pedited->colorappearance.curveMode3 = toneCurveMode3->get_active_row_number() != 3; } if (surround->get_active_row_number()==0) pp->colorappearance.surround = "Average"; @@ -409,8 +561,6 @@ void Colorappearance::write (ProcParams* pp, ParamsEdited* pedited) { else if (surround->get_active_row_number()==3) pp->colorappearance.surround = "ExtremelyDark"; -// if (wbmodel->get_active_row_number()==0) -// pp->colorappearance.wbmodel = "Equal"; if (wbmodel->get_active_row_number()==0) pp->colorappearance.wbmodel = "RawT"; else if (wbmodel->get_active_row_number()==1) @@ -426,8 +576,53 @@ void Colorappearance::write (ProcParams* pp, ParamsEdited* pedited) { pp->colorappearance.algo = "ALL"; } +void ColorAppearance::curveChanged (CurveEditor* ce) { -void Colorappearance::surrsource_toggled () { + if (listener) { + if (ce == shape) + listener->panelChanged (EvCATCurve1, M("HISTORY_CUSTOMCURVE")); + else if (ce == shape2) + listener->panelChanged (EvCATCurve2, M("HISTORY_CUSTOMCURVE")); + else if (ce == shape3) + listener->panelChanged (EvCATCurve3, M("HISTORY_CUSTOMCURVE")); + } +} + +void ColorAppearance::curveMode1Changed () { + if (listener) Glib::signal_idle().connect (sigc::mem_fun(*this, &ColorAppearance::curveMode1Changed_)); +} + +bool ColorAppearance::curveMode1Changed_ () { + if (listener) listener->panelChanged (EvCATCurveMode1, toneCurveMode->get_active_text()); + return false; +} + +void ColorAppearance::curveMode2Changed () { + if (listener) Glib::signal_idle().connect (sigc::mem_fun(*this, &ColorAppearance::curveMode2Changed_)); +} + +bool ColorAppearance::curveMode2Changed_ () { + if (listener) listener->panelChanged (EvCATCurveMode2, toneCurveMode2->get_active_text()); + return false; +} + +void ColorAppearance::curveMode3Changed () { + int tcMode3 = toneCurveMode3->get_active_row_number(); + if (tcMode3 == 0) {chroma->set_sensitive(true); schroma->set_sensitive(true); } + else if (tcMode3 == 2) {chroma->set_sensitive(false); schroma->set_sensitive(false);} + else if (tcMode3 == 1) {chroma->set_sensitive(false); schroma->set_sensitive(true); } + + if (listener) Glib::signal_idle().connect (sigc::mem_fun(*this, &ColorAppearance::curveMode3Changed_)); +} + +bool ColorAppearance::curveMode3Changed_ () { + if (listener) { + listener->panelChanged (EvCATCurveMode3, toneCurveMode3->get_active_text()); + } + return false; +} + +void ColorAppearance::surrsource_toggled () { if (batchMode) { if (surrsource->get_inconsistent()) { @@ -450,7 +645,7 @@ void Colorappearance::surrsource_toggled () { } } -void Colorappearance::gamut_toggled () { +void ColorAppearance::gamut_toggled () { if (batchMode) { if (gamut->get_inconsistent()) { @@ -474,7 +669,7 @@ void Colorappearance::gamut_toggled () { } -void Colorappearance::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { +void ColorAppearance::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { degree->setDefault (defParams->colorappearance.degree); adapscen->setDefault (defParams->colorappearance.adapscen); @@ -521,7 +716,22 @@ void Colorappearance::setDefaults (const ProcParams* defParams, const ParamsEdit } } -void Colorappearance::adjusterChanged (Adjuster* a, double newval) { +void ColorAppearance::colorForValue (double valX, double valY, int callerId, ColorCaller *caller) { + + float R, G, B; + if (callerId == 1) { // cc - bottom bar + + float value = (1.f - 0.7f) * float(valX) + 0.7f; + // whole hue range + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) + Color::hsv2rgb01(float(valY), float(valX), value, R, G, B); + } + caller->ccRed = double(R); + caller->ccGreen = double(G); + caller->ccBlue = double(B); +} + +void ColorAppearance::adjusterChanged (Adjuster* a, double newval) { if (listener && (multiImage||enabled->get_active()) ) { if(a==degree) @@ -552,7 +762,7 @@ void Colorappearance::adjusterChanged (Adjuster* a, double newval) { } } -void Colorappearance::adjusterAutoToggled (Adjuster* a, bool newval) { +void ColorAppearance::adjusterAutoToggled (Adjuster* a, bool newval) { if (multiImage) { if (degree->getAutoInconsistent()) { @@ -577,7 +787,7 @@ void Colorappearance::adjusterAutoToggled (Adjuster* a, bool newval) { } } -void Colorappearance::enabledChanged () { +void ColorAppearance::enabledChanged () { if (multiImage) { if (enabled->get_inconsistent()) { @@ -595,28 +805,32 @@ void Colorappearance::enabledChanged () { if (listener) { if (enabled->get_inconsistent()) listener->panelChanged (EvCATEnabled, M("GENERAL_UNCHANGED")); - else if (enabled->get_active ()) + else if (enabled->get_active ()) { listener->panelChanged (EvCATEnabled, M("GENERAL_ENABLED")); + curveEditorG->set_sensitive (true); + toneCurveMode->set_sensitive (true); + } else listener->panelChanged (EvCATEnabled, M("GENERAL_DISABLED")); } } -void Colorappearance::surroundChanged () { +void ColorAppearance::surroundChanged () { if (listener && (multiImage||enabled->get_active()) ) { listener->panelChanged (EvCATMethodsur, surround->get_active_text ()); } } -void Colorappearance::wbmodelChanged () { +void ColorAppearance::wbmodelChanged () { if (listener && (multiImage||enabled->get_active()) ) { listener->panelChanged (EvCATMethodWB, wbmodel->get_active_text ()); } } -void Colorappearance::algoChanged () { + +void ColorAppearance::algoChanged () { if ( algo->get_active_row_number()==0 ) { contrast->show(); @@ -628,9 +842,12 @@ void Colorappearance::algoChanged () { schroma->hide(); qbright->hide(); colorh->hide(); + curveEditorG->show(); + curveEditorG2->show(); + curveEditorG3->show(); } else if ( algo->get_active_row_number()==1 ) { - rstprotection->hide(); + rstprotection->show(); contrast->show(); qcontrast->hide(); jlight->show(); @@ -639,10 +856,13 @@ void Colorappearance::algoChanged () { schroma->show(); qbright->hide(); colorh->hide(); + curveEditorG->show(); + curveEditorG2->show(); + curveEditorG3->show(); } else if ( algo->get_active_row_number()==2 ) { contrast->hide(); - rstprotection->hide(); + rstprotection->show(); qcontrast->show(); jlight->hide(); mchroma->show(); @@ -650,6 +870,9 @@ void Colorappearance::algoChanged () { schroma->hide(); qbright->show(); colorh->hide(); + curveEditorG->show(); + curveEditorG2->show(); + curveEditorG3->show(); } else if ( algo->get_active_row_number()>=3 ) { // ">=3" because everything has to be visible with the "(unchanged)" option too contrast->show(); @@ -661,6 +884,9 @@ void Colorappearance::algoChanged () { schroma->show(); qbright->show(); colorh->show(); + curveEditorG->show(); + curveEditorG2->show(); + curveEditorG3->show(); } if (listener && (multiImage||enabled->get_active()) ) { @@ -668,7 +894,7 @@ void Colorappearance::algoChanged () { } } -void Colorappearance::setBatchMode (bool batchMode) { +void ColorAppearance::setBatchMode (bool batchMode) { ToolPanel::setBatchMode (batchMode); @@ -688,10 +914,16 @@ void Colorappearance::setBatchMode (bool batchMode) { surround->append_text (M("GENERAL_UNCHANGED")); wbmodel->append_text (M("GENERAL_UNCHANGED")); algo->append_text (M("GENERAL_UNCHANGED")); - + toneCurveMode->append_text (M("GENERAL_UNCHANGED")); +// toneCurveMode2->append_text (M("GENERAL_UNCHANGED")); +// toneCurveMode3->append_text (M("GENERAL_UNCHANGED")); + + curveEditorG->setBatchMode (batchMode); +// curveEditorG2->setBatchMode (batchMode); +// curveEditorG3->setBatchMode (batchMode); } -void Colorappearance::setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd) { +void ColorAppearance::setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd) { degree->setAddMode(degreeadd); adapscen->setAddMode(adapscenadd); @@ -705,10 +937,9 @@ void Colorappearance::setAdjusterBehavior (bool degreeadd, bool adapscenadd, boo contrast->setAddMode(contrastadd); qcontrast->setAddMode(qcontrastadd); colorh->setAddMode(colorhadd); - } -void Colorappearance::trimValues (rtengine::procparams::ProcParams* pp) { +void ColorAppearance::trimValues (rtengine::procparams::ProcParams* pp) { degree->trimValue(pp->colorappearance.degree); adapscen->trimValue(pp->colorappearance.adapscen); @@ -722,5 +953,4 @@ void Colorappearance::trimValues (rtengine::procparams::ProcParams* pp) { contrast->trimValue(pp->colorappearance.contrast); qcontrast->trimValue(pp->colorappearance.qcontrast); colorh->trimValue(pp->colorappearance.colorh); - } diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h index c49103554..e0c6025c3 100644 --- a/rtgui/colorappearance.h +++ b/rtgui/colorappearance.h @@ -22,12 +22,17 @@ #include #include "adjuster.h" #include "toolpanel.h" +#include "curveeditor.h" +#include "curveeditorgroup.h" +#include "mycurve.h" +#include "guiutils.h" +#include "colorprovider.h" -class Colorappearance : public Gtk::VBox, public AdjusterListener, public FoldableToolPanel { +class ColorAppearance : public Gtk::VBox, public AdjusterListener, public FoldableToolPanel, public CurveListener, public ColorProvider { protected: - Glib::RefPtr bgTTips; - Glib::RefPtr srTTips; + Glib::RefPtr bgTTips; + Glib::RefPtr srTTips; Glib::RefPtr bgPixbuf; Glib::RefPtr srPixbuf; @@ -43,32 +48,44 @@ class Colorappearance : public Gtk::VBox, public AdjusterListener, public Foldab Adjuster* contrast; Adjuster* qcontrast; Adjuster* colorh; + MyComboBoxText* toneCurveMode; + MyComboBoxText* toneCurveMode2; + MyComboBoxText* toneCurveMode3; //Adjuster* edge; - Gtk::CheckButton* surrsource; - Gtk::CheckButton* gamut; - + Gtk::CheckButton* surrsource; + Gtk::CheckButton* gamut; + Gtk::CheckButton* enabled; - MyComboBoxText* surround; - sigc::connection surroundconn; - MyComboBoxText* wbmodel; - sigc::connection wbmodelconn; - MyComboBoxText* algo; - sigc::connection algoconn; - sigc::connection surrconn; - sigc::connection gamutconn; + MyComboBoxText* surround; + sigc::connection surroundconn; + MyComboBoxText* wbmodel; + sigc::connection wbmodelconn; + MyComboBoxText* algo; + sigc::connection algoconn; + sigc::connection surrconn; + sigc::connection gamutconn; + sigc::connection tcmodeconn, tcmode2conn, tcmode3conn; + CurveEditorGroup* curveEditorG; + CurveEditorGroup* curveEditorG2; + CurveEditorGroup* curveEditorG3; + + DiagonalCurveEditor* shape; + DiagonalCurveEditor* shape2; + DiagonalCurveEditor* shape3; bool lastEnabled; bool lastAutoDegree; sigc::connection enaConn; - bool lastsurr; - bool lastgamut; + bool lastsurr; + bool lastgamut; 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: - Colorappearance (); + ColorAppearance (); + ~ColorAppearance (); void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); @@ -78,13 +95,27 @@ class Colorappearance : public Gtk::VBox, public AdjusterListener, public Foldab void adjusterChanged (Adjuster* a, double newval); void adjusterAutoToggled (Adjuster* a, bool newval); void enabledChanged (); - void surroundChanged (); + void surroundChanged (); void wbmodelChanged (); - void algoChanged (); - void surrsource_toggled (); - void gamut_toggled (); + void algoChanged (); + void surrsource_toggled (); + void gamut_toggled (); + void curveChanged (CurveEditor* ce); + void curveMode1Changed (); + bool curveMode1Changed_ (); + void curveMode2Changed (); + bool curveMode2Changed_ (); + void curveMode3Changed (); + bool curveMode3Changed_ (); + + void expandCurve (bool isExpanded); + bool isCurveExpanded (); + void autoOpenCurve (); + void setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd); void trimValues (rtengine::procparams::ProcParams* pp); + + virtual void colorForValue (double valX, double valY, int callerId, ColorCaller *caller); }; #endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 41871b2c6..853a8728d 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -112,6 +112,12 @@ void ParamsEdited::set (bool v) { colorappearance.rstprotection = v; colorappearance.surrsource = v; colorappearance.gamut = v; + colorappearance.curve = v; + colorappearance.curve2 = v; + colorappearance.curve3 = v; + colorappearance.curveMode = v; + colorappearance.curveMode2 = v; + colorappearance.curveMode3 = v; //colorBoost.amount = v; //colorBoost.avoidclip = v; @@ -335,6 +341,12 @@ void ParamsEdited::initFrom (const std::vector colorappearance.colorh = colorappearance.colorh && p.colorappearance.colorh == other.colorappearance.colorh; colorappearance.surrsource = colorappearance.surrsource && p.colorappearance.surrsource == other.colorappearance.surrsource; colorappearance.gamut = colorappearance.gamut && p.colorappearance.gamut == other.colorappearance.gamut; + 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; + colorappearance.curveMode = colorappearance.curveMode && p.colorappearance.curveMode == other.colorappearance.curveMode; + colorappearance.curveMode2 = colorappearance.curveMode2 && p.colorappearance.curveMode2 == other.colorappearance.curveMode2; + colorappearance.curveMode3 = colorappearance.curveMode3 && p.colorappearance.curveMode3 == other.colorappearance.curveMode3; //colorBoost.amount = colorBoost.amount && p.colorBoost.amount == other.colorBoost.amount; //colorBoost.avoidclip = colorBoost.avoidclip && p.colorBoost.avoidclip == other.colorBoost.avoidclip; @@ -566,6 +578,13 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (defringe.enabled) toEdit.defringe.enabled = mods.defringe.enabled; if (defringe.radius) toEdit.defringe.radius = mods.defringe.radius; if (defringe.threshold) toEdit.defringe.threshold = mods.defringe.threshold; + + if (colorappearance.curve) toEdit.colorappearance.curve = mods.colorappearance.curve; + if (colorappearance.curve2) toEdit.colorappearance.curve2 = mods.colorappearance.curve2; + if (colorappearance.curve3) toEdit.colorappearance.curve3 = mods.colorappearance.curve3; + if (colorappearance.curveMode) toEdit.colorappearance.curveMode = mods.colorappearance.curveMode; + if (colorappearance.curveMode2) toEdit.colorappearance.curveMode2 = mods.colorappearance.curveMode2; + if (colorappearance.curveMode3) toEdit.colorappearance.curveMode3 = mods.colorappearance.curveMode3; if (colorappearance.enabled) toEdit.colorappearance.enabled = mods.colorappearance.enabled; if (colorappearance.degree) toEdit.colorappearance.degree = dontforceSet && options.baBehav[ADDSET_CAT_DEGREE] ? toEdit.colorappearance.degree + mods.colorappearance.degree : mods.colorappearance.degree; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 5caed7a3b..c3d909904 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -181,9 +181,15 @@ public: bool thresh; }; -class ColorappearanceParamsEdited { +class ColorAppearanceParamsEdited { public: + bool curve; + bool curve2; + bool curve3; + bool curveMode; + bool curveMode2; + bool curveMode3; bool enabled; bool degree; bool autodegree; @@ -411,7 +417,7 @@ class ParamsEdited { SharpenEdgeParamsEdited sharpenEdge; SharpenMicroParamsEdited sharpenMicro; VibranceParamsEdited vibrance; - ColorappearanceParamsEdited colorappearance; + ColorAppearanceParamsEdited colorappearance; //ColorBoostParamsEdited colorBoost; WBParamsEdited wb; //ColorShiftParamsEdited colorShift; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index f64a2a8c1..036263202 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -436,6 +436,9 @@ Gtk::Widget* Preferences::getColorManagementPanel () { view->append_text (M("PREFERENCES_D60")); view->append_text (M("PREFERENCES_D65")); view->append_text (M("PREFERENCES_BLACKBODY")); + view->append_text (M("PREFERENCES_FLUOF2")); + view->append_text (M("PREFERENCES_FLUOF7")); + view->append_text (M("PREFERENCES_FLUOF11")); Gtk::Label* greylab = Gtk::manage (new Gtk::Label (M("PREFERENCES_GREY")+":", Gtk::ALIGN_LEFT)); grey = Gtk::manage (new Gtk::ComboBoxText ()); diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index c5eeae589..98851937f 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -56,7 +56,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { distortion = Gtk::manage (new Distortion ()); rotate = Gtk::manage (new Rotate ()); vibrance = Gtk::manage (new Vibrance ()); - colorappearance = Gtk::manage (new Colorappearance ()); + colorappearance = Gtk::manage (new ColorAppearance ()); whitebalance = Gtk::manage (new WhiteBalance ()); vignetting = Gtk::manage (new Vignetting ()); perspective = Gtk::manage (new PerspCorrection ()); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 31f0fe168..857330a70 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -91,7 +91,7 @@ class ToolPanelCoordinator : public ToolPanelListener, PerspCorrection* perspective; CACorrection* cacorrection; HLRecovery* hlrecovery; - Colorappearance* colorappearance; + ColorAppearance* colorappearance; Vibrance* vibrance; ChMixer* chmixer; Resize* resize;