From c296961a563416fdfdf16ff1672be5f1acdf8220 Mon Sep 17 00:00:00 2001 From: Emil Martinec Date: Sun, 14 Nov 2010 17:11:54 -0600 Subject: [PATCH] Further patches to exposure and tone curve. Histogram now stays fixed in tone curve, but all sliders up to and including brightness/contrast are applied before tone curve histogram is calculated and displayed. Bug in tone curve interaction with highlight reconstruction is fixed. --- rtengine/curves.cc | 187 +++++++++++++++++++++++++++++++++- rtengine/curves.h | 2 +- rtengine/improccoordinator.cc | 6 -- 3 files changed, 186 insertions(+), 9 deletions(-) diff --git a/rtengine/curves.cc b/rtengine/curves.cc index df2696fff..34f833ab0 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -586,7 +586,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - + /* void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, double shcompr, double br, double contr, double defmul, double gamma_, bool igamma, const std::vector& curvePoints, unsigned int* histogram, float* hlCurve, float* shCurve, int* outCurve, unsigned int* outBeforeCCurveHistogram, int skip) { double def_mul = pow (2.0, defmul); @@ -769,9 +769,192 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou outCurve[i] = (int) (65535.0 * dcurve[i]); delete [] dcurve; } - + */ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, double shcompr, double br, double contr, double defmul, double gamma_, bool igamma, const std::vector& curvePoints, unsigned int* histogram, float* hlCurve, float* shCurve, int* outCurve, unsigned int* outBeforeCCurveHistogram, int skip) { + + double def_mul = pow (2.0, defmul); + + printf ("def_mul= %f ecomp= %f black= %f hlcompr= %f shcompr= %f br= %f contr= %f defmul= %f gamma= %f, skip= %d \n",def_mul,ecomp,black,hlcompr,shcompr,br,contr,defmul,gamma_,skip); + + // compute parameters of the gamma curve + double start = exp(gamma_*log( -0.099 / ((1.0/gamma_-1.0)*1.099 ))); + double slope = 1.099 * pow (start, 1.0/gamma_-1) - 0.099/start; + double mul = 1.099; + double add = 0.099; + + // a: slope of the curve, black: starting point at the x axis + double a = pow (2.0, ecomp); + + // curve without contrast + double* dcurve = new double[65536]; + + // check if contrast curve is needed + bool needcontrast = contr>0.00001 || contr<-0.00001; + + // check if inverse gamma is needed at the end + bool needigamma = igamma && gamma_>0; + + // create a curve if needed + Curve* tcurve = NULL; + if (curvePoints.size()>0 && curvePoints[0]!=0) + tcurve = new Curve (curvePoints, CURVES_MIN_POLY_POINTS/skip); + + // clear array that stores histogram valid before applying the custom curve + if (outBeforeCCurveHistogram) + memset (outBeforeCCurveHistogram, 0, 256*sizeof(int)); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + std::vector brightcurvePoints; + brightcurvePoints.push_back((double)((CurveType)NURBS)); + + brightcurvePoints.push_back(0); //black point. Value in [0 ; 1] range + brightcurvePoints.push_back(0); //black point. Value in [0 ; 1] range + + if(br>0) { + brightcurvePoints.push_back(0.1); //toe point + brightcurvePoints.push_back(0.1+br/150.0); //value at toe point + + brightcurvePoints.push_back(0.7); //shoulder point + brightcurvePoints.push_back(MIN(1.0,0.7+br/300.0)); //value at shoulder point + } else { + brightcurvePoints.push_back(0.1-br/150.0); //toe point + brightcurvePoints.push_back(0.1); //value at toe point + + brightcurvePoints.push_back(MIN(1.0,0.7-br/300.0)); //shoulder point + brightcurvePoints.push_back(0.7); //value at shoulder point + } + brightcurvePoints.push_back(1); // white point + brightcurvePoints.push_back(1); // value at white point + + Curve* brightcurve = NULL; + brightcurve = new Curve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + for (int i=0; i<=0xffff; i++) { + + // change to [0,1] range + double val = (double)i / 65535.0; + + // apply default multiplier (that is >1 if highlight recovery is on) + // val *= def_mul; + + // apply base curve, thus, exposure compensation and black point with shadow and highlight protection + val = basecurve (val*def_mul, a, 0, def_mul, hlcompr/100.0, 0); + //val = basecurve (val*def_mul, a, black, def_mul, hlcompr/100.0, 1.5*shcompr/100.0); + + hlCurve[i] = (65535.0 * CLIPD(val)); + + //%%%%%%%%%%%%%%%%%%%%%%%%%% + // change to [0,1] range + val = (double)i / 65535.0; + + val = basecurve (val, 1, black, 1, 0, 1.5*shcompr/100.0); + + shCurve[i] = (65535.0 * CLIPD(val)); + + //%%%%%%%%%%%%%%%%%%%%%%%%%% + // change to [0,1] range + val = (double)i / 65535.0; + + // gamma correction + if (gamma_>0) + val = gamma (val, gamma_, start, slope, mul, add); + + // apply brightness curve + //val = brightness (val, br/100.0); + val = brightcurve->getVal (val); + + // store result in a temporary array + dcurve[i] = CLIPD(val); + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + if (needcontrast) { + // compute mean luminance of the image with the curve applied + int sum = 0; + double avg = 0; + //double sqavg = 0; + for (int i=0; i<=0xffff; i++) { + avg += dcurve[(int)shCurve[(int)hlCurve[i]]] * histogram[i]; + //sqavg += dcurve[i]*dcurve[i] * histogram[i]; + sum += histogram[i]; + } + avg /= sum; + //sqavg /= sum; + //double stddev = sqrt(sqavg-avg*avg); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + std::vector contrastcurvePoints; + contrastcurvePoints.push_back((double)((CurveType)NURBS)); + + contrastcurvePoints.push_back(0); //black point. Value in [0 ; 1] range + contrastcurvePoints.push_back(0); //black point. Value in [0 ; 1] range + + contrastcurvePoints.push_back(avg-avg*(0.6-contr/250.0)); //toe point + contrastcurvePoints.push_back(avg-avg*(0.6+contr/250.0)); //value at toe point + + contrastcurvePoints.push_back(avg+(1-avg)*(0.6-contr/250.0)); //shoulder point + contrastcurvePoints.push_back(avg+(1-avg)*(0.6+contr/250.0)); //value at shoulder point + + contrastcurvePoints.push_back(1); // white point + contrastcurvePoints.push_back(1); // value at white point + + Curve* contrastcurve = NULL; + contrastcurve = new Curve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // apply contrast enhancement + for (int i=0; i<=0xffff; i++) { + //double val = centercontrast (dcurve[i], contr_b, avg); + dcurve[i] = contrastcurve->getVal (dcurve[i]); + } + delete contrastcurve; + } + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + for (int i=0; i<=0xffff; i++) { + float val; + + // apply custom/parametric/NURBS curve, if any + if (tcurve) { + if (outBeforeCCurveHistogram) { + float hval = dcurve[(int)shCurve[(int)(hlCurve[i])]]; + //if (needigamma) + // hval = igamma2 (hval); + int hi = (int)(255.0*CLIPD(hval)); + outBeforeCCurveHistogram[hi]+=histogram[i] ; + } + val = tcurve->getVal (dcurve[i]); + } else { + val = (dcurve[i]); + } + + // if inverse gamma is needed, do it (standard sRGB inverse gamma is applied) + if (needigamma) + val = igamma2 (val); + + outCurve[i] = (int) (65535.0 * val + 0.5); + } + + + delete [] dcurve; + delete tcurve; + delete brightcurve; + if (outBeforeCCurveHistogram) { + //for (int i=0; i<256; i++) printf("i= %d bchist= %d \n",i,outBeforeCCurveHistogram[i]); + } + + } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/rtengine/curves.h b/rtengine/curves.h index 0330863e4..c0290a7a9 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -104,7 +104,7 @@ class CurveFactory { return y*clower2(x/m, slope*m/y, 2.0-sr); } else { double slope = a/(1-b); - double m = a*D>1 ? b/a+(0.25+0.75*(1-1/D))/slope : b+(1-b)/4; + double m = a*D>1 ? b/a+(0.25)/slope : b+(1-b)/4; double y = a*D>1 ? 0.25 : (m-b/a)*slope; if (x<=m) return b==0 ? x*slope : clower (x/m, slope*m/y, sr) * y; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 7664ffb7c..9da0605c1 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -376,14 +376,9 @@ void ImProcCoordinator::updateHistograms (int x1, int y1, int x2, int y2) { memset (ghist, 0, 256*sizeof(int)); memset (bhist, 0, 256*sizeof(int)); - memset (bcrgbhist, 0, 256*sizeof(int)); - memset (bcLhist, 0, 256*sizeof(int)); - for (int i=y1; idata[ofs]+587*previmg->data[ofs+1]+114*previmg->data[ofs+2]),0,255000)/1000; - bcrgbhist[Y]++; rhist[previmg->data[ofs++]]++; ghist[previmg->data[ofs++]]++; bhist[previmg->data[ofs++]]++; @@ -394,7 +389,6 @@ void ImProcCoordinator::updateHistograms (int x1, int y1, int x2, int y2) { for (int i=y1; iL[i][j]/256]++; - bcLhist[nprevl->L[i][j]/256]++; } /*for (int i=0; i<256; i++) {