Changes to black compression and saturation controls. Black compression from 0-50 acts the same as 0-100 on the previous version, compressing dark tones without crushing blacks. 50-100 then starts crushing blacks until by 100 on the slider, all tones up to the set black point are sent to zero. In the new saturation control, negative values of the slider set a linear curve rather than an inverted S curve, and smoothly decrease saturation to zero across the board.
This commit is contained in:
211
rtengine/green_equil_RT.cc
Normal file
211
rtengine/green_equil_RT.cc
Normal file
@@ -0,0 +1,211 @@
|
||||
// CFA pixel cleaning via directional average
|
||||
// by Emil Martinec
|
||||
// 2/18/2010
|
||||
#define TS 256 // Tile size
|
||||
|
||||
#define CLASS
|
||||
/*#define ushort UshORt
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short ushort;*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#define SQR(x) ((x)*(x))
|
||||
|
||||
|
||||
//void CLASS green_equilibrate()//for dcraw implementation
|
||||
void CLASS RawImageSource::green_equilibrate(float thresh)
|
||||
{
|
||||
// local variables
|
||||
static const int border=8;
|
||||
static const int border2=16;
|
||||
static const int v1=TS, v2=2*TS, v3=3*TS, /*v4=4*TS,*/ p1=-TS+1, p2=-2*TS+2, p3=-3*TS+3, m1=TS+1, m2=2*TS+2, m3=3*TS+3;
|
||||
|
||||
int height=H, width=W; //for RT only
|
||||
int top, left;
|
||||
|
||||
int verbose=1;
|
||||
|
||||
static const float eps=1.0; //tolerance to avoid dividing by zero
|
||||
//static const float thresh=0.03; //threshold for performing green equilibration; max percentage difference of G1 vs G2
|
||||
// G1-G2 differences larger than this will be assumed to be Nyquist texture, and left untouched
|
||||
static const float diffthresh=0.25; //threshold for texture, not to be equilibrated
|
||||
|
||||
/*double dt;
|
||||
clock_t t1, t2;
|
||||
|
||||
//clock_t t1_main, t2_main = 0;
|
||||
|
||||
// start
|
||||
if (verbose) fprintf (stderr,_("Green equilibration ...\n"));
|
||||
t1 = clock();*/
|
||||
|
||||
|
||||
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
// Fill G interpolated values with border interpolation and input values
|
||||
// Main algorithm: Tile loop
|
||||
//#pragma omp parallel for shared(image,height,width) private(top,left) schedule(dynamic)
|
||||
|
||||
for (top=0; top < height-border; top += TS-border2)
|
||||
for (left=0; left < width-border; left += TS-border2) {
|
||||
int bottom = MIN( top+TS,height);
|
||||
int right = MIN(left+TS, width);
|
||||
int numrows = bottom - top;
|
||||
int numcols = right - left;
|
||||
|
||||
int row, col;
|
||||
int rr, cc, c, indx;
|
||||
int vote1, vote2;
|
||||
|
||||
float val1;
|
||||
|
||||
float gin, gse, gsw, gne, gnw, wtse, wtsw, wtne, wtnw;
|
||||
float gu, gd, gl, gr;
|
||||
float mcorr, pcorr;
|
||||
float ginterp;
|
||||
float diffvarh, diffvarv, hvwt;
|
||||
|
||||
char *buffer; // TS*TS*16
|
||||
float (*cfa); // TS*TS*4
|
||||
float (*checker); // TS*TS*4
|
||||
float (*gvar); // TS*TS*4
|
||||
float (*gdiffv); // TS*TS*4
|
||||
float (*gdiffh); // TS*TS*4
|
||||
|
||||
/* assign working space */
|
||||
buffer = (char *) malloc(5*sizeof(float)*TS*TS);
|
||||
//merror(buffer,"green_equil()");
|
||||
memset(buffer,0,5*sizeof(float)*TS*TS);
|
||||
|
||||
cfa = (float (*)) buffer;
|
||||
checker = (float (*)) (buffer + sizeof(float)*TS*TS);
|
||||
gvar = (float (*)) (buffer + 2*sizeof(float)*TS*TS);
|
||||
gdiffv = (float (*)) (buffer + 3*sizeof(float)*TS*TS);
|
||||
gdiffh = (float (*)) (buffer + 4*sizeof(float)*TS*TS);
|
||||
|
||||
/*float cfa[TS*TS];
|
||||
float checker[TS*TS]; //this memory allocation crashes RT
|
||||
float gvar[TS*TS];
|
||||
|
||||
memset( (void *)&cfa[0], 0 ,sizeof(cfa) );*/
|
||||
|
||||
// rgb from input CFA data
|
||||
/* rgb values should be floating point number between 0 and 1
|
||||
after white balance multipliers are applied */
|
||||
for (rr=0; rr < numrows; rr++)
|
||||
for (row=rr+top, cc=0; cc < numcols; cc++) {
|
||||
col = cc+left;
|
||||
//cfa[rr*TS+cc] = image[row*width+col][FC(row,col)];//for dcraw implementation
|
||||
cfa[rr*TS+cc] = ri->data[row][col];
|
||||
|
||||
}
|
||||
|
||||
//The green equilibration algorithm starts here
|
||||
|
||||
for (rr=2; rr < numrows-2; rr++)
|
||||
//for (cc=3-(FC(rr,2)&1), indx=rr*TS+cc; cc < numcols-2; cc+=2, indx+=2) {
|
||||
for (indx=rr*TS+2; indx < rr*TS+numcols-2; indx++) {
|
||||
|
||||
if (FC(rr,indx)&1) {
|
||||
pcorr = (cfa[indx+p1]-cfa[indx])*(cfa[indx-p1]-cfa[indx]);
|
||||
mcorr = (cfa[indx+m1]-cfa[indx])*(cfa[indx-m1]-cfa[indx]);
|
||||
|
||||
if (pcorr>0 && mcorr>0) {checker[indx]=1;} else {checker[indx]=0;}
|
||||
|
||||
//checker[indx]=1;//test what happens if we always interpolate
|
||||
} else {
|
||||
gu=cfa[indx-v1]+0.5*(cfa[indx]-cfa[indx-v2]);
|
||||
gd=cfa[indx+v1]+0.5*(cfa[indx]-cfa[indx+v2]);
|
||||
gl=cfa[indx-1]+0.5*(cfa[indx]-cfa[indx-2]);
|
||||
gr=cfa[indx+1]+0.5*(cfa[indx]-cfa[indx+2]);
|
||||
|
||||
gdiffh[indx] = SQR((gl-gr)/(eps+gl+gr));
|
||||
gdiffv[indx] = SQR((gu-gd)/(eps+gu+gd));
|
||||
|
||||
//gvar[indx] = 0.25*(gu*gu+gd*gd+gl*gl+gr*gr)-SQR(0.25*(gu+gd+gl+gr));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//now smooth the cfa data
|
||||
for (rr=6; rr < numrows-6; rr++)
|
||||
for (cc=7-(FC(rr,2)&1), indx=rr*TS+cc; cc < numcols-6; cc+=2, indx+=2) {
|
||||
if (checker[indx]) {
|
||||
|
||||
diffvarh = eps+(gdiffh[indx-v1]+gdiffh[indx-1]+gdiffh[indx+1]+gdiffh[indx+v1]);
|
||||
diffvarv = eps+(gdiffv[indx-v1]+gdiffv[indx-1]+gdiffv[indx+1]+gdiffv[indx+v1]);
|
||||
hvwt = fabs(diffvarv-diffvarh)/(diffvarv+diffvarh);
|
||||
|
||||
|
||||
vote1=(checker[indx-v2]+checker[indx-2]+checker[indx+2]+checker[indx+v2]);
|
||||
vote2=(checker[indx-m1]+checker[indx+p1]+checker[indx-p1]+checker[indx+m1]);
|
||||
if (vote1>0 && vote2>0 && hvwt<diffthresh) {
|
||||
//pixel interpolation
|
||||
|
||||
gin=cfa[indx];
|
||||
|
||||
gse=(cfa[indx+m1])+0.5*(cfa[indx]-cfa[indx+m2]);
|
||||
gnw=(cfa[indx-m1])+0.5*(cfa[indx]-cfa[indx-m2]);
|
||||
gne=(cfa[indx+p1])+0.5*(cfa[indx]-cfa[indx+p2]);
|
||||
gsw=(cfa[indx-p1])+0.5*(cfa[indx]-cfa[indx-p2]);
|
||||
|
||||
|
||||
|
||||
wtse=1/(eps+SQR(cfa[indx+m2]-cfa[indx])+SQR(cfa[indx+m3]-cfa[indx+m1]));
|
||||
wtnw=1/(eps+SQR(cfa[indx-m2]-cfa[indx])+SQR(cfa[indx-m3]-cfa[indx-m1]));
|
||||
wtne=1/(eps+SQR(cfa[indx+p2]-cfa[indx])+SQR(cfa[indx+p3]-cfa[indx+p1]));
|
||||
wtsw=1/(eps+SQR(cfa[indx-p2]-cfa[indx])+SQR(cfa[indx-p3]-cfa[indx-p1]));
|
||||
|
||||
ginterp=(gse*wtse+gnw*wtnw+gne*wtne+gsw*wtsw)/(wtse+wtnw+wtne+wtsw);
|
||||
|
||||
if (/*(SQR(ginterp-gin) > 0.125*(gvar[indx-1]+gvar[indx+1]+gvar[indx-v1]+gvar[indx+v1])) &&*/ ((ginterp-gin) < thresh*(ginterp+gin)) ) {
|
||||
cfa[indx]=0.5*(ginterp+gin);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
// copy smoothed results back to image matrix
|
||||
for (rr=border; rr < numrows-border; rr++)
|
||||
for (row=rr+top, cc=border+1-(FC(rr,2)&1), indx=rr*TS+cc; cc < numcols-border; cc+=2, indx+=2) {
|
||||
if (cfa[indx]<1) continue;
|
||||
col = cc + left;
|
||||
//c = FC(row,col);
|
||||
//image[row*width + col][c] = CLIP((int)(cfa[indx] + 0.5)); //for dcraw implementation
|
||||
ri->data[row][col] = CLIP((int)(cfa[indx] + 0.5));
|
||||
}
|
||||
|
||||
// clean up
|
||||
free(buffer);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// done
|
||||
/*t2 = clock();
|
||||
dt = ((double)(t2-t1)) / CLOCKS_PER_SEC;
|
||||
if (verbose) {
|
||||
fprintf(stderr,_("elapsed time = %5.3fs\n"),dt);
|
||||
}*/
|
||||
|
||||
|
||||
}
|
||||
#undef TS
|
Reference in New Issue
Block a user