diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 2ebe0ff6f..6273eff2b 100755 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -971,7 +971,7 @@ TP_BWMIX_LABEL;Noir & Blanc TP_BWMIX_CC_ENABLED;Ajuster les couleurs complémentaires TP_BWMIX_CHANNEL;Égaliseur de Luminance TP_BWMIX_VAL;L -TP_BWMIX_CC_TOOLTIP;Activer pour permettre l'ajustage automatique des couleur complémentaire dans le mode ROJVCBMP +TP_BWMIX_CC_TOOLTIP;Activer pour permettre l'ajustage automatique des couleur complémentaire dans le mode ROJVCBPM TP_BWMIX_SETTING_TOOLTIP;Différents préréglages (films, paysage, ...) ou réglages manuel du mixeur de canaux TP_BWMIX_FILTER_TOOLTIP;Le filtre de couleur simule les prises de vue avec un filtre coloré placé devant l'objectif. Les filtres colorés réduisent la transmission d'une plage de couleur spécifique et en affectent donc leur luminosité. Ex: un filtre rouge assombri les ciels bleus. TP_BWMIX_AUTOCH;Auto @@ -992,6 +992,8 @@ TP_BWMIX_GAM_GREEN;Canal Vert TP_BWMIX_GAM_BLUE;Canal Bleu TP_BWMIX_MIXC;Mixeur TP_BWMIX_MIXF;Mixeur de Filtres +TP_BWMIX_RGBLABEL;R: %1%% V: %2%% B: %3%% Total: %4%% +TP_BWMIX_RGBLABEL_HINT;Coefficients RVB finaux qui tiennent compte de toutes les options du mixeur\nTotal affiche la somme des valeurs RVB actuellement appliqué:\n- toujours 100% en mode relatif\n- supérieur (plus clair) ou inférieur (plus sombre) à 100% en mode absolu. TP_BWMIX_FILTER;Filtre de couleur TP_BWMIX_FILTER_NONE;Aucun TP_BWMIX_FILTER_RED;Rouge @@ -1015,8 +1017,8 @@ TP_BWMIX_SET_HYPERPANCHRO;Hyper Panchromatique TP_BWMIX_SET_ORTHOCHRO;Orthochromatique TP_BWMIX_SET_RGBABS;Mixeur de Canaux - RVB Absolu TP_BWMIX_SET_RGBREL;Mixeur de Canaux - RVB Relatif -TP_BWMIX_SET_ROYGCBMPABS;Mixeur de Canaux - ROJVCBMP Absolu -TP_BWMIX_SET_ROYGCBMPREL;Mixeur de Canaux - ROJVCBMP Relatif +TP_BWMIX_SET_ROYGCBPMABS;Mixeur de Canaux - ROJVCBPM Absolu +TP_BWMIX_SET_ROYGCBPMREL;Mixeur de Canaux - ROJVCBPM Relatif TP_BWMIX_SET_INFRARED;Infrarouge TP_BWMIX_GAMMA;Correction Gamma TP_BWMIX_GAM_TOOLTIP;Corrige le gamma pour chaque canaux RVB diff --git a/rtdata/languages/default b/rtdata/languages/default index f7a881c17..824a5cbda 100755 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -975,7 +975,7 @@ TP_BWMIX_LABEL;Black & White TP_BWMIX_CC_ENABLED;Adjust complementary color TP_BWMIX_CHANNEL;Luminance Equalizer TP_BWMIX_VAL;L -TP_BWMIX_CC_TOOLTIP;Enable to allow automatic adjustment of complementary colors in ROYGCBMP mode +TP_BWMIX_CC_TOOLTIP;Enable to allow automatic adjustment of complementary colors in ROYGCBPM mode TP_BWMIX_SETTING_TOOLTIP;Different presets (films, landscape, ...) or manual settings of channel-mixer TP_BWMIX_FILTER_TOOLTIP;The color filter simulate shots taken with a colored filter placed in front of the lens. Colored filters reduce transmission of specific range of colors and correspondingly affect their lightness. E.g. a Red filter darkens Blue skies. TP_BWMIX_AUTOCH;Auto @@ -996,6 +996,8 @@ TP_BWMIX_GAM_GREEN;Green Channel TP_BWMIX_GAM_BLUE;Blue Channel TP_BWMIX_MIXC;Mixer TP_BWMIX_MIXF;Mixer Filters +TP_BWMIX_RGBLABEL;R: %1%% G: %2%% B: %3%% Total: %4%% +TP_BWMIX_RGBLABEL_HINT;Final RGB factors that take care of all of the mixer options\nTotal displays the sum of RGB values ​​actually applied:\n*always 100% in relative mode\n- higher (lighter) or lower (darker) than 100% in absolute mode. TP_BWMIX_FILTER;Color Filter TP_BWMIX_FILTER_NONE;None TP_BWMIX_FILTER_RED;Red @@ -1019,8 +1021,8 @@ TP_BWMIX_SET_HYPERPANCHRO;Hyper Panchromatic TP_BWMIX_SET_ORTHOCHRO;Orthochromatic TP_BWMIX_SET_RGBABS;Channel-Mixer absolute RGB TP_BWMIX_SET_RGBREL;Channel-Mixer relative RGB -TP_BWMIX_SET_ROYGCBMPABS;Channel-Mixer absolute ROYGCBMP -TP_BWMIX_SET_ROYGCBMPREL;Channel-Mixer relative ROYGCBMP +TP_BWMIX_SET_ROYGCBPMABS;Channel-Mixer absolute ROYGCBPM +TP_BWMIX_SET_ROYGCBPMREL;Channel-Mixer relative ROYGCBPM TP_BWMIX_SET_INFRARED;Infrared TP_BWMIX_GAMMA;Gamma Correction TP_BWMIX_GAM_TOOLTIP;Correct gamma for each channel RGB diff --git a/rtengine/LUT.h b/rtengine/LUT.h index 09c739d1d..1c7872e8e 100644 --- a/rtengine/LUT.h +++ b/rtengine/LUT.h @@ -88,7 +88,17 @@ private: __m128i sizeiv __attribute__ ((aligned (16))); #endif public: + /// convenience flag! If one doesn't want to delete the buffer but want to flag it to be recomputed... + /// The user have to handle it itself, even if some method can (re)initialize it + bool dirty; + LUT(int s, int flags = 0xfffffff) { + #ifndef NDEBUG + if (s<=0) + printf("s<=0!\n"); + assert (s>0); + #endif + dirty = true; clip = flags; data = new T[s]; owner = 1; @@ -102,8 +112,14 @@ public: #endif } void operator ()(int s, int flags = 0xfffffff) { + #ifndef NDEBUG + if (s<=0) + printf("s<=0!\n"); + assert (s>0); + #endif if (owner&&data) delete[] data; + dirty = true; // Assumption! clip = flags; data = new T[s]; owner = 1; @@ -118,6 +134,15 @@ public: } LUT(int s, T * source, int flags = 0xfffffff) { + #ifndef NDEBUG + if (s<=0) + printf("s<=0!\n"); + assert (s>0); + if (source==NULL) + printf("source is NULL!\n"); + assert (source != NULL); + #endif + dirty = false; // Assumption clip = flags; data = new T[s]; owner = 1; @@ -134,14 +159,18 @@ public: } } - LUT(void) { + LUT() { data = NULL; reset(); } ~LUT() { - if (owner) + if (owner) { delete[] data; + #ifndef NDEBUG + data=(T*)0xBAADF00D; + #endif + } } void setClip(int flags) { @@ -321,11 +350,11 @@ public: if (size) { Glib::ustring fname_ = fname + ".xyz"; // TopSolid'Design "plot" file format std::ofstream f (fname_.c_str()); - f << "$" << std::endl;; + f << "$" << std::endl; for (unsigned int iter=0; iter= 33) orM = fcompl*(mixerOrange*0.67f - 22.11f)/100.f; else orM = fcompl*(-0.3f*mixerOrange +9.9f)/100.f; + if (mixerOrange >= 33) ogM = fcompl*(-0.164f*mixerOrange+5.412f)/100.f; else ogM = fcompl*(0.4f*mixerOrange-13.2f)/100.f; + if(complement) obM =(-0.492f*mixerOrange+16.236f)/100.f; + mixerRed += orM; + mixerGreen += ogM; + mixerBlue += obM; + koymcp += (orM+ogM+obM); + } + if(mixerYellow != 33) { + yrM = fcompl*(-0.134f*mixerYellow+4.422f)/100.f;//22.4 + ygM = fcompl*( 0.5f *mixerYellow-16.5f )/100.f; + if(complement) ybM =(-0.492f*mixerYellow+16.236f)/100.f; + mixerRed += yrM; + mixerGreen += ygM; + mixerBlue += ybM; + koymcp += (yrM+ygM+ybM); + } + if(mixerMagenta != 33) { + if(mixerMagenta >= 33) mrM = fcompl*( 0.67f *mixerMagenta-22.11f)/100.f; else mrM = fcompl*(-0.3f*mixerMagenta +9.9f)/100.f; + if(mixerMagenta >= 33) mbM = fcompl*(-0.164f*mixerMagenta+5.412f)/100.f; else mbM = fcompl*( 0.4f*mixerMagenta-13.2f)/100.f; + if(complement) mgM =(-0.492f*mixerMagenta+16.236f)/100.f; + mixerRed += mrM; + mixerGreen += mgM; + mixerBlue += mbM; + koymcp += (mrM+mgM+mbM); + } + if(mixerPurple != 33) { + prM = fcompl*(-0.134f*mixerPurple+4.422f)/100.f; + pbM = fcompl*(0.5f*mixerPurple-16.5f)/100.f; + if(complement) pgM = (-0.492f*mixerPurple+16.236f)/100.f; + mixerRed += prM; + mixerGreen += pgM; + mixerBlue += pbM; + koymcp += (prM+pgM+pbM); + } + if(mixerCyan != 33) { + cgM = fcompl*(-0.134f*mixerCyan +4.422f)/100.f; + cbM = fcompl*(0.5f*mixerCyan-16.5f)/100.f; + if(complement) crM = (-0.492f*mixerCyan+16.236f)/100.f; + mixerRed += crM; + mixerGreen += cgM; + mixerBlue += cbM; + koymcp += (crM+cgM+cbM); + } + } + if(setting=="ROYGCBPM-Abs") + kcorec = koymcp+som/100.f; + //Color filters + float filred,filgreen,filblue; + filred=1.f;filgreen=1.f;filblue=1.f; + if (filter=="None") {filred=1.f; filgreen=1.f; filblue=1.f;} + else if (filter=="Red") {filred=1.f; filgreen=0.05f;filblue=0.f;} + else if (filter=="Orange") {filred=1.f; filgreen=0.6f; filblue=0.f;} + else if (filter=="Yellow") {filred=1.f; filgreen=1.f; filblue=0.05f;} + else if (filter=="YellowGreen") {filred=0.6f; filgreen=1.f; filblue=0.3f;} + else if (filter=="Green") {filred=0.2f; filgreen=1.f; filblue=0.3f;} + else if (filter=="Cyan") {filred=0.05f;filgreen=1.f; filblue=1.f;} + else if (filter=="Blue") {filred=0.f; filgreen=0.05f;filblue=1.f;} + else if (filter=="Purple") {filred=1.f; filgreen=0.05f;filblue=1.f;} + + + mixerRed = mixerRed * filred; + mixerGreen = mixerGreen * filgreen; + mixerBlue = mixerBlue * filblue; + + mixerRed = mixerRed / (mixerRed + mixerGreen + mixerBlue); + mixerGreen = mixerGreen / (mixerRed + mixerGreen + mixerBlue); + mixerBlue = mixerBlue / (mixerRed + mixerGreen + mixerBlue); + } + void Color::calcGamma (double pwr, double ts, int mode, int imax, double &gamma0, double &gamma1, double &gamma2, double &gamma3, double &gamma4, double &gamma5) { //from Dcraw (D.Coffin) int i; diff --git a/rtengine/color.h b/rtengine/color.h index 773899d1a..53923eca8 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -128,45 +128,48 @@ public: static void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, double rgb_xyz[3][3]); static void xyz2rgb (float x, float y, float z, float &r, float &g, float &b, float rgb_xyz[3][3]); static void rgbxyz (float r, float g, float b, float &x, float &y, float &z, double xyz_rgb[3][3]); - + static void Lab2XYZ(float L, float a, float b, float &x, float &y, float &z); static void XYZ2Lab(float X, float Y, float Z, float &L, float &a, float &b); static void Lab2Yuv(float L, float a, float b, float &Y, float &u, float &v); static void Yuv2Lab(float Y, float u, float v, float &L, float &a, float &b, double wp[3][3]); - static double f2xyz(double f); + static double f2xyz(double f); static void calcGamma (double pwr, double ts, int mode, int imax, double &gamma0, double &gamma1, double &gamma2, double &gamma3, double &gamma4,double &gamma5); static void trcGammaBW (float &r, float &g, float &b, float gammabwr, float gammabwg, float gammabwb); + static void computeBWMixerConstants (const Glib::ustring &setting, const Glib::ustring &filter, float &mixerRed, float &mixerGreen, + float &mixerBlue, float mixerOrange, float mixerYellow, float mixerCyan, float mixerPurple, float mixerMagenta, + bool autoc, bool complement, float &kcorec, double &rrm, double &ggm, double &bbm); static void huelab_to_huehsv (float HH, double &hr); // standard srgb gamma and its inverse - static inline double gamma2 (double x) { + static inline double gamma2 (double x) { return x <= 0.003041 ? x*12.92 : 1.055011*exp(log(x)/sRGBGammaCurve)-0.055011; } - static inline double igamma2 (double x) { - return x <= 0.039293 ? x/12.92 : exp(log((x+0.055011)/1.055011)*sRGBGammaCurve); - } + static inline double igamma2 (double x) { + return x <= 0.039293 ? x/12.92 : exp(log((x+0.055011)/1.055011)*sRGBGammaCurve); + } /* static inline double gamma709 (double x) { return x <= 0.0176 ? x*4.5 : 1.0954*exp(log(x)/2.2)-0.0954; } static inline double igamma709 (double x) { - return x <= 0.0795 ? x/4.5 : exp(log((x+0.0954)/1.0954)*2.2); + return x <= 0.0795 ? x/4.5 : exp(log((x+0.0954)/1.0954)*2.2); } */ static inline double gamma24_17 (double x) { return x <= 0.001867 ? x*17.0 : 1.044445*exp(log(x)/2.4)-0.044445; } static inline double igamma24_17 (double x) { - return x <= 0.031746 ? x/17.0 : exp(log((x+0.044445)/1.044445)*2.4); + return x <= 0.031746 ? x/17.0 : exp(log((x+0.044445)/1.044445)*2.4); } - + static inline double gamma26_11 (double x) { return x <= 0.004921 ? x*11.0 : 1.086603*exp(log(x)/2.6)-0.086603; } static inline double igamma26_11 (double x) { - return x <= 0.054127 ? x/11.0 : exp(log((x+0.086603)/1.086603)*2.6); + return x <= 0.054127 ? x/11.0 : exp(log((x+0.086603)/1.086603)*2.6); } - + // gamma function with adjustable parameters static inline double gamma (double x, double gamma, double start, double slope, double mul, double add){ return (x <= start ? x*slope : exp(log(x)/gamma)*mul-add); diff --git a/rtengine/curves.cc b/rtengine/curves.cc index b8cb3e278..8b55718ed 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -150,7 +150,7 @@ namespace rtengine { void CurveFactory::updatechroma ( const std::vector& cccurvePoints, - LUTu & histogramC, LUTu & histogramCroppedC, LUTu & outBeforeCCurveHistogramC,//for chroma + LUTu & histogramC, LUTu & outBeforeCCurveHistogramC,//for chroma int skip) { LUTf dCcurve(65536,0); @@ -184,7 +184,7 @@ void CurveFactory::curveLightBrightColor ( procparams::ColorAppearanceParams::eTCModeId curveMode2, const std::vector& curvePoints2, procparams::ColorAppearanceParams::eCTCModeId curveMode3, const std::vector& curvePoints3, LUTu & histogram, LUTu & histogramCropped, LUTu & outBeforeCCurveHistogram,//for Luminance - LUTu & histogramC, LUTu & histogramCroppedC, LUTu & outBeforeCCurveHistogramC,//for chroma + LUTu & histogramC, LUTu & outBeforeCCurveHistogramC,//for chroma ColorAppearance & customColCurve1, ColorAppearance & customColCurve2, ColorAppearance & customColCurve3, @@ -289,12 +289,9 @@ void CurveFactory::curveLightBrightColor ( } void CurveFactory::curveBW ( - procparams::BlackWhiteParams::eTCModeId curveModeb, const std::vector& curvePointsbw, - procparams::BlackWhiteParams::eTCModeId curveModeb2, const std::vector& curvePointsbw2, - LUTu & histogrambw, LUTu & histogramCropped, LUTu & outBeforeCCurveHistogrambw,//for Luminance - ChMixerbw & customToneCurvebw1, - ChMixerbw & customToneCurvebw2, - int skip) + const std::vector& curvePointsbw, const std::vector& curvePointsbw2, + LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw,//for Luminance + ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip) { LUTf dcurve(65536,0); @@ -317,11 +314,7 @@ void CurveFactory::curveBW ( } if (tcurve) { - if (tcurve->isIdentity()) { - delete tcurve; - tcurve = NULL; - } - else + if (!tcurve->isIdentity()) customToneCurvebw2.Set(tcurve); delete tcurve; tcurve = NULL; @@ -336,11 +329,7 @@ void CurveFactory::curveBW ( } if (tcurve) { - if (tcurve->isIdentity()) { - delete tcurve; - tcurve = NULL; - } - else + if (!tcurve->isIdentity()) customToneCurvebw1.Set(tcurve); delete tcurve; tcurve = NULL; @@ -404,7 +393,7 @@ void CurveFactory::curveCL ( bool & clcutili,const std::vector& clcurveP 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, const std::vector& lccurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, - LUTu & histogramC, LUTu & histogramLC, LUTu & histogramCroppedC, LUTu & outBeforeCCurveHistogram,LUTu & outBeforeLCurveHistogram, //for chroma + LUTu & histogramC, LUTu & histogramLC, LUTu & outBeforeCCurveHistogram,LUTu & outBeforeLCurveHistogram, //for chroma int skip) { @@ -414,7 +403,6 @@ void CurveFactory::curveCL ( bool & clcutili,const std::vector& clcurveP DiagonalCurve* dCurve = NULL; LUTf dCcurve(65536,0); - float val; for (int i=0; i<48000; i++) { //# 32768*1.414 approximation maxi for chroma dCcurve[i] = (float)i / 47999.0; } @@ -1058,14 +1046,5 @@ void ToneCurve::Set(Curve *pCurve) { lutToneCurve(65536); for (int i=0; i<65536; i++) lutToneCurve[i] = pCurve->getVal(double(i)/65535.) * 65535.; } -void ChMixerbw::Reset() { - lutBWCurve.reset(); -} - -// Fill a LUT with X/Y, ranged 0xffff -void ChMixerbw::Set(Curve *pCurve) { - lutBWCurve(65536); - for (int i=0; i<65536; i++) lutBWCurve[i] = pCurve->getVal(double(i)/65535.) * 65535.; -} } diff --git a/rtengine/curves.h b/rtengine/curves.h index 2401f792a..17efa202e 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -42,7 +42,6 @@ using namespace std; namespace rtengine { class ToneCurve; class ColorAppearance; - class ChMixerbw; class CurveFactory { @@ -187,26 +186,21 @@ class CurveFactory { LUTf & hlCurve, LUTf & shCurve,LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & outToneCurve, ToneCurve & outToneCurve2, int skip=1); - static void curveBW ( - procparams::BlackWhiteParams::eTCModeId curveModeb, const std::vector& curvePointsbw, - procparams::BlackWhiteParams::eTCModeId curveModeb2, const std::vector& curvePointsbw2, - LUTu & histogrambw, LUTu & histogramCropped, LUTu & outBeforeCCurveHistogrambw, - ChMixerbw & customToneCurvebw1, - ChMixerbw & customToneCurvebw2, - int skip); + static void curveBW (const std::vector& curvePointsbw, const std::vector& curvePointsbw2, LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw, + ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip); static void curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, LUTu & histogramcl, LUTu & outBeforeCLurveHistogram, int skip); static void complexsgnCurve ( bool & autili, bool & butili, bool & ccutili, bool & clcutili, double saturation, double rstprotection, const std::vector& acurvePoints, const std::vector& bcurvePoints,const std::vector& cccurvePoints,const std::vector& lccurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, - LUTu & histogramC, LUTu & histogramLC, LUTu & histogramCroppedC, LUTu & outBeforeCCurveHistogram,LUTu & outBeforeLCurveHistogram,///for chroma + LUTu & histogramC, LUTu & histogramLC, LUTu & outBeforeCCurveHistogram,LUTu & outBeforeLCurveHistogram,///for chroma 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 updatechroma ( const std::vector& cccurvePoints, - LUTu & histogramC, LUTu & histogramCroppedC, LUTu & outBeforeCCurveHistogramC,//for chroma + LUTu & histogramC, LUTu & outBeforeCCurveHistogramC,//for chroma int skip=1); static void curveLightBrightColor ( @@ -214,7 +208,7 @@ class CurveFactory { procparams::ColorAppearanceParams::eTCModeId curveMode2, const std::vector& curvePoints2, procparams::ColorAppearanceParams::eCTCModeId curveMode3, const std::vector& curvePoints3, LUTu & histogram, LUTu & histogramCropped, LUTu & outBeforeCCurveHistogram, - LUTu & histogramC, LUTu & histogramCroppedC, LUTu & outBeforeCCurveHistogramC, + LUTu & histogramC, LUTu & outBeforeCCurveHistogramC, ColorAppearance & outColCurve1, ColorAppearance & outColCurve2, ColorAppearance & outColCurve3, @@ -326,17 +320,6 @@ class ToneCurve { operator bool (void) const { return lutToneCurve; } }; -class ChMixerbw { - public: - LUTf lutBWCurve; // 0xffff range - - virtual ~ChMixerbw() {}; - - void Reset(); - void Set(Curve *pCurve); - operator bool (void) const { return lutBWCurve; } -}; - class ColorAppearance { public: LUTf lutColCurve; // 0xffff range @@ -417,7 +400,7 @@ class StandardToneCurve : public ToneCurve { public: void Apply(float& r, float& g, float& b) const; }; -class StandardToneCurvebw : public ChMixerbw { +class StandardToneCurvebw : public ToneCurve { public: void Apply(float& r, float& g, float& b) const; }; @@ -430,7 +413,7 @@ class AdobeToneCurve : public ToneCurve { void Apply(float& r, float& g, float& b) const; }; -class AdobeToneCurvebw : public ChMixerbw { +class AdobeToneCurvebw : public ToneCurve { private: void RGBTone(float& r, float& g, float& b) const; // helper for tone curve @@ -443,7 +426,7 @@ class SatAndValueBlendingToneCurve : public ToneCurve { void Apply(float& r, float& g, float& b) const; }; -class SatAndValueBlendingToneCurvebw : public ChMixerbw { +class SatAndValueBlendingToneCurvebw : public ToneCurve { public: void Apply(float& r, float& g, float& b) const; }; @@ -455,7 +438,7 @@ class WeightedStdToneCurve : public ToneCurve { void Apply(float& r, float& g, float& b) const; }; -class WeightedStdToneCurvebw : public ChMixerbw { +class WeightedStdToneCurvebw : public ToneCurve { private: float Triangle(float refX, float refY, float X2) const; public: @@ -474,11 +457,11 @@ inline void StandardToneCurve::Apply (float& r, float& g, float& b) const { // Standard tone curve inline void StandardToneCurvebw::Apply (float& r, float& g, float& b) const { - assert (lutBWCurve); + assert (lutToneCurve); - r = lutBWCurve[r]; - g = lutBWCurve[g]; - b = lutBWCurve[b]; + r = lutToneCurve[r]; + g = lutToneCurve[g]; + b = lutToneCurve[b]; } // Tone curve according to Adobe's reference implementation @@ -506,15 +489,15 @@ inline void AdobeToneCurve::Apply (float& r, float& g, float& b) const { } inline void AdobeToneCurvebw::Apply (float& r, float& g, float& b) const { - assert (lutBWCurve); + assert (lutToneCurve); 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 else if (b > g) RGBTone (r, b, g); // Case 3: r >= b > g else { // Case 4: r >= g == b - r = lutBWCurve[r]; - g = lutBWCurve[g]; + r = lutToneCurve[r]; + g = lutToneCurve[g]; b = g; } } @@ -535,8 +518,8 @@ inline void AdobeToneCurve::RGBTone (float& r, float& g, float& b) const { inline void AdobeToneCurvebw::RGBTone (float& r, float& g, float& b) const { float rold=r,gold=g,bold=b; - r = lutBWCurve[rold]; - b = lutBWCurve[bold]; + r = lutToneCurve[rold]; + b = lutToneCurve[bold]; g = b + ((r - b) * (gold - bold) / (rold - bold)); } @@ -586,17 +569,17 @@ inline void WeightedStdToneCurve::Apply (float& r, float& g, float& b) const { inline void WeightedStdToneCurvebw::Apply (float& r, float& g, float& b) const { - assert (lutBWCurve); + assert (lutToneCurve); - float r1 = lutBWCurve[r]; + float r1 = lutToneCurve[r]; float g1 = Triangle(r, r1, g); float b1 = Triangle(r, r1, b); - float g2 = lutBWCurve[g]; + float g2 = lutToneCurve[g]; float r2 = Triangle(g, g2, r); float b2 = Triangle(g, g2, b); - float b3 = lutBWCurve[b]; + float b3 = lutToneCurve[b]; float r3 = Triangle(b, b3, r); float g3 = Triangle(b, b3, g); @@ -638,12 +621,12 @@ inline void SatAndValueBlendingToneCurve::Apply (float& r, float& g, float& b) c inline void SatAndValueBlendingToneCurvebw::Apply (float& r, float& g, float& b) const { - assert (lutBWCurve); + assert (lutToneCurve); float h, s, v; float lum = (r+g+b)/3.f; //float lum = Color::rgbLuminance(r, g, b); - float newLum = lutBWCurve[lum]; + float newLum = lutToneCurve[lum]; if (newLum == lum) return; bool increase = newLum > lum; diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 36cde4bae..5eb33f12e 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -164,11 +164,13 @@ void Crop::update (int todo) { baseCrop->b[(int)(xref/skip)][(int)(yref/skip)]/256, parent->imgsrc->getGamma()); }*/ - double rrm, ggm, bbm; + double rrm, ggm, bbm; if (todo & M_RGBCURVE) parent->ipf.rgbProc (baseCrop, laboCrop, parent->hltonecurve, parent->shtonecurve, parent->tonecurve, cshmap, - params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, parent->customToneCurve1, parent->customToneCurve2, parent->customToneCurvebw1, parent->customToneCurvebw2,rrm, ggm, bbm); + params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, parent->customToneCurve1, + parent->customToneCurve2, parent->beforeToneCurveBW, parent->afterToneCurveBW,rrm, ggm, bbm, + parent->bwAutoR, parent->bwAutoG, parent->bwAutoB); /*xref=000;yref=000; if (colortest && cropw>115 && croph>115) @@ -245,11 +247,13 @@ void Crop::update (int todo) { if(settings->ciecamfloat) { float d; // not used after this block - parent->ipf.ciecam_02float (cieCrop, float(adap), begh, endh, 1, 2, labnCrop, ¶ms, parent->customColCurve1, parent->customColCurve2, parent->customColCurve3, dummy, dummy, 5, 1,(float**)cbuffer, execsharp, d); + parent->ipf.ciecam_02float (cieCrop, float(adap), begh, endh, 1, 2, labnCrop, ¶ms, parent->customColCurve1, parent->customColCurve2, parent->customColCurve3, + dummy, dummy, parent->CAMBrightCurveJ, parent->CAMBrightCurveQ, parent->CAMMean, 5, 1,(float**)cbuffer, execsharp, d); } else { double dd; // not used after this block - parent->ipf.ciecam_02 (cieCrop,adap, begh, endh, 1, 2, labnCrop, ¶ms, parent->customColCurve1, parent->customColCurve2, parent->customColCurve3, dummy, dummy, 5, 1,(float**)cbuffer, execsharp, dd); + parent->ipf.ciecam_02 (cieCrop,adap, begh, endh, 1, 2, labnCrop, ¶ms, parent->customColCurve1, parent->customColCurve2, parent->customColCurve3, + dummy, dummy, parent->CAMBrightCurveJ, parent->CAMBrightCurveQ, parent->CAMMean, 5, 1,(float**)cbuffer, execsharp, dd); } } else { @@ -465,10 +469,12 @@ bool Crop::tryUpdate() { /* @brief Handles Crop updating in its own thread * - * This method will cycle updates ss long as Crop::newUpdatePending will be true. During the processing, + * This method will cycle updates as long as Crop::newUpdatePending will be true. During the processing, * intermediary update will be automatically flushed by Crop::tryUpdate. + * + * This method is called when the visible part of the crop has changed (resize, zoom, etc..), so it needs a full update */ -void Crop::fullUpdate () { +void Crop::fullUpdate () { parent->updaterThreadStart.lock (); if (parent->updaterRunning && parent->thread) { diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 366f33ca9..789a20538 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -32,6 +32,7 @@ ImProcCoordinator::ImProcCoordinator () : orig_prev(NULL), oprevi(NULL), oprevl(NULL), nprevl(NULL), previmg(NULL), workimg(NULL), ncie(NULL), imgsrc(NULL), shmap(NULL), lastAwbEqual(0.), ipf(¶ms, true), scale(10), highDetailPreprocessComputed(false), highDetailRawComputed(false), allocated(false), + bwAutoR(-9000.f), bwAutoG(-9000.f), bwAutoB(-9000.f), CAMMean(0.f), hltonecurve(65536,0), shtonecurve(65536,2),//clip above @@ -47,26 +48,29 @@ ImProcCoordinator::ImProcCoordinator () vhist16(65536),vhist16bw(65536), lhist16(65536), lhist16Cropped(65536), lhist16CAM(65536), lhist16CroppedCAM(65536), - lhist16CCAM(65536), lhist16CroppedCCAM(65536), + lhist16CCAM(65536), lhist16CCAMAF(65536), lhist16ClabAF(65536), histCropped(65536), - lhist16Clad(65536),lhist16CroppedClad(65536),lhist16CLlad(65536), - lhist16LClad(65536), lhist16LLClad(65536), + lhist16Clad(65536),lhist16CLlad(65536), + lhist16LClad(65536), lhist16LLClad(65536), histRed(256), histRedRaw(256), histGreen(256), histGreenRaw(256), histBlue(256), histBlueRaw(256), - histLuma(256), histChroma(256), + histLuma(256), histToneCurve(256), histToneCurveBW(256), histLCurve(256), histCCurve(256), histCLurve(256), histLLCurve(256), - + histLCAM(256), histCCAM(256), histClad(256), bcabhist(256), + histChroma(256), + + CAMBrightCurveJ(), CAMBrightCurveQ(), rCurve(), gCurve(), @@ -117,6 +121,8 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { int numofphases = 14; int readyphase = 0; + bwAutoR = bwAutoG = bwAutoB = -9000.f; + if (todo==CROP && ipf.needsPCVignetting()) todo |= TRANSFORM; // Change about Crop does affect TRANSFORM @@ -298,20 +304,22 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, scale==1 ? 1 : 1); CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, scale==1 ? 1 : 1); - CurveFactory::curveBW (params.blackwhite.beforeCurveMode, params.blackwhite.beforeCurve, params.blackwhite.afterCurveMode, params.blackwhite.afterCurve, - vhist16bw, histCropped, histToneCurveBW, customToneCurvebw1, customToneCurvebw2,scale==1 ? 1 : 1); + CurveFactory::curveBW (params.blackwhite.beforeCurve,params.blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW,scale==1 ? 1 : 1); - //initialize rrm bbm ggm different from zero to avoid black screen in somme cases + //initialize rrm bbm ggm different from zero to avoid black screen in some cases double rrm=33.; double ggm=33.; double bbm=33.; - // if it's just crop we just need the histogram, no image updates if ( todo!=MINUPDATE ) { ipf.rgbProc (oprevi, oprevl, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, - rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2,customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm,params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); - if(params.blackwhite.enabled && abwListener) abwListener->BWChanged((float) rrm, (float) ggm, (float) bbm); + rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2,beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); + if(params.blackwhite.enabled && params.blackwhite.autoc && abwListener) { + if (settings->verbose) + printf("ImProcCoordinator / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", bwAutoR, bwAutoG, bwAutoB); + abwListener->BWChanged((float) rrm, (float) ggm, (float) bbm); + } // correct GUI black and white with value } @@ -319,13 +327,13 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { int x1, y1, x2, y2, pos, poscc; params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); lhist16.clear(); lhist16Cropped.clear(); - lhist16Clad.clear(); lhist16CroppedClad.clear();lhist16CLlad.clear();lhist16LLClad.clear(); + lhist16Clad.clear(); lhist16CLlad.clear();lhist16LLClad.clear(); lhist16ClabAF.clear(); for (int x=0; xL[x][y])); lhist16[pos]++; - if (y>=y1 && y=x1 && x=y1 && y=x1 && xCopyFrom(oprevl); @@ -408,7 +416,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { int x1, y1, x2, y2, pos, posc; params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); lhist16CAM.clear(); lhist16CroppedCAM.clear(); - lhist16CCAM.clear(); lhist16CroppedCCAM.clear(); + lhist16CCAM.clear(); lhist16CCAMAF.clear(); for (int x=0; xa[x][y]*nprevl->a[x][y] + nprevl->b[x][y]*nprevl->b[x][y])); if(!params.colorappearance.datacie) lhist16CCAM[posc]++; if(!params.colorappearance.datacie)lhist16CAM[pos]++; - if (y>=y1 && y=x1 && x=y1 && y=x1 && xciecamfloat){ - ipf.ciecam_02float (ncie, float(adap), begh, endh, pW, 2, nprevl, ¶ms, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1, (float**)buffer, execsharp, d); + ipf.ciecam_02float (ncie, float(adap), begh, endh, pW, 2, nprevl, ¶ms, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, (float**)buffer, execsharp, d); if(params.colorappearance.autodegree && acListener && params.colorappearance.enabled) acListener->autoCamChanged(100.*(double)d); if(params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) acListener->adapCamChanged(adap);//real value of adapt scene luminosity } else { - ipf.ciecam_02 (ncie, adap, begh, endh, pW, 2, nprevl, ¶ms, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, 5, 1, (float**)buffer, execsharp, dd); + ipf.ciecam_02 (ncie, adap, begh, endh, pW, 2, nprevl, ¶ms, customColCurve1,customColCurve2,customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, (float**)buffer, execsharp, dd); if(params.colorappearance.autodegree && acListener && params.colorappearance.enabled) acListener->autoCamChanged(100.*dd); if(params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) acListener->adapCamChanged(adap); } @@ -476,9 +488,12 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { readyphase++; } else { - // CIECAM is disbaled, we free up its image buffer to save some space + // CIECAM is disabled, we free up its image buffer to save some space if (ncie) delete ncie; ncie=NULL; + + if (CAMBrightCurveJ) CAMBrightCurveJ.reset(); + if (CAMBrightCurveQ) CAMBrightCurveQ.reset(); } } // process crop, if needed @@ -486,6 +501,11 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { if (crops[i]->hasListener () && cropCall != crops[i] ) crops[i]->update (todo); // may call ourselves + // Flagging some LUT as dirty now, whether they have been freed up or not + CAMBrightCurveJ.dirty = true; + CAMBrightCurveQ.dirty = true; + + progress ("Conversion to RGB...",100*readyphase/numofphases); if (todo!=CROP && todo!=MINUPDATE) { MyMutex::MyLock prevImgLock(previmg->getMutex()); diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index c8a290639..2fbf63009 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -77,6 +77,11 @@ class ImProcCoordinator : public StagedImageProcessor { void freeAll (); + // Precomputed values used by DetailedCrop ---------------------------------------------- + + float bwAutoR, bwAutoG, bwAutoB; + float CAMMean; + LUTf hltonecurve; LUTf shtonecurve; LUTf tonecurve; @@ -91,15 +96,18 @@ class ImProcCoordinator : public StagedImageProcessor { LUTu vhist16,vhist16bw; LUTu lhist16,lhist16Cropped; LUTu lhist16CAM,lhist16CroppedCAM; - LUTu lhist16CCAM,lhist16CroppedCCAM; + LUTu lhist16CCAM; LUTu lhist16CCAMAF; LUTu lhist16ClabAF; LUTu histCropped; - LUTu lhist16Clad,lhist16CroppedClad,lhist16CLlad,lhist16LClad,lhist16LLClad; + LUTu lhist16Clad,lhist16CLlad,lhist16LClad,lhist16LLClad; LUTu histRed, histRedRaw; LUTu histGreen, histGreenRaw; LUTu histBlue, histBlueRaw; - LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve, histCLurve, histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma; + LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve, histCLurve; + LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma; + + LUTf CAMBrightCurveJ, CAMBrightCurveQ; LUTf rCurve; LUTf gCurve; @@ -116,13 +124,15 @@ class ImProcCoordinator : public StagedImageProcessor { ColorAppearance customColCurve1; ColorAppearance customColCurve2; ColorAppearance customColCurve3; - ChMixerbw customToneCurvebw1; - ChMixerbw customToneCurvebw2; + ToneCurve beforeToneCurveBW; + ToneCurve afterToneCurveBW; LUTu rcurvehist, rcurvehistCropped, rbeforehist; LUTu gcurvehist, gcurvehistCropped, gbeforehist; LUTu bcurvehist, bcurvehistCropped, bbeforehist; + // ------------------------------------------------------------------------------------ + int fw, fh, tr, fullw, fullh; int pW, pH; @@ -131,7 +141,7 @@ class ImProcCoordinator : public StagedImageProcessor { AutoExpListener* aeListener; AutoCamListener* acListener; AutoBWListener* abwListener; - + HistogramListener* hListener; std::vector sizeListeners; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 2d81c4d8b..07e7e846a 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -63,11 +63,11 @@ namespace rtengine { extern const Settings* settings; -LUTf ImProcFunctions::cachef ; -LUTf ImProcFunctions::gamma2curve = 0; +LUTf ImProcFunctions::cachef; +LUTf ImProcFunctions::gamma2curve; void ImProcFunctions::initCache () { - int maxindex = 65536; + const int maxindex = 65536; cachef(maxindex,0/*LUT_CLIP_BELOW*/); gamma2curve(maxindex,0); @@ -233,7 +233,9 @@ void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* par } // Copyright (c) 2012 Jacques Desmis -void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh, int pW, int pwb, LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2,const ColorAppearance & customColCurve3, LUTu & histLCAM, LUTu & histCCAM, int Iterates, int scale, float** buffer, bool execsharp, double &d) +void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh, int pW, int pwb, LabImage* lab, const ProcParams* params , + const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2,const ColorAppearance & customColCurve3, + LUTu & histLCAM, LUTu & histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, float** buffer, bool execsharp, double &d) { if(params->colorappearance.enabled) { @@ -241,28 +243,34 @@ if(params->colorappearance.enabled) { MyTime t1e,t2e; t1e.set(); #endif - LUTf dLcurve(65536,0); - LUTu hist16JCAM(65536); + LUTf dLcurve; + LUTu hist16JCAM; bool jp=false; float val; //preparate for histograms CIECAM if(pW!=1){//only with improccoordinator - for (int i=0; i<32768; i++) { //# 32768*1.414 approximation maxi for chroma + dLcurve(65536,0); + dLcurve.clear(); + hist16JCAM(65536,0); + hist16JCAM.clear(); + for (int i=0; i<32768; i++) { //# 32768*1.414 approximation maxi for chroma val = (double)i / 32767.0; dLcurve[i] = CLIPD(val); } - hist16JCAM.clear(); } - LUTf dCcurve(65536,0); - LUTu hist16_CCAM(65536); + LUTf dCcurve; + LUTu hist16_CCAM; bool chropC=false; float valc; + if(pW!=1){//only with improccoordinator - for (int i=0; i<48000; i++) { //# 32768*1.414 approximation maxi for chroma + dCcurve(65536,0); + hist16_CCAM(65536); + hist16_CCAM.clear(); + for (int i=0; i<48000; i++) { //# 32768*1.414 approximation maxi for chroma valc = (double)i / 47999.0; dCcurve[i] = CLIPD(valc); } - hist16_CCAM.clear(); } //end preparate histogram int width = lab->W, height = lab->H; @@ -283,47 +291,6 @@ if(params->colorappearance.enabled) { int alg=0; bool algepd=false; float sum=0.f; - float mean; - //LUTf for sliders J and Q - LUTf bright_curve (65536,0);//init curve - LUTf bright_curveQ (65536,0);//init curve - - LUTu hist16J (65536); - LUTu hist16Q (65536); - float koef=1.0f;//rough correspondence between L and J - hist16J.clear();hist16Q.clear(); - for (int i=0; iL[i][j])/327.68f)>95.) koef=1.f; - else if(((lab->L[i][j])/327.68f)>85.) koef=0.97f; - else if(((lab->L[i][j])/327.68f)>80.) koef=0.93f; - else if(((lab->L[i][j])/327.68f)>70.) koef=0.87f; - else if(((lab->L[i][j])/327.68f)>60.) koef=0.85f; - else if(((lab->L[i][j])/327.68f)>50.) koef=0.8f; - else if(((lab->L[i][j])/327.68f)>40.) koef=0.75f; - else if(((lab->L[i][j])/327.68f)>30.) koef=0.7f; - else if(((lab->L[i][j])/327.68f)>20.) koef=0.7f; - else if(((lab->L[i][j])/327.68f)>10.) koef=0.9f; - else if(((lab->L[i][j])/327.68f)>0.) koef=1.0f; - - hist16J[CLIP((int)((koef*lab->L[i][j])))]++;//evaluate histogram luminance L # J - sum+=koef*lab->L[i][j];//evaluate mean J to calcualte Yb - hist16Q[CLIP((int) (32768.f*sqrt((koef*(lab->L[i][j]))/32768.f)))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L - } - //mean=(sum/((endh-begh)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone - mean=(sum/((height)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone - if (mean<15.f) yb=3.0; - else if(mean<30.f) yb=5.0; - else if(mean<40.f) yb=10.0; - else if(mean<45.f) yb=15.0; - else if(mean<50.f) yb=18.0; - else if(mean<55.f) yb=23.0; - else if(mean<60.f) yb=30.0; - else if(mean<70.f) yb=40.0; - else if(mean<80.f) yb=60.0; - else if(mean<90.f) yb=80.0; - else yb=90.0; bool ciedata=params->colorappearance.datacie; @@ -341,6 +308,9 @@ if(params->colorappearance.enabled) { else if(params->colorappearance.algo=="JS") alg=1; else if(params->colorappearance.algo=="QM") {alg=2;algepd=true;} else if(params->colorappearance.algo=="ALL") {alg=3;algepd=true;} + + bool needJ = (alg==0 || alg==1 || alg==3); + bool needQ = (alg==2 || 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 @@ -394,10 +364,71 @@ if(params->colorappearance.enabled) { bool hasColCurve3 = bool(customColCurve3); + if(CAMBrightCurveJ.dirty || CAMBrightCurveQ.dirty){ + LUTu hist16J; + LUTu hist16Q; + if (needJ) { + hist16J (65536); + hist16J.clear(); + } + if (needQ) { + hist16Q (65536); + hist16Q.clear(); + } + float koef=1.0f;//rough correspondence between L and J + for (int i=0; iL[i][j]/327.68f; + if (currL>95.) koef=1.f; + else if(currL>85.) koef=0.97f; + else if(currL>80.) koef=0.93f; + else if(currL>70.) koef=0.87f; + else if(currL>60.) koef=0.85f; + else if(currL>50.) koef=0.8f; + else if(currL>40.) koef=0.75f; + else if(currL>30.) koef=0.7f; + else if(currL>20.) koef=0.7f; + else if(currL>10.) koef=0.9f; + else if(currL>0.) koef=1.0f; + + if (needJ) + hist16J[CLIP((int)((koef*lab->L[i][j])))]++;//evaluate histogram luminance L # J + if (needQ) + 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 + sum+=koef*lab->L[i][j];//evaluate mean J to calcualte Yb + } + //mean=(sum/((endh-begh)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone + mean=(sum/((height)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone + + //evaluate lightness, contrast + if (needJ) { + if (!CAMBrightCurveJ) { + CAMBrightCurveJ(65536,0); + CAMBrightCurveJ.dirty = false; + } + ColorTemp::curveJ (jli, contra, 1, CAMBrightCurveJ, hist16J);//lightness and contrast J + } + if (needQ) { + if (!CAMBrightCurveQ) { + CAMBrightCurveQ(65536,0); + CAMBrightCurveQ.dirty = false; + } + ColorTemp::curveJ (qbri, qcontra, 1, CAMBrightCurveQ, hist16Q);//brightness and contrast Q + } + } + 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; - //evaluate lightness, contrast - ColorTemp::curveJ (jli, contra, 1, bright_curve,hist16J);//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 @@ -476,7 +507,7 @@ if(params->colorappearance.enabled) { // 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 + Jpro=(CAMBrightCurveJ[(float)(Jpro*327.68)])/327.68;//ligthness CIECAM02 + contrast double sres; double Sp=spro/100.0; double parsat=1.5; @@ -496,7 +527,7 @@ if(params->colorappearance.enabled) { } 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 + if(alg==3 || alg==2) Qpro=(CAMBrightCurveQ[(float)(Qpro*coef)])/coef;//brightness and contrast double Mp, sres; double coe=pow(fl,0.25); Mp=Mpro/100.0; @@ -514,7 +545,7 @@ if(params->colorappearance.enabled) { 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 + if(alg!=2) Jpro=(CAMBrightCurveJ[(float)(Jpro*327.68)])/327.68;//ligthness CIECAM02 + contrast double Cp; double Sp=spro/100.0; parsat=1.5; @@ -1036,7 +1067,9 @@ if((params->colorappearance.tonecie || (params->colorappearance.tonecie && param // Copyright (c) 2012 Jacques Desmis -void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int endh, int pW, int pwb, LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2,const ColorAppearance & customColCurve3, LUTu & histLCAM, LUTu & histCCAM, int Iterates, int scale, float** buffer, bool execsharp, float &d) +void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int endh, int pW, int pwb, LabImage* lab, const ProcParams* params, + const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve2,const ColorAppearance & customColCurve3, + LUTu & histLCAM, LUTu & histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, float** buffer, bool execsharp, float &d) { if(params->colorappearance.enabled) { //printf("ciecam float\n"); @@ -1044,17 +1077,20 @@ if(params->colorappearance.enabled) { MyTime t1e,t2e; t1e.set(); #endif - LUTf dLcurve(65536,0); - LUTu hist16JCAM(65536); + LUTf dLcurve; + LUTu hist16JCAM; bool jp=false; float val; //preparate for histograms CIECAM if(pW!=1){//only with improccoordinator - for (int i=0; i<32768; i++) { //# 32768*1.414 approximation maxi for chroma + dLcurve(65536, 0); + dLcurve.clear(); + hist16JCAM(65536); + hist16JCAM.clear(); + for (int i=0; i<32768; i++) { //# 32768*1.414 approximation maxi for chroma val = (double)i / 32767.0; dLcurve[i] = CLIPD(val); } - hist16JCAM.clear(); } LUTf dCcurve(65536,0); LUTu hist16_CCAM(65536); @@ -1062,11 +1098,11 @@ if(params->colorappearance.enabled) { float valc; if(pW!=1){//only with improccoordinator - for (int i=0; i<48000; i++) { //# 32768*1.414 approximation maxi for chroma + for (int i=0; i<48000; i++) { //# 32768*1.414 approximation maxi for chroma valc = (double)i / 47999.0; dCcurve[i] = CLIPD(valc); } - hist16_CCAM.clear(); + hist16_CCAM.clear(); } //end preparate histogram int width = lab->W, height = lab->H; @@ -1087,47 +1123,6 @@ if(params->colorappearance.enabled) { int alg=0; bool algepd=false; float sum=0.f; - float mean; - //LUTf for sliders J and Q - LUTf bright_curve (65536,0);//init curve - LUTf bright_curveQ (65536,0);//init curve - - LUTu hist16J (65536); - LUTu hist16Q (65536); - float koef=1.0f;//rough correspondence between L and J - hist16J.clear();hist16Q.clear(); - for (int i=0; iL[i][j])/327.68f)>95.) koef=1.f; - else if(((lab->L[i][j])/327.68f)>85.) koef=0.97f; - else if(((lab->L[i][j])/327.68f)>80.) koef=0.93f; - else if(((lab->L[i][j])/327.68f)>70.) koef=0.87f; - else if(((lab->L[i][j])/327.68f)>60.) koef=0.85f; - else if(((lab->L[i][j])/327.68f)>50.) koef=0.8f; - else if(((lab->L[i][j])/327.68f)>40.) koef=0.75f; - else if(((lab->L[i][j])/327.68f)>30.) koef=0.7f; - else if(((lab->L[i][j])/327.68f)>20.) koef=0.7f; - else if(((lab->L[i][j])/327.68f)>10.) koef=0.9f; - else if(((lab->L[i][j])/327.68f)>0.) koef=1.0f; - - hist16J[CLIP((int)((koef*lab->L[i][j])))]++;//evaluate histogram luminance L # J - sum+=koef*lab->L[i][j];//evaluate mean J to calcualte Yb - hist16Q[CLIP((int) (32768.f*sqrt((koef*(lab->L[i][j]))/32768.f)))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L - } - //mean=(sum/((endh-begh)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone - mean=(sum/((height)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone - if (mean<15.f) yb=3.0f; - else if(mean<30.f) yb=5.0f; - else if(mean<40.f) yb=10.0f; - else if(mean<45.f) yb=15.0f; - else if(mean<50.f) yb=18.0f; - else if(mean<55.f) yb=23.0f; - else if(mean<60.f) yb=30.0f; - else if(mean<70.f) yb=40.0f; - else if(mean<80.f) yb=60.0f; - else if(mean<90.f) yb=80.0f; - else yb=90.0f; bool ciedata=params->colorappearance.datacie; @@ -1140,11 +1135,14 @@ if(params->colorappearance.enabled) { //scene condition for surround if(params->colorappearance.surrsource==true) {f = 0.85f; c = 0.55f; nc = 0.85f;}// if user => source image has surround very dark - //with which algorithme + //with which algorithm if (params->colorappearance.algo=="JC") alg=0; else if(params->colorappearance.algo=="JS") alg=1; else if(params->colorappearance.algo=="QM") {alg=2;algepd=true;} else if(params->colorappearance.algo=="ALL") {alg=3;algepd=true;} + + bool needJ = (alg==0 || alg==1 || alg==3); + bool needQ = (alg==2 || alg==3); //settings white point of output device - or illuminant viewing if(settings->viewingdevice==0) {xwd=96.42f;ywd=100.0f;zwd=82.52f;}//5000K else if(settings->viewingdevice==1) {xwd=95.68f;ywd=100.0f;zwd=92.15f;}//5500 @@ -1198,10 +1196,71 @@ if(params->colorappearance.enabled) { bool hasColCurve3 = bool(customColCurve3); + if(CAMBrightCurveJ.dirty || CAMBrightCurveQ.dirty){ + LUTu hist16J; + LUTu hist16Q; + if (needJ) { + hist16J (65536); + hist16J.clear(); + } + if (needQ) { + hist16Q (65536); + hist16Q.clear(); + } + float koef=1.0f;//rough correspondence between L and J + for (int i=0; iL[i][j]/327.68f; + if (currL>95.) koef=1.f; + else if(currL>85.) koef=0.97f; + else if(currL>80.) koef=0.93f; + else if(currL>70.) koef=0.87f; + else if(currL>60.) koef=0.85f; + else if(currL>50.) koef=0.8f; + else if(currL>40.) koef=0.75f; + else if(currL>30.) koef=0.7f; + else if(currL>20.) koef=0.7f; + else if(currL>10.) koef=0.9f; + else if(currL>0.) koef=1.0f; + + if (needJ) + hist16J[CLIP((int)((koef*lab->L[i][j])))]++;//evaluate histogram luminance L # J + if (needQ) + 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 + sum+=koef*lab->L[i][j];//evaluate mean J to calculate Yb + } + //mean=(sum/((endh-begh)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone + mean=(sum/((height)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone + + //evaluate lightness, contrast + if (needJ) { + if (!CAMBrightCurveJ) { + CAMBrightCurveJ(65536,0); + CAMBrightCurveJ.dirty = false; + } + ColorTemp::curveJfloat (jli, contra, 1, CAMBrightCurveJ, hist16J);//lightness and contrast J + } + if (needQ) { + if (!CAMBrightCurveQ) { + CAMBrightCurveQ(65536,0); + CAMBrightCurveQ.dirty = false; + } + ColorTemp::curveJfloat (qbri, qcontra, 1, CAMBrightCurveQ, hist16Q);//brightness and contrast Q + } + } + if (mean<15.f) yb=3.0f; + else if(mean<30.f) yb=5.0f; + else if(mean<40.f) yb=10.0f; + else if(mean<45.f) yb=15.0f; + else if(mean<50.f) yb=18.0f; + else if(mean<55.f) yb=23.0f; + else if(mean<60.f) yb=30.0f; + else if(mean<70.f) yb=40.0f; + else if(mean<80.f) yb=60.0f; + else if(mean<90.f) yb=80.0f; + else yb=90.0f; - //evaluate lightness, contrast - ColorTemp::curveJfloat (jli, contra, 1, bright_curve,hist16J);//lightness and contrast J - ColorTemp::curveJfloat (qbri, qcontra, 1, bright_curveQ, hist16Q);//brightness and contrast Q int gamu=0; bool highlight = params->hlrecovery.enabled; //Get the value if "highlight reconstruction" is activated @@ -1277,7 +1336,7 @@ if(params->colorappearance.enabled) { // we cannot have all algoritms with all chroma curves if(alg==1) { // Lightness saturation - Jpro=(bright_curve[(float)(Jpro*327.68f)])/327.68f;//ligthness CIECAM02 + contrast + Jpro=(CAMBrightCurveJ[(float)(Jpro*327.68f)])/327.68f;//ligthness CIECAM02 + contrast float sres; float Sp=spro/100.0f; float parsat=1.5f; @@ -1297,7 +1356,7 @@ if(params->colorappearance.enabled) { } else if(alg==3 || alg==0 || alg==2) { float coef=32760.f/wh; - if(alg==3 || alg==2) Qpro=(bright_curveQ[(float)(Qpro*coef)])/coef;//brightness and contrast + if(alg==3 || alg==2) Qpro=(CAMBrightCurveQ[(float)(Qpro*coef)])/coef;//brightness and contrast float Mp, sres; float coe=pow_F(fl,0.25f); Mp=Mpro/100.0f; @@ -1315,7 +1374,7 @@ if(params->colorappearance.enabled) { Jpro=(100.0f* Qpro*Qpro) /(wh*wh); Cpro= Mpro/coe; spro = 100.0f * sqrt( Mpro / Qpro ); - if(alg!=2) Jpro=(bright_curve[(float)(Jpro*327.68f)])/327.68f;//ligthness CIECAM02 + contrast + if(alg!=2) Jpro=(CAMBrightCurveJ[(float)(Jpro*327.68f)])/327.68f;//ligthness CIECAM02 + contrast float Cp; float Sp=spro/100.0f; parsat=1.5f; @@ -1812,31 +1871,19 @@ if((params->colorappearance.tonecie && (params->edgePreservingDecompositionUI.en } } - hist16JCAM.reset(); - hist16_CCAM.reset(); - dLcurve.reset(); - dCcurve.reset(); - bright_curve.reset(); - bright_curveQ.reset(); - hist16J.reset(); - hist16Q.reset(); - } } //end CIECAM 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, const ChMixerbw & customToneCurvebw1,const ChMixerbw & customToneCurvebw2, double &rrm, double &ggm, double &bbm ) { - rgbProc (working, lab, hltonecurve, shtonecurve, tonecurve, shmap, sat, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2,rrm, ggm, bbm, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh); + const ToneCurve & customToneCurve1,const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1,const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob ) { + rgbProc (working, lab, hltonecurve, shtonecurve, tonecurve, shmap, sat, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2,rrm, ggm, bbm, autor, autog, autob, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh); } // Process RGB image and convert to LAB space 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, const ChMixerbw & customToneCurvebw1,const ChMixerbw & customToneCurvebw2,double &rrm, double &ggm, double &bbm, double expcomp, int hlcompr, int hlcomprthresh) { - - - + const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1,const ToneCurve & customToneCurvebw2,double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh) { LUTf iGammaLUTf; Imagefloat *tmpImage = working->copy(); @@ -1852,6 +1899,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone double lceamount = params->sh.localcontrast / 200.0; TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); + TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); double toxyz[3][3] = { { @@ -1869,7 +1917,6 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone } }; - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); //inverse matrix user select double wip[3][3] = { {wiprof[0][0],wiprof[0][1],wiprof[0][2]}, @@ -1877,6 +1924,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone {wiprof[2][0],wiprof[2][1],wiprof[2][2]} }; + double wp[3][3] = { + {wprof[0][0],wprof[0][1],wprof[0][2]}, + {wprof[1][0],wprof[1][1],wprof[1][2]}, + {wprof[2][0],wprof[2][1],wprof[2][2]}}; + + bool mixchannels = (params->chmixer.red[0]!=100 || params->chmixer.red[1]!=0 || params->chmixer.red[2]!=0 || params->chmixer.green[0]!=0 || params->chmixer.green[1]!=100 || params->chmixer.green[2]!=0 || params->chmixer.blue[0]!=0 || params->chmixer.blue[1]!=0 || params->chmixer.blue[2]!=100); @@ -1889,11 +1942,6 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone FlatCurve* vCurve; FlatCurve* bwlCurve; - - float* cossq = new float [8192]; - for (int i=0; i<8192; i++) - cossq[i] = SQR(cos(pi*(float)i/16384.0)); - FlatCurveType hCurveType = (FlatCurveType)params->hsvequalizer.hcurve.at(0); FlatCurveType sCurveType = (FlatCurveType)params->hsvequalizer.scurve.at(0); FlatCurveType vCurveType = (FlatCurveType)params->hsvequalizer.vcurve.at(0); @@ -1907,7 +1955,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone if (hCurveEnabled) hCurve = new FlatCurve(params->hsvequalizer.hcurve); if (sCurveEnabled) sCurve = new FlatCurve(params->hsvequalizer.scurve); if (vCurveEnabled) vCurve = new FlatCurve(params->hsvequalizer.vcurve); - if (bwlCurveEnabled) bwlCurve = new FlatCurve(params->blackwhite.luminanceCurve); + if (bwlCurveEnabled) { + bwlCurve = new FlatCurve(params->blackwhite.luminanceCurve); + if (bwlCurve->isIdentity()) { + delete bwlCurve; + bwlCurve = NULL; + bwlCurveEnabled = false; + } + } const float exp_scale = pow (2.0, expcomp); const float comp = (max(0.0, expcomp) + 1.0)*hlcompr/100.0; @@ -1953,11 +2008,15 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone if (params->blackwhite.method=="Desaturation") algm=0; else if(params->blackwhite.method=="LumEqualizer") algm=1; else if(params->blackwhite.method=="ChannelMixer") algm=2; - //gamma correction of each channel + float kcorec=1.f; + //gamma correction of each channel float gamvalr=125.f; float gamvalg=125.f; float gamvalb=125.f; - float autor,autog,autob; + double nr=0; + double ng=0; + double nb=0; + bool computeMixerAuto = params->blackwhite.autoc && (autor < -5000.f); if(bwrgam < 0) gamvalr=100.f; if(bwggam < 0) gamvalg=100.f; if(bwbgam < 0) gamvalb=100.f; @@ -2314,9 +2373,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone } } -//if (sat!=0 || hCurveEnabled || sCurveEnabled || vCurveEnabled) { -if (sat> -110 || hCurveEnabled || sCurveEnabled || vCurveEnabled) { - if(algm==1 && blackwhite /* && bwlCurveEnabled*/) sat= -75;//increase effect of luminance mixer bw +if (sat!=0 || hCurveEnabled || sCurveEnabled || vCurveEnabled) { #ifdef _OPENMP #pragma omp for schedule(dynamic, 5) #endif @@ -2328,14 +2385,12 @@ if (sat> -110 || hCurveEnabled || sCurveEnabled || vCurveEnabled) { float b = tmpImage->b(i,j); float h,s,v; Color::rgb2hsv(r,g,b,h,s,v); - if (sat > 0.5f) { + if (sat > 0) { s = (1.f-float(sat)/100.f)*s+float(sat)/100.f*(1.f-SQR(SQR(1.f-min(s,1.0f)))); - if (s<0) s=0.f; - } else { - if (sat < -0.5) - s *= 1.f+float(sat)/100.f; - } - + if (s<0.f) s=0.f; + } else /*if (sat < 0)*/ + s *= 1.f+float(sat)/100.f; + //HSV equalizer if (hCurveEnabled) { h = (hCurve->getVal(double(h)) - 0.5) * 2.f + h; @@ -2350,10 +2405,8 @@ if (sat> -110 || hCurveEnabled || sCurveEnabled || vCurveEnabled) { if (satparam > 0.00001f) { s = (1.f-satparam)*s+satparam*(1.f-SQR(1.f-min(s,1.0f))); if (s<0.f) s=0.f; - } else { - if (satparam < -0.00001f) - s *= 1.f+satparam; - } + } else if (satparam < -0.00001f) + s *= 1.f+satparam; } if (vCurveEnabled) { @@ -2433,10 +2486,8 @@ if(blackwhite){ } } } -} - -if (algm==0 && blackwhite){//desaturated + if (algm==0){//lightness #ifdef _OPENMP #pragma omp for schedule(dynamic, 5) #endif @@ -2446,16 +2497,99 @@ if (algm==0 && blackwhite){//desaturated float r = tmpImage->r(i,j); float g = tmpImage->g(i,j); float b = tmpImage->b(i,j); - float lum = (0.299f*r+0.587f*g + 0.114f*b); - tmpImage->r(i,j)= lum; - tmpImage->g(i,j)=tmpImage->r(i,j); - tmpImage->b(i,j)=tmpImage->r(i,j); - if (hasgammabw) Color::trcGammaBW (tmpImage->r(i,j), tmpImage->g(i,j), tmpImage->b(i,j), gammabwr, gammabwg, gammabwb); - } - } -} -if (algm==1 && blackwhite && (bwlCurveEnabled || hasgammabw)) {//Luminance mixer + // -------------------------------------------------- + + // Method 1: Luminosity (code taken from Gimp) + /* + float maxi = max(r, g, b); + float mini = min(r, g, b); + r = g = b = (maxi+mini)/2; + */ + + // Method 2: Luminance (former RT code) + r = g = b = (0.299f*r + 0.587f*g + 0.114f*b); + + // -------------------------------------------------- + + //gamma correction: pseudo TRC curve + if (hasgammabw) Color::trcGammaBW (r, g, b, gammabwr, gammabwg, gammabwb); + + tmpImage->r(i,j) = r; + tmpImage->g(i,j) = g; + tmpImage->b(i,j) = b; + } + } + } + + else if (algm==1) {//Luminance mixer in Lab mode to avoid artifacts + +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ihlrecovery.enabled;//Get the value if "highlight reconstruction" is activated + //rgb=>lab + float r = tmpImage->r(i,j); + float g = tmpImage->g(i,j); + float b = tmpImage->b(i,j); + float X,Y,Z; + float L,aa,bb; + Color::rgbxyz(r,g,b,X,Y,Z,wp); + //convert Lab + Color::XYZ2Lab(X, Y, Z, L, aa, bb); + //end rgb=>lab + //lab ==> Ch + float CC=sqrt(SQR(aa/327.68f) + SQR(bb/327.68f));//CC chromaticity in 0..180 or more + float HH=xatan2f(bb,aa);// HH hue in -3.141 +3.141 + float l_r;//Luminance Lab in 0..1 + l_r = L/32768.f; + if (bwlCurveEnabled) { + double hr; + Color::huelab_to_huehsv (HH, hr);//correspondance H lab ==> h hsv + float valparam = float((bwlCurve->getVal(hr)-0.5f) * 2.0f);//get l_r=f(H) + float kcc=(CC/70.f);//take Chroma into account...70 "middle" of chromaticity (arbitrary and simple), one can imagine other algorithme + //reduct action for low chroma and increase action for high chroma + valparam *= kcc; + if(valparam > 0.f) { l_r = (1.f-valparam)*l_r+ valparam*(1.f-SQR(SQR(SQR(SQR(1.f-min(l_r,1.0f))))));}// SQR (SQR((SQR) to increase action in low light + else l_r *= (1.f + 2.f*valparam);//for negative + } + L=l_r*32768.f; + float RR,GG,BB; + float Lr; + Lr=L/327.68f;//for gamutlch +#ifdef _DEBUG + bool neg=false; + bool more_rgb=false; + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH,Lr,CC, RR, GG, BB, wip, highlight, 0.15f, 0.96f, neg, more_rgb); +#else + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH,Lr,CC, RR, GG, BB, wip, highlight, 0.15f, 0.96f); +#endif + //convert CH ==> ab + L=Lr*327.68f; + float a_,b_; + a_=0.f;//grey + b_=0.f;//grey + //convert lab=>rgb + Color::Lab2XYZ(L, a_, b_, X, Y, Z); + float rr_,gg_,bb_; + Color::xyz2rgb(X,Y,Z,rr_,gg_,bb_,wip); + + //gamma correction: pseudo TRC curve + if (hasgammabw) Color::trcGammaBW (rr_, gg_, bb_, gammabwr, gammabwg, gammabwb); + tmpImage->r(i,j)=rr_; + tmpImage->g(i,j)=gg_; + tmpImage->b(i,j)=bb_; + } + } + } + + +/* + else if (algm==1) {//Luminance mixer #ifdef _OPENMP #pragma omp for schedule(dynamic, 5) #endif @@ -2465,7 +2599,6 @@ if (algm==1 && blackwhite && (bwlCurveEnabled || hasgammabw)) {//Luminance mixer float g = tmpImage->g(i,j); float b = tmpImage->b(i,j); if (bwlCurveEnabled) { - float lum; float h,s,v; Color::rgb2hsv(r,g,b,h,s,v); if (v<0) v=0; @@ -2473,204 +2606,127 @@ if (algm==1 && blackwhite && (bwlCurveEnabled || hasgammabw)) {//Luminance mixer valparam *= (1.f-(SQR(SQR(1.f-min(s,1.0f))))); //float valcor=1.f/(0.501f-valparam); - if (valparam > 0.00001f) { - // v = (1.f-valparam)*v+ valparam*(1.f-(SQR(SQR(1.f-min(v,1.0f)))));// SQR (SQR to increase action and avoid artefacts, but there's always a little - // v = (1.f-valparam)*v+ valparam*(1.f- pow((1.f-min(v,1.0f)), 2.f+valcor));//(SQR(SQR(1.f-min(v,1.0f)))));// SQR (SQR to increase action and avoid artefacts, but there's always a little + if (valparam < -0.00001f || valparam > 0.00001f) v *= (1.f + 4.f*valparam); - } else { - if (valparam < -0.00001f) - {v *= (1.f + 4.f*valparam);//4to increase action - } - } - CLIPD(v); - Color::hsv2rgb(h, s, v, tmpImage->r(i,j), tmpImage->g(i,j), tmpImage->b(i,j)); - lum = (0.299f*tmpImage->r(i,j)+0.587f*tmpImage->g(i,j)+ 0.114f*tmpImage->b(i,j));// get luminance - tmpImage->r(i,j)=lum;//black and white - tmpImage->g(i,j)=lum; - tmpImage->b(i,j)=lum; + v = CLIPD(v); + Color::hsv2rgb(h, s, v, r, g, b); } - //correction gamma : pseudo TRC curve - if (hasgammabw) Color::trcGammaBW (tmpImage->r(i,j), tmpImage->g(i,j), tmpImage->b(i,j), gammabwr, gammabwg, gammabwb); - } - } -} + // get luminance + r = g = b = (0.2126f*r + 0.7152f*g + 0.0722f*b); // (constant taken from Gimp, see https://git.gnome.org/browse/gimp/tree/libgimpcolor/gimprgb.h) + //r = g = b = (0.299f*r + 0.587f*g + 0.114f*b); // (obsolete constant) -if (algm==2 && blackwhite) {//channel-mixer - if (params->blackwhite.autoc) { - // auto channel-mixer - float nr=0.f; - float ng=0.f; - float nb=0.f; -#ifdef _OPENMP -#pragma omp for schedule(dynamic, 5) -#endif - for (int i=0; ir(i,j); - float gg = tmpImage->g(i,j); - float bb = tmpImage->b(i,j); - nr+=rr; - ng+=gg; - nb+=bb; - float srgb; - srgb = nr+ng+nb; - float knr=nr/srgb; - float kng=ng/srgb; - float knb=nb/srgb; - knr = 1.f/knr; - kng = 1.f/kng; - knb = 1.f/knb; - float sk; - sk=knr+kng+knb; - knr=100.f*knr/sk; - kng=100.f*kng/sk; - knb=100.f*knb/sk; - autor=knr; - autog=kng; - autob=knb; + //gamma correction: pseudo TRC curve + if (hasgammabw) Color::trcGammaBW (r, g, b, gammabwr, gammabwg, gammabwb); + + tmpImage->r(i,j) = r; + tmpImage->g(i,j) = g; + tmpImage->b(i,j) = b; } } } - //end auto chmix - float som, somm; - float rM,gM,bM; - som=bwr+bwg+bwb; - float mix[3][3]; - float val[3]; - float in[3]; - float kcorec=1.f; - //presets - if (params->blackwhite.setting=="RGB-Abs" || params->blackwhite.setting=="ROYGCBMP-Abs") {rM=bwr;gM=bwg;bM=bwb;kcorec=som/100.f;} - else if(params->blackwhite.setting=="RGB-Rel" || params->blackwhite.setting=="ROYGCBMP-Rel") {rM=bwr;gM=bwg;bM=bwb;} - else if(params->blackwhite.setting=="NormalContrast") {rM=43.f ;gM=33.f; bM=30.f;} - else if(params->blackwhite.setting=="Panchromatic") {rM=33.3f;gM=33.3f;bM=33.3f;} - else if(params->blackwhite.setting=="HyperPanchromatic") {rM=41.f ;gM=25.f; bM=34.f;} - else if(params->blackwhite.setting=="LowSensitivity") {rM=27.f ;gM=27.f; bM=46.f;} - else if(params->blackwhite.setting=="HighSensitivity") {rM=30.f ;gM=28.f; bM=42.f;} - else if(params->blackwhite.setting=="Orthochromatic") {rM=0.f ;gM=42.f; bM=58.f;} - else if(params->blackwhite.setting=="HighContrast") {rM=40.f ;gM=34.f; bM=60.f;} - else if(params->blackwhite.setting=="Luminance") {rM=30.f ;gM=59.f; bM=11.f;} - else if(params->blackwhite.setting=="Landscape") {rM=66.f ;gM=24.f; bM=10.f;} - else if(params->blackwhite.setting=="Portrait") {rM=54.f ;gM=44.f; bM=12.f;} - else if(params->blackwhite.setting=="InfraRed") {rM=-40.f;gM=200.f;bM=-17.f;} +*/ - if (params->blackwhite.autoc) {rM=autor;gM=autog;bM=autob; mixerOrange=33.f; mixerYellow=33.f;mixerMagenta=33.f;mixerPurple=33.f;mixerCyan=33.f;} // auto channel-mixer - rrm=rM; - ggm=gM; - bbm=bM; - - somm=rM+gM+bM; - rM=rM/somm;gM=gM/somm;bM=bM/somm; - float koymcp=0.f; - - if(params->blackwhite.setting=="ROYGCBMP-Abs" || params->blackwhite.setting=="ROYGCBMP-Rel") { - float obM=0.f; - float ogM=0.f; - float orM=0.f; - - float ybM=0.f; - float yrM=0.f; - float ygM=0.f; - - float mgM=0.f; - float mrM=0.f; - float mbM=0.f; - - float pgM=0.f; - float prM=0.f; - float pbM=0.f; - - float crM=0.f; - float cgM=0.f; - float cbM=0.f; - - - float fcompl = 1.f; - if(complem) fcompl = 3.f; - // ponderate filters: report to R=G=B=33 - // I ponder RGB channel, not only orange or yellow or cyan, etc...it's my choice ! - if(mixerOrange !=33){//orange - if (mixerOrange >=33) orM=fcompl*(mixerOrange*0.67f - 22.11f)/100.f; else orM=fcompl*(-0.3f*mixerOrange +9.9f)/100.f; - if (mixerOrange >=33) ogM=fcompl*(-0.164f*mixerOrange+5.412f)/100.f; else ogM=fcompl*(0.4f*mixerOrange-13.2f)/100.f; - if(complem) obM=(-0.492f*mixerOrange+16.236f)/100.f; - rM+=orM; - gM+=ogM; - bM+=obM; - koymcp += (orM+ogM+obM); - } - if(mixerYellow !=33){//yellow - yrM=fcompl*(-0.134f*mixerYellow +4.422f)/100.f;//22.4 - ygM=fcompl*(0.5f*mixerYellow-16.5f)/100.f; - if(complem) ybM=(-0.492f*mixerYellow+16.236f)/100.f; - rM+=yrM; - gM+=ygM; - bM+=ybM; - koymcp += (yrM+ygM+ybM); - } - if(mixerMagenta !=33){//Magenta - if(mixerMagenta >=33) mrM=fcompl*(0.67f*mixerMagenta -22.11f)/100.f;else mrM=fcompl*(-0.3f*mixerMagenta +9.9f)/100.f; - if(mixerMagenta >=33) mbM=fcompl*(-0.164f*mixerMagenta+5.412f)/100.f;else mbM=fcompl*(0.4f*mixerMagenta-13.2f)/100.f; - if(complem) mgM=(-0.492f*mixerMagenta+16.236f)/100.f; - rM+=mrM; - gM+=mgM; - bM+=mbM; - koymcp += (mrM+mgM+mbM); - } - if(mixerPurple!=33){//Purple - prM=fcompl*(-0.134f*mixerPurple +4.422f)/100.f; - pbM=fcompl*(0.5f*mixerPurple-16.5f)/100.f; - if(complem) pgM=(-0.492f*mixerPurple+16.236f)/100.f; - rM+=prM; - gM+=pgM; - bM+=pbM; - koymcp += (prM+pgM+pbM); - } - if(mixerCyan !=33){//Cyan - cgM=fcompl*(-0.134f*mixerCyan +4.422f)/100.f; - cbM=fcompl*(0.5f*mixerCyan-16.5f)/100.f; - if(complem) crM=(-0.492f*mixerCyan+16.236f)/100.f; - rM+=crM; - gM+=cgM; - bM+=cbM; - koymcp += (crM+cgM+cbM); - } - } - if(params->blackwhite.setting=="ROYGCBMP-Abs") {kcorec=koymcp+som/100.f;} - //Color filters - float filred,filgreen,filblue; - filred=1.f;filgreen=1.f;filblue=1.f; - if (params->blackwhite.filter=="None") {filred=1.f; filgreen=1.f; filblue=1.f;} - else if (params->blackwhite.filter=="Red") {filred=1.f; filgreen=0.05f;filblue=0.f;} - else if (params->blackwhite.filter=="Orange") {filred=1.f; filgreen=0.6f; filblue=0.f;} - else if (params->blackwhite.filter=="Yellow") {filred=1.f; filgreen=1.f; filblue=0.05f;} - else if (params->blackwhite.filter=="YellowGreen") {filred=0.6f; filgreen=1.f; filblue=0.3f;} - else if (params->blackwhite.filter=="Green") {filred=0.2f; filgreen=1.f; filblue=0.3f;} - else if (params->blackwhite.filter=="Cyan") {filred=0.05f;filgreen=1.f; filblue=1.f;} - else if (params->blackwhite.filter=="Blue") {filred=0.f; filgreen=0.05f;filblue=1.f;} - else if (params->blackwhite.filter=="Purple") {filred=1.f; filgreen=0.05f;filblue=1.f;} - - - rM = rM*filred; - gM = gM*filgreen; - bM = bM*filblue; - - rM=rM / (rM+gM+bM); - gM=gM / (rM+gM+bM); - bM=bM / (rM+gM+bM); - - mix[0][0] = rM; - mix[1][0] = rM; - mix[2][0] = rM; - mix[0][1] = gM; - mix[1][1] = gM; - mix[2][1] = gM; - mix[0][2] = bM; - mix[1][2] = bM; - mix[2][2] = bM; + else if (algm==2) {//channel-mixer + //end auto chmix + float mix[3][3]; + + if (computeMixerAuto) { + // auto channel-mixer #ifdef _OPENMP -#pragma omp for schedule(dynamic, 5) private (val, in) +#pragma omp for schedule(dynamic, 5) reduction(+:nr,ng,nb) +#endif + for (int i=0; ir(i,j); + ng += tmpImage->g(i,j); + nb += tmpImage->b(i,j); + } + } + +#ifdef _OPENMP +#pragma omp single +#endif +{ + double srgb = nr+ng+nb; + double knr = srgb/nr; + double kng = srgb/ng; + double knb = srgb/nb; + double sk = knr+kng+knb; + autor=(float)(100.0*knr/sk); + autog=(float)(100.0*kng/sk); + autob=(float)(100.0*knb/sk); +} + +/* +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ir(i,j); + float gg = tmpImage->g(i,j); + float bb = tmpImage->b(i,j); + nr+=rr; + ng+=gg; + nb+=bb; + float srgb; + srgb = nr+ng+nb; + float knr=nr/srgb; + float kng=ng/srgb; + float knb=nb/srgb; + knr = 1.f/knr; + kng = 1.f/kng; + knb = 1.f/knb; + float sk; + sk=knr+kng+knb; + knr=100.f*knr/sk; + kng=100.f*kng/sk; + knb=100.f*knb/sk; + autor=knr; + autog=kng; + autob=knb; + } + } +*/ + } + + if (params->blackwhite.autoc) { + // auto channel-mixer + bwr = autor; + bwg = autog; + bwb = autob; + mixerOrange = 33.f; + mixerYellow = 33.f; + mixerMagenta = 33.f; + mixerPurple = 33.f; + mixerCyan = 33.f; + } + +#ifdef _OPENMP +#pragma omp barrier +#pragma omp single +#endif +{ + Color::computeBWMixerConstants(params->blackwhite.setting, params->blackwhite.filter, + bwr, bwg, bwb, mixerOrange, mixerYellow, mixerCyan, mixerPurple, mixerMagenta, + params->blackwhite.autoc, complem, kcorec, rrm, ggm, bbm); +} + mix[0][0] = bwr; + mix[1][0] = bwr; + mix[2][0] = bwr; + mix[0][1] = bwg; + mix[1][1] = bwg; + mix[2][1] = bwg; + mix[0][2] = bwb; + mix[1][2] = bwb; + mix[2][2] = bwb; + + float in[3], val[3]; + +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) #endif for (int i=0; ir(i,j) = CLIP(val[0]*kcorec); - tmpImage->g(i,j) = CLIP(val[1]*kcorec); - tmpImage->b(i,j) = CLIP(val[2]*kcorec); - //correction gamma : pseudo TRC curve + tmpImage->r(i,j) = tmpImage->g(i,j) = tmpImage->b(i,j) = CLIP(val[0]*kcorec); + + //gamma correction: pseudo TRC curve if (hasgammabw) Color::trcGammaBW (tmpImage->r(i,j), tmpImage->g(i,j), tmpImage->b(i,j), gammabwr, gammabwg, gammabwb); } } - -} + } -if(blackwhite){//after BW conversion if (hasToneCurvebw2) { if (afterCurveMode==BlackWhiteParams::TC_MODE_STD_BW){ // Standard @@ -2725,7 +2778,8 @@ if(blackwhite){//after BW conversion } } } -} + +} // end blackwhite #ifdef _OPENMP #pragma omp for schedule(dynamic, 5) @@ -2777,7 +2831,6 @@ if(blackwhite){//after BW conversion if (hCurveEnabled) delete hCurve; if (sCurveEnabled) delete sCurve; if (vCurveEnabled) delete vCurve; - delete [] cossq; } @@ -3480,7 +3533,7 @@ float rew=params->edgePreservingDecompositionUI.ReweightingIterates; if(stren < 0.0f) DetailBoost = 0.0f; //Go with effect of exponent only if uncompressing. //Auto select number of iterates. Note that p->EdgeStopping = 0 makes a Gaussian blur. - if(Iterates == 0) Iterates = (unsigned int)(edgest*15.0); + if(Iterates == 0) Iterates = (unsigned int)(edgest*15.0f); /* Debuggery. Saves L for toying with outside of RT. char nm[64]; @@ -3489,7 +3542,7 @@ FILE *f = fopen(nm, "wb"); fwrite(L, N, sizeof(float), f); fclose(f);*/ - epd.CompressDynamicRange(L, (float)sca/skip, (float)edgest, Compression, DetailBoost, Iterates, rew, L); + epd.CompressDynamicRange(L, sca/float(skip), edgest, Compression, DetailBoost, Iterates, rew, L); //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. float s = (1.0f + 38.7889f)*powf(Compression, 1.5856f)/(1.0f + 38.7889f*powf(Compression, 1.5856f)); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 6258b4d91..201c84b5e 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -195,20 +195,26 @@ class ImProcFunctions { void firstAnalysis (Imagefloat* working, const ProcParams* params, LUTu & vhist16, double gamma); void 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, const ChMixerbw & customToneCurvebw1,const ChMixerbw & customToneCurvebw2, double &rrm, double &ggm, double &bbm); + SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, + const ToneCurve & customToneCurvebw1,const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob); void 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, const ChMixerbw & customToneCurvebw1,const ChMixerbw & customToneCurvebw2, double &rrm, double &ggm, double &bbm, - double expcomp, int hlcompr, int hlcomprthresh); - void luminanceCurve (LabImage* lold, LabImage* lnew, LUTf &curve); - void ciecam_02float (CieImage* ncie, float adap, int begh, int endh, int pW, int pwb, LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3, LUTu &histLCAM, LUTu &histCCAM,int Iterates, int scale, float** buffer, bool execsharp, float &d); - void ciecam_02 (CieImage* ncie, double adap, int begh, int endh, int pW, int pwb, LabImage* lab, const ProcParams* params , const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3, LUTu &histLCAM, LUTu &histCCAM,int Iterates, int scale, float** buffer, bool execsharp, double &d); + SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, + const ToneCurve & customToneCurvebw1,const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, + double expcomp, int hlcompr, int hlcomprthresh); + void luminanceCurve (LabImage* lold, LabImage* lnew, LUTf &curve); + void ciecam_02float (CieImage* ncie, float adap, int begh, int endh, int pW, int pwb, LabImage* lab, const ProcParams* params, + const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3, + LUTu &histLCAM, LUTu &histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, float** buffer, bool execsharp, float &d); + void ciecam_02 (CieImage* ncie, double adap, int begh, int endh, int pW, int pwb, LabImage* lab, const ProcParams* params, + const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3, + LUTu &histLCAM, LUTu &histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, float** buffer, bool execsharp, double &d); void chromiLuminanceCurve (int pW, LabImage* lold, LabImage* lnew, LUTf &acurve, LUTf &bcurve, LUTf & satcurve,LUTf & satclcurve, LUTf &clcurve, LUTf &curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histCLurve, LUTu &histLCurve, LUTu &histLurve); - void vibrance (LabImage* lab);//Jacques' vibrance + void vibrance (LabImage* lab);//Jacques' vibrance void colorCurve (LabImage* lold, LabImage* lnew); void sharpening (LabImage* lab, float** buffer); void sharpeningcam (CieImage* ncie, float** buffer); void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, - double focalLen, double focalLen35mm, float focusDist, int rawRotationDeg, bool fullImage); + double focalLen, double focalLen35mm, float focusDist, int rawRotationDeg, bool fullImage); void lab2monitorRgb (LabImage* lab, Image8* image); void resize (Image16* src, Image16* dst, float dScale); void deconvsharpening (LabImage* lab, float** buffer); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 5084d84d6..facf18316 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -748,8 +748,8 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei ColorAppearance customColCurve1; ColorAppearance customColCurve2; ColorAppearance customColCurve3; - ChMixerbw customToneCurvebw1; - ChMixerbw customToneCurvebw2; + ToneCurve customToneCurvebw1; + ToneCurve customToneCurvebw2; ipf.g = gamma; ipf.iGamma = true; @@ -766,11 +766,12 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei LabImage* labView = new LabImage (fw,fh); CieImage* cieView = new CieImage (fw,fh); - CurveFactory::curveBW (params.blackwhite.beforeCurveMode, params.blackwhite.beforeCurve, params.blackwhite.afterCurveMode, params.blackwhite.afterCurve, - hist16, dummy, dummy, customToneCurvebw1, customToneCurvebw2, 16); + CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 16); double rrm, ggm, bbm; - ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2,rrm, ggm, bbm,expcomp, hlcompr, hlcomprthresh); + float autor, autog, autob; + autor = autog = autob = -9000.f; // This will ask to compute the "auto" values for the B&W tool + ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2,rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh); if (shmap) delete shmap; @@ -799,7 +800,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei CurveFactory::complexsgnCurve (autili, butili, ccutili, cclutili,params.labCurve.chromaticity, params.labCurve.rstprotection, params.labCurve.acurve, params.labCurve.bcurve,params.labCurve.cccurve,params.labCurve.lccurve, curve1, curve2, satcurve,lhskcurve, - hist16C, hist16C, hist16C, dummy, dummy, + hist16C, hist16C, dummy, dummy, 16); //ipf.luminanceCurve (labView, labView, curve); ipf.chromiLuminanceCurve (1,labView, labView, curve1, curve2, satcurve,lhskcurve, clcurve, curve, utili, autili, butili, ccutili,cclutili, clcutili, dummy, dummy, dummy, dummy); @@ -816,46 +817,48 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei params.colorappearance.curveMode2, params.colorappearance.curve2, params.colorappearance.curveMode3, params.colorappearance.curve3, hist16, hist16, dummy, - hist16C, hist16C, dummy, + hist16C, dummy, customColCurve1, customColCurve2, customColCurve3, 16); - int f_h=2,f_w=2; if(params.colorappearance.enabled){ - float** buffer = new float*[fh]; - for (int i=0; i direct EV - E_V += expo2; - float expo1;//exposure raw white point - expo1=log2(params.raw.expos);//log2 ==>linear to EV - E_V += expo1; - adap2 = adap= powf(2.f, E_V-3.f);//cd / m2 - ada=ada2=(double) adap; - //end calculation adaptation scene luminosity - } + float** buffer = new float*[fh]; + for (int i=0; i direct EV + E_V += expo2; + float expo1;//exposure raw white point + expo1=log2(params.raw.expos);//log2 ==>linear to EV + E_V += expo1; + adap= powf(2.f, E_V-3.f);//cd / m2 + //end calculation adaptation scene luminosity + } - ipf.ciecam_02float (cieView, adap, begh, endh, 1, 2, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 6, (float**)buffer, execsharp, d); - for (int i=0; igetGamma(); ipf.iGamma = true; @@ -203,10 +203,13 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p LabImage* labView = new LabImage (fw,fh); - CurveFactory::curveBW (params.blackwhite.beforeCurveMode, params.blackwhite.beforeCurve, params.blackwhite.afterCurveMode, params.blackwhite.afterCurve, - hist16, dummy, dummy, customToneCurvebw1, customToneCurvebw2, 1); + CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 1); double rrm, ggm, bbm; - ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2,customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, expcomp, hlcompr, hlcomprthresh); + float autor, autog, autob; + autor = -9000.f; // This will ask to compute the "auto" values for the B&W tool (have to be inferior to -5000) + ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2,customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh); + if (settings->verbose) + printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob); // Freeing baseImg because not used anymore delete baseImg; @@ -227,16 +230,24 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p if(params.labCurve.contrast !=0) {//only use hist16 for contrast #ifdef _OPENMP -#pragma�omp�parallel�shared(hist16,labView, fh, fw) +#pragma omp parallel shared(hist16,labView, fh, fw) #endif { -#ifdef _OPENMP -#pragma omp for schedule(static) + LUTu hist16thr (65536); // one temporary lookup table per thread + hist16thr.clear(); +#ifdef _OPENMP +#pragma omp for schedule(static) nowait #endif for (int i=0; iL[i][j])))]++; - } + hist16thr[CLIP((int)((labView->L[i][j])))]++; + } + +#pragma omp critical +{ + for(int i=0;i<65536;i++) + hist16[i] += hist16thr[i]; +} } @@ -253,7 +264,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p CurveFactory::complexsgnCurve (autili, butili, ccutili, cclutili, params.labCurve.chromaticity, params.labCurve.rstprotection, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve,params.labCurve.lccurve,curve1, curve2, satcurve,lhskcurve, - hist16C, hist16C, hist16C, dummy,dummy, + hist16C, hist16C, dummy,dummy, 1); ipf.chromiLuminanceCurve (1,labView, labView, curve1, curve2, satcurve,lhskcurve,clcurve, lumacurve, utili, autili, butili, ccutili,cclutili, clcutili, dummy, dummy, dummy, dummy); @@ -303,58 +314,60 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p params.colorappearance.curveMode2, params.colorappearance.curve2, params.colorappearance.curveMode3, params.colorappearance.curve3, hist16, hist16,dummy, - hist16C, hist16C,dummy, + hist16C, dummy, customColCurve1, customColCurve2, - customColCurve3, + customColCurve3, 1); float adap2,adap; double ada, ada2; - if(params.colorappearance.enabled){ - float fnum = imgsrc->getMetaData()->getFNumber ();// F number - float fiso = imgsrc->getMetaData()->getISOSpeed () ;// ISO - float fspeed = imgsrc->getMetaData()->getShutterSpeed () ;//speed - float fcomp = imgsrc->getMetaData()->getExpComp ();//compensation + - - if(fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) {adap=adap2=2000.f;ada=ada2=2000.;}//if no exif data or wrong - else { - float E_V = fcomp + log2 ((fnum*fnum) / fspeed / (fiso/100.f)); - float expo2= params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV - E_V += expo2; - float expo1;//exposure raw white point - expo1=log2(params.raw.expos);//log2 ==>linear to EV - E_V += expo1; - adap2 = adap= powf(2.f, E_V-3.f);//cd / m2 - ada=ada2=(double) adap; - } - if (params.sharpening.enabled) { - float d; - double dd; - - float** buffer = new float*[fh]; - for (int i=0; iciecamfloat) ipf.ciecam_02float (cieView, adap, begh, endh,1,2, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 1, (float**)buffer, true, d); - else ipf.ciecam_02 (cieView, ada, begh, endh,1,2, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 1, (float**)buffer, true, dd); + if(params.colorappearance.enabled){ + float fnum = imgsrc->getMetaData()->getFNumber ();// F number + float fiso = imgsrc->getMetaData()->getISOSpeed () ;// ISO + float fspeed = imgsrc->getMetaData()->getShutterSpeed () ;//speed + float fcomp = imgsrc->getMetaData()->getExpComp ();//compensation + - + if(fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) {adap=adap2=2000.f;ada=ada2=2000.;}//if no exif data or wrong + else { + float E_V = fcomp + log2 ((fnum*fnum) / fspeed / (fiso/100.f)); + float expo2= params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV + E_V += expo2; + float expo1;//exposure raw white point + expo1=log2(params.raw.expos);//log2 ==>linear to EV + E_V += expo1; + adap2 = adap= powf(2.f, E_V-3.f);//cd / m2 + ada=ada2=(double) adap; + } + LUTf CAMBrightCurveJ; + LUTf CAMBrightCurveQ; + float CAMMean; + if (params.sharpening.enabled) { + float d; + double dd; - for (int i=0; iciecamfloat) ipf.ciecam_02float (cieView, adap, begh, endh,1,2, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, (float**)buffer, true, d); + else ipf.ciecam_02 (cieView, ada, begh, endh,1,2, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, (float**)buffer, true, dd); + for (int i=0; iciecamfloat) ipf.ciecam_02float (cieView, adap, begh, endh,1,2, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 1, (float**)buffer, true, d); -else ipf.ciecam_02 (cieView, adap, begh, endh,1, 2, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, 5, 1, (float**)buffer, true, dd); - for (int i=0; iciecamfloat) ipf.ciecam_02float (cieView, adap, begh, endh,1,2, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, (float**)buffer, true, d); + else ipf.ciecam_02 (cieView, adap, begh, endh,1, 2, labView, ¶ms,customColCurve1,customColCurve2,customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, (float**)buffer, true, dd); + + for (int i=0; iset_border_width(4); mixerVBox->set_spacing(4); @@ -122,9 +126,6 @@ BlackWhite::BlackWhite (): Gtk::VBox(), FoldableToolPanel(this) { settingHBox->set_tooltip_markup (M("TP_BWMIX_SETTING_TOOLTIP")); Gtk::Label *settingLabel = Gtk::manage (new Gtk::Label (M("TP_BWMIX_SETTING")+":")); - Gtk::SeparatorMenuItem *menuSep1 = Gtk::manage (new Gtk::SeparatorMenuItem ()); - Gtk::SeparatorMenuItem *menuSep2 = Gtk::manage (new Gtk::SeparatorMenuItem ()); - settingHBox->pack_start (*settingLabel, Gtk::PACK_SHRINK); setting = Gtk::manage (new MyComboBoxText ()); setting->append_text (M("TP_BWMIX_SET_NORMCONTAST")); @@ -139,8 +140,8 @@ BlackWhite::BlackWhite (): Gtk::VBox(), FoldableToolPanel(this) { setting->append_text (M("TP_BWMIX_SET_ORTHOCHRO")); setting->append_text (M("TP_BWMIX_SET_RGBABS")); setting->append_text (M("TP_BWMIX_SET_RGBREL")); - setting->append_text (M("TP_BWMIX_SET_ROYGCBMPABS")); - setting->append_text (M("TP_BWMIX_SET_ROYGCBMPREL")); + setting->append_text (M("TP_BWMIX_SET_ROYGCBPMABS")); + setting->append_text (M("TP_BWMIX_SET_ROYGCBPMREL")); setting->append_text (M("TP_BWMIX_SET_INFRARED")); setting->set_active (0); @@ -148,6 +149,10 @@ BlackWhite::BlackWhite (): Gtk::VBox(), FoldableToolPanel(this) { mixerVBox->pack_start (*settingHBox); settingconn = setting->signal_changed().connect ( sigc::mem_fun(*this, &BlackWhite::settingChanged) ); + RGBLabels = Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER)); + RGBLabels->set_tooltip_text(M("TP_BWMIX_RGBLABEL_HINT")); + mixerVBox->pack_start (*RGBLabels); + //----------- Complementary Color checkbox ------------------------------ enabledccSep= Gtk::manage (new Gtk::HSeparator()); @@ -189,16 +194,16 @@ BlackWhite::BlackWhite (): Gtk::VBox(), FoldableToolPanel(this) { mixerVBox->pack_start (*filterHBox); filterconn = filter->signal_changed().connect ( sigc::mem_fun(*this, &BlackWhite::filterChanged) ); - //----------- RGB / ROYGCBMP Mixer ------------------------------ + //----------- RGB / ROYGCBPM Mixer ------------------------------ imgIcon[0] = Gtk::manage (new RTImage ("Chanmixer-R.png")); - imgIcon[1] = Gtk::manage (new RTImage ("Chanmixer-G.png")); - imgIcon[2] = Gtk::manage (new RTImage ("Chanmixer-B.png")); - imgIcon[3] = Gtk::manage (new RTImage ("Chanmixer-O.png")); - imgIcon[4] = Gtk::manage (new RTImage ("Chanmixer-Y.png")); - imgIcon[5] = Gtk::manage (new RTImage ("Chanmixer-C.png")); - imgIcon[6] = Gtk::manage (new RTImage ("Chanmixer-M.png")); - imgIcon[7] = Gtk::manage (new RTImage ("Chanmixer-P.png")); + imgIcon[1] = Gtk::manage (new RTImage ("Chanmixer-O.png")); + imgIcon[2] = Gtk::manage (new RTImage ("Chanmixer-Y.png")); + imgIcon[3] = Gtk::manage (new RTImage ("Chanmixer-G.png")); + imgIcon[4] = Gtk::manage (new RTImage ("Chanmixer-C.png")); + imgIcon[5] = Gtk::manage (new RTImage ("Chanmixer-B.png")); + imgIcon[6] = Gtk::manage (new RTImage ("Chanmixer-P.png")); + imgIcon[7] = Gtk::manage (new RTImage ("Chanmixer-M.png")); imgIcon[8] = Gtk::manage (new RTImage ("Chanmixer-Rgamma.png")); imgIcon[9] = Gtk::manage (new RTImage ("Chanmixer-Ggamma.png")); @@ -213,55 +218,58 @@ BlackWhite::BlackWhite (): Gtk::VBox(), FoldableToolPanel(this) { mixerRed->show(); mixerVBox->pack_start( *mixerRed, Gtk::PACK_SHRINK, 0); - mixerOrange= Gtk::manage(new Adjuster (/*M("TP_BWMIX_ORANGE")*/"", -100, 200, 1, 33, imgIcon[3])); - if (mixerOrange->delay < 50) mixerOrange->delay = 50; - mixerOrange->setAdjusterListener (this); - mixerOrange->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); - mixerOrange->show(); - mixerVBox->pack_start( *mixerOrange, Gtk::PACK_SHRINK, 0); - - mixerYellow= Gtk::manage(new Adjuster (/*M("TP_BWMIX_YELLOW")*/"", -100, 200, 1, 33, imgIcon[4])); - if (mixerYellow->delay < 50) mixerYellow->delay = 50; - mixerYellow->setAdjusterListener (this); - mixerYellow->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); - mixerYellow->show(); - mixerVBox->pack_start( *mixerYellow, Gtk::PACK_SHRINK, 0); - - mixerGreen= Gtk::manage(new Adjuster (/*M("TP_BWMIX_GREEN")*/"", -100, 200, 1, 33, imgIcon[1])); + mixerGreen= Gtk::manage(new Adjuster (/*M("TP_BWMIX_GREEN")*/"", -100, 200, 1, 33, imgIcon[3])); if (mixerGreen->delay < 50) mixerGreen->delay = 50; mixerGreen->setAdjusterListener (this); mixerGreen->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); mixerGreen->show(); mixerVBox->pack_start( *mixerGreen, Gtk::PACK_SHRINK, 0); - mixerCyan= Gtk::manage(new Adjuster (/*M("TP_BWMIX_CYAN")*/"", -100, 200, 1, 33, imgIcon[5])); - if (mixerCyan->delay < 50) mixerCyan->delay = 50; - mixerCyan->setAdjusterListener (this); - mixerCyan->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); - mixerCyan->show(); - mixerVBox->pack_start( *mixerCyan, Gtk::PACK_SHRINK, 0); - - mixerBlue= Gtk::manage(new Adjuster (/*M("TP_BWMIX_BLUE")*/"", -100, 200, 1, 33, imgIcon[2])); + mixerBlue= Gtk::manage(new Adjuster (/*M("TP_BWMIX_BLUE")*/"", -100, 200, 1, 33, imgIcon[5])); if (mixerBlue->delay < 50) mixerBlue->delay = 50; mixerBlue->setAdjusterListener (this); mixerBlue->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); mixerBlue->show(); mixerVBox->pack_start( *mixerBlue, Gtk::PACK_SHRINK, 0); - mixerMagenta= Gtk::manage(new Adjuster (/*M("TP_BWMIX_MAGENTA")*/"", -100, 200, 1, 33, imgIcon[6])); - if (mixerMagenta->delay < 50) mixerMagenta->delay = 50; - mixerMagenta->setAdjusterListener (this); - mixerMagenta->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); - mixerMagenta->show(); - mixerVBox->pack_start( *mixerMagenta, Gtk::PACK_SHRINK, 0); + filterSep2 = Gtk::manage (new Gtk::HSeparator()); + mixerVBox->pack_start (*filterSep2); - mixerPurple= Gtk::manage(new Adjuster (/*M("TP_BWMIX_PURPLE")*/"", -100, 200, 1, 33, imgIcon[7])); + mixerOrange= Gtk::manage(new Adjuster (/*M("TP_BWMIX_ORANGE")*/"", -100, 200, 1, 33, imgIcon[1])); + if (mixerOrange->delay < 50) mixerOrange->delay = 50; + mixerOrange->setAdjusterListener (this); + mixerOrange->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); + mixerOrange->show(); + mixerVBox->pack_start( *mixerOrange, Gtk::PACK_SHRINK, 0); + + mixerYellow= Gtk::manage(new Adjuster (/*M("TP_BWMIX_YELLOW")*/"", -100, 200, 1, 33, imgIcon[2])); + if (mixerYellow->delay < 50) mixerYellow->delay = 50; + mixerYellow->setAdjusterListener (this); + mixerYellow->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); + mixerYellow->show(); + mixerVBox->pack_start( *mixerYellow, Gtk::PACK_SHRINK, 0); + + mixerCyan= Gtk::manage(new Adjuster (/*M("TP_BWMIX_CYAN")*/"", -100, 200, 1, 33, imgIcon[4])); + if (mixerCyan->delay < 50) mixerCyan->delay = 50; + mixerCyan->setAdjusterListener (this); + mixerCyan->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); + mixerCyan->show(); + mixerVBox->pack_start( *mixerCyan, Gtk::PACK_SHRINK, 0); + + mixerPurple= Gtk::manage(new Adjuster (/*M("TP_BWMIX_PURPLE")*/"", -100, 200, 1, 33, imgIcon[6])); if (mixerPurple->delay < 50) mixerPurple->delay = 50; mixerPurple->setAdjusterListener (this); mixerPurple->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); mixerPurple->show(); mixerVBox->pack_start( *mixerPurple, Gtk::PACK_SHRINK, 0); + mixerMagenta= Gtk::manage(new Adjuster (/*M("TP_BWMIX_MAGENTA")*/"", -100, 200, 1, 33, imgIcon[7])); + if (mixerMagenta->delay < 50) mixerMagenta->delay = 50; + mixerMagenta->setAdjusterListener (this); + mixerMagenta->set_tooltip_markup (M("TP_BWMIX_RGB_TOOLTIP")); + mixerMagenta->show(); + mixerVBox->pack_start( *mixerMagenta, Gtk::PACK_SHRINK, 0); + mixerFrame->add(*mixerVBox); //----------- Gamma sliders ------------------------------ @@ -376,6 +384,8 @@ bool BlackWhite::BWComputed_ () { mixerBlue->setValue (nextbluebw); enableListener (); + updateRGBLabel(); + return false; } @@ -389,7 +399,6 @@ void BlackWhite::read (const ProcParams* pp, const ParamsEdited* pedited) { enaccconn.block (true); enaconn.block (true); - if (pedited && !pedited->blackwhite.setting) setting->set_active (15); // "Unchanged" else if (pp->blackwhite.setting=="NormalContrast") @@ -416,9 +425,9 @@ void BlackWhite::read (const ProcParams* pp, const ParamsEdited* pedited) { setting->set_active (10); else if (pp->blackwhite.setting=="RGB-Rel") setting->set_active (11); - else if (pp->blackwhite.setting=="ROYGCBMP-Abs") + else if (pp->blackwhite.setting=="ROYGCBPM-Abs") setting->set_active (12); - else if (pp->blackwhite.setting=="ROYGCBMP-Rel") + else if (pp->blackwhite.setting=="ROYGCBPM-Rel") setting->set_active (13); else if (pp->blackwhite.setting=="InfraRed") setting->set_active (14); @@ -515,6 +524,8 @@ void BlackWhite::read (const ProcParams* pp, const ParamsEdited* pedited) { enaconn.block (false); enaccconn.block (false); + updateRGBLabel(); + enableListener (); } @@ -578,55 +589,8 @@ void BlackWhite::write (ProcParams* pp, ParamsEdited* pedited) { else if (method->get_active_row_number()==2) pp->blackwhite.method = "ChannelMixer"; - if (setting->get_active_row_number()==0) - pp->blackwhite.setting = "NormalContrast"; - else if (setting->get_active_row_number()==1) - pp->blackwhite.setting = "HighContrast"; - else if (setting->get_active_row_number()==2) - pp->blackwhite.setting = "Luminance"; - else if (setting->get_active_row_number()==3) - pp->blackwhite.setting = "Landscape"; - else if (setting->get_active_row_number()==4) - pp->blackwhite.setting = "Portrait"; - else if (setting->get_active_row_number()==5) - pp->blackwhite.setting = "LowSensitivity"; - else if (setting->get_active_row_number()==6) - pp->blackwhite.setting = "HighSensitivity"; - else if (setting->get_active_row_number()==7) - pp->blackwhite.setting = "Panchromatic"; - else if (setting->get_active_row_number()==8) - pp->blackwhite.setting = "HyperPanchromatic"; - else if (setting->get_active_row_number()==9) - pp->blackwhite.setting = "Orthochromatic"; - else if (setting->get_active_row_number()==10) - pp->blackwhite.setting = "RGB-Abs"; - else if (setting->get_active_row_number()==11) - pp->blackwhite.setting = "RGB-Rel"; - else if (setting->get_active_row_number()==12) - pp->blackwhite.setting = "ROYGCBMP-Abs"; - else if (setting->get_active_row_number()==13) - pp->blackwhite.setting = "ROYGCBMP-Rel"; - else if (setting->get_active_row_number()==14) - pp->blackwhite.setting = "InfraRed"; - - if (filter->get_active_row_number()==0) - pp->blackwhite.filter = "None"; - else if (filter->get_active_row_number()==1) - pp->blackwhite.filter = "Red"; - else if (filter->get_active_row_number()==2) - pp->blackwhite.filter = "Orange"; - else if (filter->get_active_row_number()==3) - pp->blackwhite.filter = "Yellow"; - else if (filter->get_active_row_number()==4) - pp->blackwhite.filter = "YellowGreen"; - else if (filter->get_active_row_number()==5) - pp->blackwhite.filter = "Green"; - else if (filter->get_active_row_number()==6) - pp->blackwhite.filter = "Cyan"; - else if (filter->get_active_row_number()==7) - pp->blackwhite.filter = "Blue"; - else if (filter->get_active_row_number()==8) - pp->blackwhite.filter = "Purple"; + pp->blackwhite.setting = getSettingString(); + pp->blackwhite.filter = getFilterString(); } void BlackWhite::curveChanged (CurveEditor* ce) { @@ -698,7 +662,7 @@ void BlackWhite::settingChanged () { showFilter(); } else if ( setting->get_active_row_number()==12 || setting->get_active_row_number()==13 ) { - // ROYGCBMP Channel Mixer + // ROYGCBPM Channel Mixer showMixer(7); showEnabledCC(); showFilter(); @@ -717,6 +681,18 @@ void BlackWhite::settingChanged () { showFilter(); } + // Checking "listener" to avoid "autoch" getting toggled off because it has to change the sliders when toggling on + if (listener){ + if (multiImage && autoch->get_inconsistent()) + autoch->set_inconsistent (false); + autoconn.block(true); + autoch->set_active (false); + autoconn.block(false); + lastAuto = false; + } + + updateRGBLabel(); + if (listener && (multiImage||enabled->get_active())) { listener->panelChanged (EvBWsetting, setting->get_active_text ()); } @@ -724,6 +700,18 @@ void BlackWhite::settingChanged () { void BlackWhite::filterChanged () { + // Checking "listener" to avoid "autoch" getting toggled off because it has to change the sliders when toggling on + if (listener){ + if (multiImage && autoch->get_inconsistent()) + autoch->set_inconsistent (false); + autoconn.block(true); + autoch->set_active (false); + autoconn.block(false); + lastAuto = false; + } + + updateRGBLabel(); + if (listener && (multiImage||enabled->get_active())) { listener->panelChanged (EvBWfilter, filter->get_active_text ()); } @@ -803,15 +791,17 @@ void BlackWhite::neutral_pressed () { // This method deselects auto chmixer and sets "neutral" values to params disableListener(); - if (multiImage) { + if (multiImage && autoch->get_inconsistent()) autoch->set_inconsistent (false); - autoch->set_active (false); + autoconn.block(true); + autoch->set_active (false); + autoconn.block(false); + lastAuto = false; - lastAuto = autoch->get_active (); - } - else { //!batchMode - autoch->set_active (false); - } + int activeSetting = setting->get_active_row_number(); + if (activeSetting < 10 || activeSetting > 13) + setting->set_active (11); + filter->set_active (0); mixerRed->resetValue(false); mixerGreen->resetValue(false); mixerBlue->resetValue(false); @@ -820,23 +810,23 @@ void BlackWhite::neutral_pressed () { mixerMagenta->resetValue(false); mixerPurple->resetValue(false); mixerCyan->resetValue(false); - int activeSetting = setting->get_active_row_number(); - if (activeSetting < 10 || activeSetting > 13) - setting->set_active (11); - filter->set_active (0); enableListener(); + updateRGBLabel(); + listener->panelChanged (EvNeutralBW, M("ADJUSTER_RESET_TO_DEFAULT")); } void BlackWhite::enabledcc_toggled () { + // toggling off the Complementary Colors does switch off the Auto button if (multiImage) { + // multiple image editing (batch) if (enabledcc->get_inconsistent()) { - enabledcc->set_inconsistent (false); + enabledcc->set_inconsistent (false); // set consistent enaccconn.block (true); - enabledcc->set_active (false); + enabledcc->set_active (false); // ... and deactivated enaccconn.block (false); } else if (lastEnabledcc) @@ -844,6 +834,16 @@ void BlackWhite::enabledcc_toggled () { lastEnabledcc = enabledcc->get_active (); } + + if (multiImage && autoch->get_inconsistent()) + autoch->set_inconsistent (false); + autoconn.block(true); + autoch->set_active (false); + autoconn.block(false); + lastAuto = false; + + updateRGBLabel(); + if (listener) { if (enabledcc->get_inconsistent()) listener->panelChanged (EvBWChmixEnabledLm, M("GENERAL_UNCHANGED")); @@ -902,14 +902,16 @@ void BlackWhite::setDefaults (const ProcParams* defParams, const ParamsEdited* p void BlackWhite::autoch_toggled () { if (batchMode) { - if (autoch->get_inconsistent()) { - autoch->set_inconsistent (false); - autoconn.block (true); - autoch->set_active (false); - autoconn.block (false); + if (multiImage) { + if (autoch->get_inconsistent()) { + autoch->set_inconsistent (false); + autoconn.block (true); + autoch->set_active (false); + autoconn.block (false); + } + else if (lastAuto) + autoch->set_inconsistent (true); } - else if (lastAuto) - autoch->set_inconsistent (true); lastAuto = autoch->get_active (); @@ -937,18 +939,19 @@ void BlackWhite::autoch_toggled () { mixerMagenta->resetValue(true); if (mixerPurple->getAddMode()) mixerPurple->resetValue(true); - if (mixerMagenta->getAddMode()) - mixerPurple->resetValue(true); + if (mixerCyan->getAddMode()) + mixerCyan->resetValue(true); setting->set_active (11); filter->set_active (0); if (wasEnabled) enableListener(); if (listener) { - if (!autoch->get_inconsistent()) { - if (autoch->get_active ()) - listener->panelChanged (EvAutoch, M("GENERAL_ENABLED"));} - else - listener->panelChanged (EvAutoch, M("GENERAL_DISABLED")); + if (autoch->get_inconsistent()) + listener->panelChanged (EvAutoch, M("GENERAL_UNCHANGED")); + else if (autoch->get_active ()) + listener->panelChanged (EvAutoch, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvAutoch, M("GENERAL_DISABLED")); } } else { @@ -966,6 +969,8 @@ void BlackWhite::autoch_toggled () { filter->set_active (0); if (wasEnabled) enableListener(); + updateRGBLabel(); + if (listener) listener->panelChanged (EvAutoch, M("GENERAL_ENABLED")); } @@ -979,13 +984,22 @@ void BlackWhite::autoch_toggled () { void BlackWhite::adjusterChanged (Adjuster* a, double newval) { - if (autoch->get_active() && (a==mixerRed || a==mixerGreen || a==mixerBlue || a==mixerOrange || a==mixerYellow || a==mixerMagenta || a==mixerPurple || a==mixerCyan )) { + // Checking "listener" to avoid "autoch" getting toggled off because it has to change the sliders when toggling on + if (listener && (a==mixerRed || a==mixerGreen || a==mixerBlue || a==mixerOrange || a==mixerYellow || a==mixerMagenta || a==mixerPurple || a==mixerCyan) ) { + if (multiImage && autoch->get_inconsistent()) + autoch->set_inconsistent (false); autoconn.block(true); autoch->set_active (false); autoconn.block(false); - autoch->set_inconsistent (false); + lastAuto = false; } + if (a == mixerRed || a==mixerGreen || a== mixerBlue + || a == mixerOrange || a == mixerYellow ||a == mixerCyan + || a == mixerMagenta || a == mixerPurple) + + updateRGBLabel(); + if (listener && (multiImage||enabled->get_active())) { Glib::ustring value = a->getTextValue(); if (a == mixerRed) @@ -1013,6 +1027,41 @@ void BlackWhite::adjusterChanged (Adjuster* a, double newval) { } } +void BlackWhite::updateRGBLabel () { + if (!batchMode) { + float kcorrec=1.f; + float r, g, b; + if (autoch->get_active()) { + r = nextredbw; + g = nextgreenbw; + b = nextbluebw; + } + else { + r = mixerRed->getValue(); + g = mixerGreen->getValue(); + b = mixerBlue->getValue(); + } + double mixR, mixG, mixB; + Glib::ustring sSetting = getSettingString(); + Color::computeBWMixerConstants(sSetting, getFilterString(), r, g, b, + mixerOrange->getValue(), mixerYellow->getValue(), mixerCyan->getValue(), mixerPurple->getValue(), mixerMagenta->getValue(), + autoch->get_active(), enabledcc->get_active(), kcorrec, mixR, mixG, mixB); + RGBLabels->set_text( + Glib::ustring::compose(M("TP_BWMIX_RGBLABEL"), + Glib::ustring::format(std::fixed, std::setprecision(1), r*100.), + Glib::ustring::format(std::fixed, std::setprecision(1), g*100.), + Glib::ustring::format(std::fixed, std::setprecision(1), b*100.), + Glib::ustring::format(std::fixed, std::setprecision(0), (r+g+b)*100.)) + ); + // We have to update the RGB sliders too if preset values has been chosen + if (sSetting != "RGB-Abs" && sSetting != "RGB-Rel" && sSetting != "ROYGCBPM-Abs" && sSetting != "ROYGCBPM-Rel") { + mixerRed->setValue(mixR); + mixerGreen->setValue(mixG); + mixerBlue->setValue(mixB); + } + } +} + void BlackWhite::setBatchMode (bool batchMode) { removeIfThere (autoHBox, autoch, false); autoch = Gtk::manage (new Gtk::CheckButton (M("TP_BWMIX_AUTOCH"))); @@ -1020,6 +1069,10 @@ void BlackWhite::setBatchMode (bool batchMode) { autoconn = autoch->signal_toggled().connect( sigc::mem_fun(*this, &BlackWhite::autoch_toggled) ); autoHBox->pack_start (*autoch); + removeIfThere (mixerVBox, RGBLabels, false); + delete RGBLabels; + RGBLabels = NULL; + ToolPanel::setBatchMode (batchMode); mixerRed->showEditedCB (); mixerOrange->showEditedCB (); @@ -1122,10 +1175,14 @@ void BlackWhite::hideEnabledCC() { } void BlackWhite::showMixer(int nChannels, bool RGBIsSensitive) { + if (!batchMode) + RGBLabels->show(); + if (!batchMode && nChannels == 3) { mixerRed->show(); mixerRed->set_sensitive (RGBIsSensitive); mixerGreen->show(); mixerGreen->set_sensitive (RGBIsSensitive); mixerBlue->show(); mixerBlue->set_sensitive (RGBIsSensitive); + filterSep2->hide(); mixerOrange->hide(); mixerYellow->hide(); mixerCyan->hide(); @@ -1136,6 +1193,7 @@ void BlackWhite::showMixer(int nChannels, bool RGBIsSensitive) { mixerRed->show(); mixerRed->set_sensitive (true); mixerGreen->show(); mixerGreen->set_sensitive (true); mixerBlue->show(); mixerBlue->set_sensitive (true); + filterSep2->show(); mixerOrange->show(); mixerYellow->show(); mixerCyan->show(); @@ -1158,3 +1216,61 @@ void BlackWhite::hideGamma() { if (!batchMode) gammaFrame->hide(); } + +Glib::ustring BlackWhite::getSettingString() { + Glib::ustring retVal; + if (setting->get_active_row_number()==0) + retVal = "NormalContrast"; + else if (setting->get_active_row_number()==1) + retVal = "HighContrast"; + else if (setting->get_active_row_number()==2) + retVal = "Luminance"; + else if (setting->get_active_row_number()==3) + retVal = "Landscape"; + else if (setting->get_active_row_number()==4) + retVal = "Portrait"; + else if (setting->get_active_row_number()==5) + retVal = "LowSensitivity"; + else if (setting->get_active_row_number()==6) + retVal = "HighSensitivity"; + else if (setting->get_active_row_number()==7) + retVal = "Panchromatic"; + else if (setting->get_active_row_number()==8) + retVal = "HyperPanchromatic"; + else if (setting->get_active_row_number()==9) + retVal = "Orthochromatic"; + else if (setting->get_active_row_number()==10) + retVal = "RGB-Abs"; + else if (setting->get_active_row_number()==11) + retVal = "RGB-Rel"; + else if (setting->get_active_row_number()==12) + retVal = "ROYGCBPM-Abs"; + else if (setting->get_active_row_number()==13) + retVal = "ROYGCBPM-Rel"; + else if (setting->get_active_row_number()==14) + retVal = "InfraRed"; + return retVal; +} + +Glib::ustring BlackWhite::getFilterString() { + Glib::ustring retVal; + if (filter->get_active_row_number()==0) + retVal = "None"; + else if (filter->get_active_row_number()==1) + retVal = "Red"; + else if (filter->get_active_row_number()==2) + retVal = "Orange"; + else if (filter->get_active_row_number()==3) + retVal = "Yellow"; + else if (filter->get_active_row_number()==4) + retVal = "YellowGreen"; + else if (filter->get_active_row_number()==5) + retVal = "Green"; + else if (filter->get_active_row_number()==6) + retVal = "Cyan"; + else if (filter->get_active_row_number()==7) + retVal = "Blue"; + else if (filter->get_active_row_number()==8) + retVal = "Purple"; + return retVal; +} diff --git a/rtgui/blackwhite.h b/rtgui/blackwhite.h index 0d8c60971..804a5f569 100644 --- a/rtgui/blackwhite.h +++ b/rtgui/blackwhite.h @@ -43,6 +43,7 @@ class BlackWhite : public Gtk::VBox, public AdjusterListener, public FoldableToo Gtk::ToggleButton* autoch; Gtk::HBox* autoHBox; Gtk::Button* neutral; + Gtk::Label* RGBLabels; Adjuster *mixerRed; Adjuster *mixerGreen; @@ -58,13 +59,14 @@ class BlackWhite : public Gtk::VBox, public AdjusterListener, public FoldableToo MyComboBoxText* method; sigc::connection methodconn; Gtk::HBox* filterHBox; - Gtk::HSeparator* filterSep; + Gtk::HSeparator* filterSep, *filterSep2; MyComboBoxText* filter; sigc::connection filterconn; Gtk::HBox* settingHBox; MyComboBoxText* setting; sigc::connection settingconn; Gtk::Frame* mixerFrame; + Gtk::VBox * mixerVBox; Gtk::Frame* gammaFrame; Gtk::Image *imgIcon[11]; @@ -106,6 +108,7 @@ class BlackWhite : public Gtk::VBox, public AdjusterListener, public FoldableToo void autoch_toggled (); void neutral_pressed (); + void updateRGBLabel (); void adjusterChanged (Adjuster* a, double newval); void setAdjusterBehavior (bool bwadd, bool bwgadd); void trimValues (rtengine::procparams::ProcParams* pp); @@ -122,6 +125,9 @@ class BlackWhite : public Gtk::VBox, public AdjusterListener, public FoldableToo bool curveMode1Changed_ (); void curveMode1Changed2 (); bool curveMode1Changed2_ (); + + Glib::ustring getSettingString (); + Glib::ustring getFilterString (); }; #endif