From b2836b388f9082a411a4d9b77ac26bbf402f0d47 Mon Sep 17 00:00:00 2001 From: torger Date: Thu, 23 Jul 2015 21:34:00 +0200 Subject: [PATCH] Issue 2850: normalized RGB-pipeline curve gammas to sRGB, make curve algorithms operate on linear image data --- rtengine/curves.cc | 87 ++++++++++++++++++----------------- rtengine/curves.h | 16 ++++++- rtengine/imagesource.h | 2 - rtengine/improccoordinator.cc | 4 +- rtengine/improcfun.cc | 56 ++++++++-------------- rtengine/improcfun.h | 4 +- rtengine/rawimagesource.h | 2 - rtengine/rtthumbnail.cc | 4 +- rtengine/simpleprocess.cc | 4 +- rtengine/stdimagesource.h | 1 - 10 files changed, 80 insertions(+), 100 deletions(-) diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 17f5d0fd5..02b509d58 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -340,6 +340,11 @@ void CurveFactory::curveBW ( LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw,//for Luminance ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip) { + const float gamma_ = Color::sRGBGamma; + const float start = expf(gamma_*logf( -0.055 / ((1.0/gamma_-1.0)*1.055 ))); + const float slope = 1.055 * powf (start, 1.0/gamma_-1) - 0.055/start; + const float mul = 1.055; + const float add = 0.055; outBeforeCCurveHistogrambw.clear(); bool histNeeded = false; @@ -355,7 +360,7 @@ void CurveFactory::curveBW ( } if (tcurve) { if (!tcurve->isIdentity()) - customToneCurvebw2.Set(tcurve); + customToneCurvebw2.Set(tcurve, gamma_, start, slope, mul, add); delete tcurve; tcurve = NULL; } @@ -370,7 +375,7 @@ void CurveFactory::curveBW ( } if (tcurve) { if (!tcurve->isIdentity()) - customToneCurvebw1.Set(tcurve); + customToneCurvebw1.Set(tcurve, gamma_, start, slope, mul, add); delete tcurve; tcurve = NULL; } @@ -617,7 +622,7 @@ void CurveFactory::curveToningLL ( bool & llctoningutili,const std::vector& curvePoints, procparams::ToneCurveParams::eTCModeId curveMode2, const std::vector& curvePoints2, LUTu & histogram, LUTu & histogramCropped, @@ -626,32 +631,17 @@ void CurveFactory::curveToningLL ( bool & llctoningutili,const std::vector1.; + const float a = powf (2.0, ecomp); // clear array that stores histogram valid before applying the custom curve outBeforeCCurveHistogram.clear(); @@ -727,9 +717,8 @@ void CurveFactory::curveToningLL ( bool & llctoningutili,const std::vector1.) - val = gamma (val, gamma_, start, slope, mul, add); + // gamma correction + val = gamma (val, gamma_, start, slope, mul, add); // apply brightness curve if (brightcurve) @@ -747,8 +736,7 @@ void CurveFactory::curveToningLL ( bool & llctoningutili,const std::vector1.) - val = gamma (val, gamma_, start, slope, mul, add); + val = gamma (val, gamma_, start, slope, mul, add); // apply brightness curve if (brightcurve) @@ -825,7 +813,7 @@ void CurveFactory::curveToningLL ( bool & llctoningutili,const std::vectorisIdentity()) - customToneCurve2.Set(tcurve); + customToneCurve2.Set(tcurve, gamma_, start, slope, mul, add); delete tcurve; tcurve = NULL; } @@ -844,7 +832,7 @@ void CurveFactory::curveToningLL ( bool & llctoningutili,const std::vectorisIdentity()) - customToneCurve1.Set(tcurve); + customToneCurve1.Set(tcurve, gamma_, start, slope, mul, add); delete tcurve; tcurve = NULL; } @@ -904,11 +892,7 @@ void CurveFactory::curveToningLL ( bool & llctoningutili,const std::vectorgetVal ((float)i/65536.0f); + + // RGB curves are defined with sRGB gamma, but operate on linear data + float val = float(i)/65535.f; + val = CurveFactory::gamma2 (val); + val = tcurve->getVal(val); + val = CurveFactory::igamma2 (val); + //float val = tcurve->getVal ((float)i/65536.0f); outCurve[i] = (65536.0f * val); } delete tcurve; @@ -1165,9 +1155,20 @@ void ToneCurve::Reset() { } // Fill a LUT with X/Y, ranged 0xffff -void ToneCurve::Set(Curve *pCurve) { - lutToneCurve(65536); - for (int i=0; i<65536; i++) lutToneCurve[i] = pCurve->getVal(double(i)/65535.) * 65535.; +void ToneCurve::Set(Curve *pCurve, float gamma, float start, float slope, float mul, float add) { + lutToneCurve(65536); + if (gamma <= 0.0 || gamma == 1.) { + for (int i=0; i<65536; i++) lutToneCurve[i] = (float)pCurve->getVal(float(i)/65535.f) * 65535.f; + } else { + // apply gamma, that is 'pCurve' is defined with the given gamma and here we convert it to a curve in linear space + for (int i=0; i<65536; i++) { + float val = float(i)/65535.f; + val = CurveFactory::gamma (val, gamma, start, slope, mul, add); + val = pCurve->getVal(val); + val = CurveFactory::igamma (val, gamma, start, slope, mul, add); + lutToneCurve[i] = val * 65535.f; + } + } } void OpacityCurve::Reset() { diff --git a/rtengine/curves.h b/rtengine/curves.h index 99a1cbe4c..09ff263ff 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -181,6 +181,12 @@ class CurveFactory { static inline double igamma2 (double x) { return x <= 0.03928 ? x/12.92 : exp(log((x+0.055)/1.055)*sRGBGammaCurve); } + static inline float gamma2 (float x) { + return x <= 0.00304 ? x*12.92 : 1.055*expf(logf(x)/sRGBGammaCurve)-0.055; + } + static inline float igamma2 (float x) { + return x <= 0.03928 ? x/12.92 : expf(logf((x+0.055)/1.055)*sRGBGammaCurve); + } // 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); @@ -188,6 +194,12 @@ class CurveFactory { static inline double igamma (double x, double gamma, double start, double slope, double mul, double add){ return (x <= start*slope ? x/slope : exp(log((x+add)/mul)*gamma) ); } + static inline float gamma (float x, float gamma, float start, float slope, float mul, float add){ + return (x <= start ? x*slope : expf(logf(x)/gamma)*mul-add); + } + static inline float igamma (float x, float gamma, float start, float slope, float mul, float add){ + return (x <= start*slope ? x/slope : expf(logf((x+add)/mul)*gamma) ); + } static inline float hlcurve (const float exp_scale, const float comp, const float hlrange, float level) { @@ -208,7 +220,7 @@ class CurveFactory { public: static void complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double contr, - double gamma_, bool igamma_, procparams::ToneCurveParams::eTCModeId curveMode, const std::vector& curvePoints, procparams::ToneCurveParams::eTCModeId curveMode2, const std::vector& curvePoints2, + procparams::ToneCurveParams::eTCModeId curveMode, const std::vector& curvePoints, procparams::ToneCurveParams::eTCModeId curveMode2, const std::vector& curvePoints2, LUTu & histogram, LUTu & histogramCropped, LUTf & hlCurve, LUTf & shCurve,LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & outToneCurve, ToneCurve & outToneCurve2, @@ -348,7 +360,7 @@ class ToneCurve { virtual ~ToneCurve() {}; void Reset(); - void Set(Curve *pCurve); + void Set(Curve *pCurve, float gamma=0, float start=0, float slope=0, float mul=0, float add=0); operator bool (void) const { return lutToneCurve; } }; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 2aa1faa9f..8ec92c64e 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -86,8 +86,6 @@ class ImageSource : public InitialImage { virtual double getDefGain () { return 1.0; } - virtual double getGamma () { return 0.0; } - virtual void getFullSize (int& w, int& h, int tr = TR_NONE) {} virtual void getSize (int tran, PreviewProps pp, int& w, int& h) {} virtual int getRotateDegree() const { return 0; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index cba394658..6c928e3c1 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -354,12 +354,10 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { // if (hListener) oprevi->calcCroppedHistogram(params, scale, histCropped); //complexCurve also calculated pre-curves histogram depending on crop - ipf.g = imgsrc->getGamma(); - ipf.iGamma = true; CurveFactory::complexCurve (params.toneCurve.expcomp, params.toneCurve.black/65535.0, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, - ipf.g, !ipf.iGamma, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, + params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, vhist16, histCropped, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, scale==1 ? 1 : 1); CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, scale==1 ? 1 : 1); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 9de6ac34c..3e57e0fb1 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -2432,7 +2432,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *e SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit ,float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve,LUTf & cl2Toningcurve, 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, DCPProfile *dcpProf) { - LUTf iGammaLUTf; + LUTf fGammaLUTf; Imagefloat *tmpImage=NULL; // NOTE: We're getting all 3 pointers here, but this function may not need them all, so one could optimize this @@ -2688,20 +2688,11 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *e } bool hasgammabw = gammabwr!=1.f || gammabwg!=1.f || gammabwb!=1.f; - //normalize gamma to sRGB - double start = exp(g*log( -0.055 / ((1.0/g-1.0)*1.055 ))); - double slope = 1.055 * pow (start, 1.0/g-1) - 0.055/start; - double mul = 1.055; - double add = 0.055; - - if (iGamma && g > 1.) { - iGammaLUTf(65535); + fGammaLUTf(65535); #pragma omp parallel for - for (int i=0; i<65536; i++) { - iGammaLUTf[i] = float(CurveFactory::igamma (double(i)/65535., g, start, slope, mul, add)*65535.); - } + for (int i=0; i<65536; i++) { + fGammaLUTf[i] = CurveFactory::gamma2 (float(i)/65535.f) * 65535.f; } - if (hasColorToning || blackwhite) tmpImage = new Imagefloat(working->width,working->height); @@ -2887,9 +2878,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *e if (editID == EUID_ToneCurve1) { // filling the pipette buffer for (int i=istart,ti=0; iv(i,j) = CLIP(tmpImage->r(i,j)/65535.f); // assuming that r=g=b + editWhatever->v(i,j) = CLIP(fGammaLUTf[tmpImage->r(i,j)]/65535.f); // assuming that r=g=b } } } @@ -5732,7 +5712,7 @@ fclose(f);*/ double gavg = 0.; for (int i=0; i<65536>>histcompr; i++) - gavg += histogram[i] * CurveFactory::gamma2((int)(corr*(i<get_rotateDegree(); } diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index d204d8e02..49bf12d9b 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -910,10 +910,8 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei ToneCurve customToneCurvebw1; ToneCurve customToneCurvebw2; - ipf.g = gamma; - ipf.iGamma = true; CurveFactory::complexCurve (expcomp, black/65535.0, hlcompr, hlcomprthresh, - params.toneCurve.shcompr, bright, contr, ipf.g, !ipf.iGamma, + params.toneCurve.shcompr, bright, contr, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, hist16, dummy, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2, 16); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index bb6203d15..b5201a597 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -606,9 +606,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p ToneCurve customToneCurvebw2; //if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; - ipf.g = imgsrc->getGamma(); - ipf.iGamma = true; - CurveFactory::complexCurve (expcomp, black/65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, ipf.g, !ipf.iGamma, + CurveFactory::complexCurve (expcomp, black/65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, hist16, dummy, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2 ); diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index d8ab7275d..ed14ebba8 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -53,7 +53,6 @@ class StdImageSource : public ImageSource { void getAutoExpHistogram (LUTu &histogram, int& histcompr); double getDefGain () { return 0.0; } - double getGamma () { return 0.0; } void getFullSize (int& w, int& h, int tr = TR_NONE); void getSize (int tran, PreviewProps pp, int& w, int& h);