/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ #include #include #include #include #include #include #include "rt_math.h" #include "mytime.h" #include "array2D.h" #include "LUT.h" #include "curves.h" #undef CLIPD #define CLIPD(a) ((a)>0.0f?((a)<1.0f?(a):1.0f):0.0f) using namespace std; namespace rtengine { Curve::Curve () : N(0), x(NULL), y(NULL), ypp(NULL), hashSize(1000 /* has to be initialized to the maximum value */ ) {} void Curve::AddPolygons () { if (firstPointIncluded) { poly_x.push_back(x1); poly_y.push_back(y1); } for (int k=1; k<(nbr_points-1); k++) { double t = k*increment; double t2 = t*t; double tr = 1.-t; double tr2 = tr*tr; double tr2t = tr*2*t; // adding a point to the polyline poly_x.push_back( tr2*x1 + tr2t*x2 + t2*x3); poly_y.push_back( tr2*y1 + tr2t*y2 + t2*y3); } // adding the last point of the sub-curve poly_x.push_back(x3); poly_y.push_back(y3); } void Curve::fillHash() { hash.resize(hashSize+2); unsigned int polyIter = 0; double const increment = 1./hashSize; double milestone = 0.; for (unsigned short i=0; i<(hashSize+1);) { while(poly_x[polyIter] <= milestone) ++polyIter; hash.at(i).smallerValue = polyIter-1; ++i; milestone = i*increment; } milestone = 0.; polyIter = 0; for (unsigned int i=0; i<(hashSize+1);) { while(poly_x[polyIter] < (milestone+increment)) ++polyIter; hash.at(i).higherValue = polyIter; ++i; milestone = i*increment; } hash.at(hashSize+1).smallerValue = poly_x.size()-1; hash.at(hashSize+1).higherValue = poly_x.size(); /* * Uncoment the code below to dump the polygon points and the hash table in files if (poly_x.size() > 500) { printf("Files generated (%d points)\n", poly_x.size()); FILE* f = fopen ("hash.txt", "wt"); for (unsigned int i=0; igetVal (val); // store result in a temporary array lutCurve[i] = (val); } // if skip>1, let apply linear interpolation in the skipped points of the curve if (skip > 1) { int prev = 0; for (int i=1; i<=0xffff-skip; i++) { if (i%skip==0) { prev+=skip; continue; } lutCurve[i] = ( lutCurve[prev] * (skip - i%skip) + lutCurve[prev+skip] * (i%skip) ) / skip; } } for (int i=0; i<=0xffff; i++) { outCurve[i] = (65535.0 * lutCurve[i]); } } else { for (int i=0; i<=0xffff; i++) { outCurve[i] = (float)i; } } } void CurveFactory::updatechroma ( const std::vector& cccurvePoints, LUTu & histogramC, LUTu & outBeforeCCurveHistogramC,//for chroma int skip) { LUTf dCcurve(65536,0); float val; for (int i=0; i<48000; i++) {//32768*1.414 + ... val = (double)i / 47999.0; dCcurve[i] = CLIPD(val); } outBeforeCCurveHistogramC.clear(); bool histNeededC = false; if (!cccurvePoints.empty() && cccurvePoints[0]!=0) { if (outBeforeCCurveHistogramC /*&& histogramCropped*/) histNeededC = true; } for (int i=0; i<48000; i++) {//32768*1.414 + ... float val; if (histNeededC) { float hval = dCcurve[i]; int hi = (int)(255.0*CLIPD(hval)); // outBeforeCCurveHistogramC[hi] += histogramC[i] ; } } } void CurveFactory::curveLightBrightColor ( procparams::ColorAppearanceParams::eTCModeId curveMode1, const std::vector& curvePoints1, 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 & outBeforeCCurveHistogramC,//for chroma ColorAppearance & customColCurve1, ColorAppearance & customColCurve2, ColorAppearance & customColCurve3, int skip) { LUTf dcurve(65536,0); LUTf dCcurve(65536,0); float val; for (int i=0; i<32768; i++) { val = (double)i / 32767.0; dcurve[i] = CLIPD(val); } for (int i=0; i<48000; i++) { //# 32768*1.414 approximation maxi for chroma val = (double)i / 47999.0; dCcurve[i] = CLIPD(val); } outBeforeCCurveHistogram.clear(); outBeforeCCurveHistogramC.clear(); bool histNeededC = false; bool histNeeded = false; DiagonalCurve* tcurve = NULL; customColCurve3.Reset(); if (!curvePoints3.empty() && curvePoints3[0]>DCT_Linear && curvePoints3[0]isIdentity()) { delete tcurve; tcurve = NULL; } else customColCurve3.Set(tcurve); delete tcurve; tcurve = NULL; } customColCurve2.Reset(); if (!curvePoints2.empty() && curvePoints2[0]>DCT_Linear && curvePoints2[0]isIdentity()) { delete tcurve; tcurve = NULL; } else customColCurve2.Set(tcurve); delete tcurve; tcurve = NULL; } // create first curve if needed customColCurve1.Reset(); if (!curvePoints1.empty() && curvePoints1[0]>DCT_Linear && curvePoints1[0]isIdentity()) { delete tcurve; tcurve = NULL; } else { customColCurve1.Set(tcurve); delete tcurve; tcurve = NULL; } } for (int i=0; i<32768; i++) { float val; if (histNeeded) { float hval = dcurve[i]; int hi = (int)(255.0*CLIPD(hval)); outBeforeCCurveHistogram[hi] += histogram[i] ; } } for (int i=0; i<48000; i++) {//32768*1.414 + ... float val; if (histNeededC) { float hval = dCcurve[i]; int hi = (int)(255.0*CLIPD(hval)); // outBeforeCCurveHistogramC[hi] += histogramC[i] ; } } if (tcurve) delete tcurve; } void CurveFactory::curveBW ( const std::vector& curvePointsbw, const std::vector& curvePointsbw2, LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw,//for Luminance ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip) { LUTf dcurve(65536,0); float val; for (int i=0; i<32768; i++) { val = (double)i / 32767.0; dcurve[i] = CLIPD(val); } outBeforeCCurveHistogrambw.clear(); bool histNeeded = false; DiagonalCurve* tcurve = NULL; customToneCurvebw2.Reset(); if (!curvePointsbw2.empty() && curvePointsbw2[0]>DCT_Linear && curvePointsbw2[0]isIdentity()) customToneCurvebw2.Set(tcurve); delete tcurve; tcurve = NULL; } customToneCurvebw1.Reset(); if (!curvePointsbw.empty() && curvePointsbw[0]>DCT_Linear && curvePointsbw[0]isIdentity()) customToneCurvebw1.Set(tcurve); delete tcurve; tcurve = NULL; } // create first curve if needed for (int i=0; i<32768; i++) { float val; if (histNeeded) { float hval = dcurve[i]; int hi = (int)(255.0*CLIPD(hval)); outBeforeCCurveHistogrambw[hi] += histogrambw[i] ; } } if (tcurve) delete tcurve; } // add curve Lab : C=f(L) void CurveFactory::curveCL ( bool & clcutili,const std::vector& clcurvePoints, LUTf & clCurve, LUTu & histogramcl, LUTu & outBeforeCLurveHistogram,int skip){ bool needed; DiagonalCurve* dCurve = NULL; LUTf dCcurve(65536,0); float val; for (int i=0; i<50000; i++) { //# 32768*1.414 approximation maxi for chroma dCcurve[i] = (float)i / 49999.0; } if (outBeforeCLurveHistogram) outBeforeCLurveHistogram.clear(); bool histNeededCL = false; needed = false; if (!clcurvePoints.empty() && clcurvePoints[0]!=0) { dCurve = new DiagonalCurve (clcurvePoints, CURVES_MIN_POLY_POINTS/skip); if (outBeforeCLurveHistogram) histNeededCL = true; if (dCurve && !dCurve->isIdentity()) {needed = true;clcutili=true;} } for (int i=0; i<50000; i++) {//32768*1.414 + ... float val; if (histNeededCL) { float hval = dCcurve[i]; int hi = (int)(255.0*CLIPD(hval)); // outBeforeCLurveHistogram[hi] += histogramcl[i] ; } } fillCurveArray(dCurve, clCurve, skip, needed); if (dCurve) { delete dCurve; dCurve = NULL; } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void CurveFactory::complexsgnCurve (float adjustr, 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 & outBeforeCCurveHistogram,LUTu & outBeforeLCurveHistogram, //for chroma int skip) { //----------------------------------------------------- bool needed; DiagonalCurve* dCurve = NULL; LUTf dCcurve(65536,0); int k=48000;//32768*1.41 for (int i=0; iisIdentity()) { needed = true; autili=true; } } fillCurveArray(dCurve, aoutCurve, skip, needed); //if(autili) aoutCurve.dump("acurve"); if (dCurve) { delete dCurve; dCurve = NULL; } //----------------------------------------------------- needed = false; if (!bcurvePoints.empty() && bcurvePoints[0]!=0) { dCurve = new DiagonalCurve (bcurvePoints, CURVES_MIN_POLY_POINTS/skip); if (dCurve && !dCurve->isIdentity()) { needed = true; butili=true; } } fillCurveArray(dCurve, boutCurve, skip, needed); if (dCurve) { delete dCurve; dCurve = NULL; } //----------------------------------------------- needed = false; if (!cccurvePoints.empty() && cccurvePoints[0]!=0) { dCurve = new DiagonalCurve (cccurvePoints, CURVES_MIN_POLY_POINTS/skip); if (outBeforeCCurveHistogram /*&& histogramCropped*/) histNeededC = true; if (dCurve && !dCurve->isIdentity()) {needed = true;ccutili=true;} } for (int i=0; iisIdentity()) {needed = true;cclutili=true;} } for (int i=0; i& curvePoints, procparams::ToneCurveParams::eTCModeId curveMode2, const std::vector& curvePoints2, LUTu & histogram, LUTu & histogramCropped, LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & customToneCurve1, ToneCurve & customToneCurve2, 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; // gamma BT709*/ //normalize gamma to sRGB double start = exp(gamma_*log( -0.055 / ((1.0/gamma_-1.0)*1.055 ))); double slope = 1.055 * pow (start, 1.0/gamma_-1) - 0.055/start; double mul = 1.055; double add = 0.055; // a: slope of the curve, black: starting point at the x axis double a = pow (2.0, ecomp); // curve without contrast LUTf dcurve(0x10000); // check if inverse gamma is needed at the end bool needigamma = igamma_ && gamma_>1.; // clear array that stores histogram valid before applying the custom curve outBeforeCCurveHistogram.clear(); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DiagonalCurve* brightcurve = NULL; // check if brightness curve is needed if (br>0.00001 || br<-0.00001) { std::vector brightcurvePoints; brightcurvePoints.resize(9); brightcurvePoints.at(0) = double(DCT_NURBS); brightcurvePoints.at(1) = 0.; //black point. Value in [0 ; 1] range brightcurvePoints.at(2) = 0.; //black point. Value in [0 ; 1] range if(br>0) { brightcurvePoints.at(3) = 0.1; //toe point brightcurvePoints.at(4) = 0.1+br/150.0; //value at toe point brightcurvePoints.at(5) = 0.7; //shoulder point brightcurvePoints.at(6) = min(1.0,0.7+br/300.0); //value at shoulder point } else { brightcurvePoints.at(3) = max(0.0,0.1-br/150.0); //toe point brightcurvePoints.at(4) = 0.1; //value at toe point brightcurvePoints.at(5) = 0.7-br/300.0; //shoulder point brightcurvePoints.at(6) = 0.7; //value at shoulder point } brightcurvePoints.at(7) = 1.; // white point brightcurvePoints.at(8) = 1.; // value at white point brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% float exp_scale = a; float scale = 65536.0; float comp = (max(0.0,ecomp) + 1.0)*hlcompr/100.0; float shoulder = ((scale/max(1.0f,exp_scale))*(hlcomprthresh/200.0))+0.1; //printf("shoulder = %e\n",shoulder); //printf ("exp_scale= %f comp= %f def_mul=%f a= %f \n",exp_scale,comp,def_mul,a); for (int i=0; i<0x10000; i++) { // change to [0,1] range float val = (float)i-shoulder; if (comp>0.0) { if (val>0.0) { float R = val*comp/(scale-shoulder); hlCurve[i] = log(1.0+R*exp_scale)/R; } else { hlCurve[i]=exp_scale; } } else { hlCurve[i]=exp_scale; } //%%%%%%%%%%%%%%%%%%%%%%%%%% // change to [0,1] range if (i!=0) { val = (float)i / 65535.0f; } else { val = 1.0/65535.0; } float val2 = basecurve (val, 1.0, black, 1.0, 0.0, 1.5*shcompr/100.0); shCurve[i] = CLIPD(val2)/val; //%%%%%%%%%%%%%%%%%%%%%%%%%% // change to [0,1] range val = (double)i / 65535.0; // gamma correction if (gamma_>1.) val = gamma (val, gamma_, start, slope, mul, add); // apply brightness curve if (brightcurve) val = brightcurve->getVal (val); // TODO: getVal(double) is very slow! Optimize with a LUTf // store result in a temporary array dcurve[i] = CLIPD(val); } if (brightcurve) delete brightcurve; //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // check if contrast curve is needed if (contr>0.00001 || contr<-0.00001) { // compute mean luminance of the image with the curve applied int sum = 0; float avg = 0; //double sqavg = 0; for (int i=0; i<=0xffff; i++) { float fi=i; fi = hlCurve[fi]*fi; avg += dcurve[(int)(shCurve[fi]*fi)] * 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.resize(9); contrastcurvePoints.at(0) = double(DCT_NURBS); contrastcurvePoints.at(1) = 0; //black point. Value in [0 ; 1] range contrastcurvePoints.at(2) = 0; //black point. Value in [0 ; 1] range contrastcurvePoints.at(3) = avg-avg*(0.6-contr/250.0); //toe point contrastcurvePoints.at(4) = avg-avg*(0.6+contr/250.0); //value at toe point contrastcurvePoints.at(5) = avg+(1-avg)*(0.6-contr/250.0); //shoulder point contrastcurvePoints.at(6) = avg+(1-avg)*(0.6+contr/250.0); //value at shoulder point contrastcurvePoints.at(7) = 1.; // white point contrastcurvePoints.at(8) = 1.; // value at white point DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // apply contrast enhancement for (int i=0; i<=0xffff; i++) { dcurve[i] = contrastcurve->getVal (dcurve[i]); } delete contrastcurve; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // create second curve if needed bool histNeeded = false; DiagonalCurve* tcurve = NULL; customToneCurve2.Reset(); if (!curvePoints2.empty() && curvePoints2[0]>DCT_Linear && curvePoints2[0]isIdentity()) customToneCurve2.Set(tcurve); delete tcurve; tcurve = NULL; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // create first curve if needed customToneCurve1.Reset(); if (!curvePoints.empty() && curvePoints[0]>DCT_Linear && curvePoints[0]isIdentity()) customToneCurve1.Set(tcurve); delete tcurve; tcurve = NULL; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // create curve bw // curve 2 /* DiagonalCurve* tbwcurve = NULL; customToneCurvebw2.Reset(); if (!curvePointsbw2.empty() && curvePointsbw2[0]>DCT_Linear && curvePointsbw2[0]isIdentity()) { delete tbwcurve; tbwcurve = NULL; } else customToneCurvebw2.Set(tbwcurve); delete tbwcurve; tbwcurve = NULL; } customToneCurvebw1.Reset(); if (!curvePointsbw.empty() && curvePointsbw[0]>DCT_Linear && curvePointsbw[0]isIdentity()) { delete tbwcurve; tbwcurve = NULL; } else if (curveModeb != procparams::BlackWhiteParams::TC_MODE_STD_BW) { customToneCurvebw1.Set(tbwcurve); delete tbwcurve; tbwcurve = NULL; } } */ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% for (int i=0; i<=0xffff; i++) { float val = dcurve[i];; if (histNeeded) { float fi=i; float hval = hlCurve[i]*fi; hval = dcurve[shCurve[hval]*hval]; //if (needigamma) // hval = igamma2 (hval); int hi = (int)(255.0*(hval)); outBeforeCCurveHistogram[hi] += histogram/*Cropped*/[i] ; } // if inverse gamma is needed, do it (standard sRGB inverse gamma is applied) if (needigamma) val = igamma (val, gamma_, start, slope, mul, add); outCurve[i] = (65535.0 * val); } if (tcurve) delete tcurve; /*if (outBeforeCCurveHistogram) { for (int i=0; i<256; i++) printf("i= %d bchist= %d \n",i,outBeforeCCurveHistogram[i]); }*/ } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void CurveFactory::complexLCurve (double br, double contr, const std::vector& curvePoints, LUTu & histogram, LUTu & histogramCropped, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili) { // curve without contrast LUTf dcurve(65536,0); // clear array that stores histogram valid before applying the custom curve if (outBeforeCCurveHistogram) outBeforeCCurveHistogram.clear(); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // check if brightness curve is needed if (br>0.00001 || br<-0.00001) { utili=true; std::vector brightcurvePoints; brightcurvePoints.resize(9); brightcurvePoints.at(0) = double(DCT_NURBS); brightcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range brightcurvePoints.at(2) = 0.; // black point. Value in [0 ; 1] range if (br>0) { brightcurvePoints.at(3) = 0.1; // toe point brightcurvePoints.at(4) = 0.1+br/150.0; //value at toe point brightcurvePoints.at(5) = 0.7; // shoulder point brightcurvePoints.at(6) = min(1.0,0.7+br/300.0); //value at shoulder point } else { brightcurvePoints.at(3) = 0.1-br/150.0; // toe point brightcurvePoints.at(4) = 0.1; // value at toe point brightcurvePoints.at(5) = min(1.0,0.7-br/300.0); // shoulder point brightcurvePoints.at(6) = 0.7; // value at shoulder point } brightcurvePoints.at(7) = 1.; // white point brightcurvePoints.at(8) = 1.; // value at white point DiagonalCurve* brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // Applying brightness curve for (int i=0; i<32768; i++) { // L values range up to 32767, higher values are for highlight overflow // change to [0,1] range float val = (float)i / 32767.0; // apply brightness curve val = brightcurve->getVal (val); // store result in a temporary array dcurve[i] = CLIPD(val); } delete brightcurve; } else { for (int i=0; i<32768; i++) { // L values range up to 32767, higher values are for highlight overflow // set the identity curve in the temporary array dcurve[i] = (float)i / 32767.0; } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // check if contrast curve is needed if (contr>0.00001 || contr<-0.00001) { utili=true; DiagonalCurve* contrastcurve = NULL; // compute mean luminance of the image with the curve applied int sum = 0; float avg = 0; //float sqavg = 0; for (int i=0; i<32768; i++) { avg += dcurve[i] * histogram[i]; //sqavg += dcurve[i]*dcurve[i] * histogram[i]; sum += histogram[i]; } if(sum) { avg /= sum; //sqavg /= sum; //float stddev = sqrt(sqavg-avg*avg); // printf("avg=%f\n",avg); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% std::vector contrastcurvePoints; contrastcurvePoints.resize(9); contrastcurvePoints.at(0) = double(DCT_NURBS); contrastcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range contrastcurvePoints.at(2) = 0.; // black point. Value in [0 ; 1] range contrastcurvePoints.at(3) = avg-avg*(0.6-contr/250.0); // toe point contrastcurvePoints.at(4) = avg-avg*(0.6+contr/250.0); // value at toe point contrastcurvePoints.at(5) = avg+(1-avg)*(0.6-contr/250.0); // shoulder point contrastcurvePoints.at(6) = avg+(1-avg)*(0.6+contr/250.0); // value at shoulder point contrastcurvePoints.at(7) = 1.; // white point contrastcurvePoints.at(8) = 1.; // value at white point contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% } else { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // sum has an invalid value (next to 0, producing a division by zero, so we create a fake contrast curve, producing a white image std::vector contrastcurvePoints; contrastcurvePoints.resize(5); contrastcurvePoints.at(0) = double(DCT_NURBS); contrastcurvePoints.at(1) = 0.; // black point. Value in [0 ; 1] range contrastcurvePoints.at(2) = 1.; // black point. Value in [0 ; 1] range contrastcurvePoints.at(3) = 1.; // white point contrastcurvePoints.at(4) = 1.; // value at white point contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% } // apply contrast enhancement for (int i=0; i<32768; i++) { dcurve[i] = contrastcurve->getVal (dcurve[i]); } delete contrastcurve; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // create a curve if needed DiagonalCurve* tcurve = NULL; bool histNeeded = false; if (!curvePoints.empty() && curvePoints[0]!=0) { tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip); if (outBeforeCCurveHistogram /*&& histogramCropped*/) histNeeded = true; } if (tcurve && tcurve->isIdentity()) { delete tcurve; tcurve = NULL; } if (tcurve) { utili=true;//if active // L values go up to 32767, last stop is for highlight overflow for (int i=0; i<32768; i++) { float val; if (histNeeded) { float hval = dcurve[i]; int hi = (int)(255.0*CLIPD(hval)); outBeforeCCurveHistogram[hi]+=histogram/*Cropped*/[i] ; } // apply custom/parametric/NURBS curve, if any val = tcurve->getVal (dcurve[i]); outCurve[i] = (32767.0 * val); } } else { // Skip the slow getval method if no curve is used (or an identity curve) // L values go up to 32767, last stop is for highlight overflow for (int i=0; i<32768; i++) { if (histNeeded) { float hval = dcurve[i]; int hi = (int)(255.0*CLIPD(hval)); outBeforeCCurveHistogram[hi]+=histogram/*Cropped*/[i] ; } outCurve[i] = 32767.0*dcurve[i]; } } for (int i=32768; i<65536; i++) outCurve[i]=(float)i; if (tcurve) delete tcurve; /*if (outBeforeCCurveHistogram) { for (int i=0; i<256; i++) printf("i= %d bchist= %d \n",i,outBeforeCCurveHistogram[i]); }*/ } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void CurveFactory::RGBCurve (const std::vector& curvePoints, LUTf & outCurve, int skip) { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // create a curve if needed DiagonalCurve* tcurve = NULL; if (!curvePoints.empty() && curvePoints[0]!=0) { tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip); } if (tcurve && tcurve->isIdentity()) { delete tcurve; tcurve = NULL; } if (tcurve) { if (!outCurve) outCurve(65536, 0); for (int i=0; i<65536; i++) { // apply custom/parametric/NURBS curve, if any float val = tcurve->getVal ((float)i/65536.0f); outCurve[i] = (65536.0f * val); } delete tcurve; } // let the LUTf empty for identity curves else { outCurve.reset(); } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void ColorAppearance::Reset() { lutColCurve.reset(); } // Fill a LUT with X/Y, ranged 0xffff void ColorAppearance::Set(Curve *pCurve) { lutColCurve(65536); for (int i=0; i<65536; i++) lutColCurve[i] = pCurve->getVal(double(i)/65535.) * 65535.; } void ToneCurve::Reset() { lutToneCurve.reset(); } // 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.; } }