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.

This commit is contained in:
Emil Martinec 2010-11-14 17:11:54 -06:00
parent aa666fd19c
commit c296961a56
3 changed files with 186 additions and 9 deletions

View File

@ -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<double>& curvePoints, unsigned int* histogram, float* hlCurve, float* shCurve, int* outCurve, unsigned int* outBeforeCCurveHistogram, int skip) { void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, double shcompr, double br, double contr, double defmul, double gamma_, bool igamma, const std::vector<double>& curvePoints, unsigned int* histogram, float* hlCurve, float* shCurve, int* outCurve, unsigned int* outBeforeCCurveHistogram, int skip) {
double def_mul = pow (2.0, defmul); 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]); outCurve[i] = (int) (65535.0 * dcurve[i]);
delete [] dcurve; 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<double>& 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<double> 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<double> 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]);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View File

@ -104,7 +104,7 @@ class CurveFactory {
return y*clower2(x/m, slope*m/y, 2.0-sr); return y*clower2(x/m, slope*m/y, 2.0-sr);
} else { } else {
double slope = a/(1-b); 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; double y = a*D>1 ? 0.25 : (m-b/a)*slope;
if (x<=m) if (x<=m)
return b==0 ? x*slope : clower (x/m, slope*m/y, sr) * y; return b==0 ? x*slope : clower (x/m, slope*m/y, sr) * y;

View File

@ -376,14 +376,9 @@ void ImProcCoordinator::updateHistograms (int x1, int y1, int x2, int y2) {
memset (ghist, 0, 256*sizeof(int)); memset (ghist, 0, 256*sizeof(int));
memset (bhist, 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; i<y2; i++) { for (int i=y1; i<y2; i++) {
int ofs = (i*pW + x1)*3; int ofs = (i*pW + x1)*3;
for (int j=x1; j<x2; j++) { for (int j=x1; j<x2; j++) {
int Y = CLIPTO((299*previmg->data[ofs]+587*previmg->data[ofs+1]+114*previmg->data[ofs+2]),0,255000)/1000;
bcrgbhist[Y]++;
rhist[previmg->data[ofs++]]++; rhist[previmg->data[ofs++]]++;
ghist[previmg->data[ofs++]]++; ghist[previmg->data[ofs++]]++;
bhist[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; i<y2; i++) for (int i=y1; i<y2; i++)
for (int j=x1; j<x2; j++) { for (int j=x1; j<x2; j++) {
Lhist[nprevl->L[i][j]/256]++; Lhist[nprevl->L[i][j]/256]++;
bcLhist[nprevl->L[i][j]/256]++;
} }
/*for (int i=0; i<256; i++) { /*for (int i=0; i<256; i++) {