Added a "gamma" slider to pyramid NR. Noise reduction is carried out with L channel mapped to that gamma. Default value is 2.0; lower values increase shadow smoothing, higher values smooth highlights more. Unfortunately adjusting this slider interacts with the other two, so all three have to be iteratively adjusted to achieve a desired result.
This commit is contained in:
@@ -526,6 +526,7 @@ TP_CROP_W;W
|
||||
TP_CROP_X;x
|
||||
TP_CROP_Y;y
|
||||
TP_DIRPYRDENOISE_CHROMA;Chrominance
|
||||
TP_DIRPYRDENOISE_GAMMA;Gamma
|
||||
TP_DIRPYRDENOISE_LABEL;Directional Pyramid Noise Reduction
|
||||
TP_DIRPYRDENOISE_LUMA;Luminance
|
||||
TP_DISTORTION_AMOUNT;Amount
|
||||
|
@@ -41,15 +41,9 @@
|
||||
#define DIRWT_AB(i1,j1,i,j) ( /*domker[(i1-i)/scale+halfwin][(j1-j)/scale+halfwin]*/ rangefn_ab[(int)(data_fine->a[i1][j1]-data_fine->a[i][j]+0x10000)] * \
|
||||
rangefn_ab[(int)(data_fine->b[i1][j1]-data_fine->b[i][j]+0x10000)] )
|
||||
|
||||
//#define IDIRWT_L(i1,j1,i,j) (irangefn_L[(int)data_fine->L[i1][j1]-data_fine->L[i][j]+0x10000] )
|
||||
|
||||
/*#define IDIRWT_AB(i1,j1,i,j) ( \
|
||||
irangefn_ab[(int)data_fine->a[i1][j1]-data_fine->a[i][j]+0x10000] * \
|
||||
irangefn_ab[(int)data_fine->b[i1][j1]-data_fine->b[i][j]+0x10000]) */
|
||||
|
||||
#define NRWT_L(a) (nrwt_l[a] )
|
||||
|
||||
#define NRWT_AB (nrwt_ab[(int)((hipass[1]+0x10000)/*tonefactor*/)] * nrwt_ab[(int)((hipass[2]+0x10000)/*tonefactor*/)])
|
||||
#define NRWT_AB (nrwt_ab[(int)((hipass[1]+0x10000))] * nrwt_ab[(int)((hipass[2]+0x10000))])
|
||||
|
||||
|
||||
|
||||
@@ -87,9 +81,9 @@ namespace rtengine {
|
||||
|
||||
|
||||
|
||||
void ImProcFunctions :: dirpyrLab_denoise(LabImage * src, LabImage * dst, const int luma, const int chroma )
|
||||
void ImProcFunctions :: dirpyrLab_denoise(LabImage * src, LabImage * dst, const int luma, const int chroma, float gam )
|
||||
{
|
||||
float gam = 2.0;//MIN(3.0, 0.1*fabs(c[4])/3.0+0.001);
|
||||
//float gam = 2.0;//MIN(3.0, 0.1*fabs(c[4])/3.0+0.001);
|
||||
float gamthresh = 0.03;
|
||||
float gamslope = exp(log((double)gamthresh)/gam)/gamthresh;
|
||||
unsigned short gamcurve[65536];
|
||||
@@ -108,59 +102,61 @@ namespace rtengine {
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int * rangefn_L = new int [0x20000];
|
||||
int * irangefn_L = new int [0x20000];
|
||||
float * nrwt_l = new float [0x20000];
|
||||
|
||||
float noise_L = 2*25.0*luma;
|
||||
float noisevar_L = 4*SQR(25.0 * luma);
|
||||
|
||||
float * nrwt_l = new float [0x10000];
|
||||
|
||||
|
||||
int * rangefn_ab = new int [0x20000];
|
||||
int * irangefn_ab = new int [0x20000];
|
||||
float * nrwt_ab = new float [0x20000];
|
||||
|
||||
float noise_ab = 25*chroma;
|
||||
float noisevar_ab = SQR(25.0 * chroma);
|
||||
|
||||
|
||||
int intfactor = 16384;
|
||||
|
||||
|
||||
//set up range function
|
||||
/*for (int i=0; i<0x20000; i++)
|
||||
rangefn_L[i] = (int)(( exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*9*noisevar_L)) * noisevar_L/((double)(i-0x10000)*(double)(i-0x10000)+noisevar_L))*intfactor);
|
||||
for (int i=0; i<0x20000; i++)
|
||||
rangefn_ab[i] = (int)(( exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*9*noisevar_ab)) * noisevar_ab/((double)(i-0x10000)*(double)(i-0x10000)+noisevar_ab))*intfactor);
|
||||
*/
|
||||
//set up NR weight functions
|
||||
|
||||
//gamma correction for chroma in shadows
|
||||
float nrwtl_norm = ((CurveFactory::gamma((double)65535.0/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) - \
|
||||
(CurveFactory::gamma((double)75535.0/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)));
|
||||
for (int i=0; i<0x10000; i++) {
|
||||
nrwt_l[i] = ((CurveFactory::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0) - \
|
||||
CurveFactory::gamma((double)(i+10000)/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) )/nrwtl_norm;
|
||||
//if (i % 100 ==0) printf("%d %f \n",i,nrwt_l[i]);
|
||||
}
|
||||
|
||||
float tonefactor = nrwt_l[32768];
|
||||
|
||||
float noise_L = 25.0*luma;
|
||||
float noisevar_L = 4*SQR(noise_L);
|
||||
|
||||
float noise_ab = 25*chroma;
|
||||
float noisevar_ab = SQR(noise_ab);
|
||||
|
||||
|
||||
//set up range functions
|
||||
for (int i=0; i<0x20000; i++)
|
||||
rangefn_L[i] = (int)(( exp(-(double)fabs(i-0x10000) / (1+3*noise_L)) * /*(1.01+(c[5])/100)*/ noisevar_L/((double)(i-0x10000)*(double)(i-0x10000)+ /*(1.01+(c[5])/100)*/ noisevar_L))*intfactor);
|
||||
rangefn_L[i] = (int)(( exp(-(double)fabs(i-0x10000) * tonefactor / (1+3*noise_L)) * noisevar_L/((double)(i-0x10000)*(double)(i-0x10000) + noisevar_L))*intfactor);
|
||||
for (int i=0; i<0x20000; i++)
|
||||
rangefn_ab[i] = (int)(( exp(-(double)fabs(i-0x10000) / (1+3*noise_ab)) * noisevar_ab/((double)(i-0x10000)*(double)(i-0x10000)+noisevar_ab))*intfactor);
|
||||
rangefn_ab[i] = (int)(( exp(-(double)fabs(i-0x10000) * tonefactor / (1+3*noise_ab)) * noisevar_ab/((double)(i-0x10000)*(double)(i-0x10000) + noisevar_ab))*intfactor);
|
||||
|
||||
for (int i=0; i<0x20000; i++)
|
||||
irangefn_L[i] = 1+(int)( exp(-(double)fabs(i-0x10000) / (1+16*noise_L) )*intfactor);
|
||||
for (int i=0; i<0x20000; i++)
|
||||
irangefn_ab[i] = 1+(int)( exp(-(double)fabs(i-0x10000)/ (1+64*noise_ab) )*intfactor);
|
||||
irangefn_ab[i] = 1+(int)( exp(-(double)fabs(i-0x10000)/ (1+64*noise_ab) )*intfactor);
|
||||
|
||||
//for (int i=0; i<500; i++) printf("%d %d \n",i,gamcurve[i]);
|
||||
|
||||
float nrwtl_norm = ((CurveFactory::gamma((double)65535.0/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) - \
|
||||
(CurveFactory::gamma((double)65536.0/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)));
|
||||
for (int i=0; i<0x10000; i++) {
|
||||
nrwt_l[i] = ((CurveFactory::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) - \
|
||||
(CurveFactory::gamma((double)(i+1)/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) )/nrwtl_norm;
|
||||
//nrwt_l[i] = ((float)(gamcurve[i + 16] - gamcurve[i])/16.0);
|
||||
//int test = gamcurve[i + 16] - gamcurve[i];
|
||||
//if (i % 100 ==0) printf("%d %f \n",i,nrwt_l[i]);
|
||||
}
|
||||
for (int i=0; i<0x20000; i++)
|
||||
nrwt_ab[i] = ((1+abs(i-0x10000)/(1+8*noise_ab)) * exp(-(double)fabs(i-0x10000)/ (1+8*noise_ab) ) );
|
||||
|
||||
|
||||
//for (int i=0; i<65536; i+=100) printf("%d %d \n",i,gamcurve[i]);
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
|
||||
int level;
|
||||
@@ -214,20 +210,16 @@ namespace rtengine {
|
||||
|
||||
for(int level = maxlevel - 1; level > 0; level--)
|
||||
{
|
||||
//float noisevar_L = SQR(25.0 * luma)/pow(2.0,(level+1)*(1+c[2]/100));
|
||||
//float noisevar_ab = SQR(100.0 * chroma);
|
||||
|
||||
|
||||
int scale = scales[level];
|
||||
int pitch = pitches[level];
|
||||
idirpyr(dirpyrLablo[level], dirpyrLablo[level-1], level, irangefn_L, irangefn_ab, nrwt_l, nrwt_ab, pitch, scale, luma, chroma );
|
||||
idirpyr(dirpyrLablo[level], dirpyrLablo[level-1], level, nrwt_l, nrwt_ab, pitch, scale, luma, chroma );
|
||||
}
|
||||
|
||||
//noisevar_L = SQR(25.0 * luma);
|
||||
//noisevar_ab = SQR(100.0 * chroma);
|
||||
|
||||
|
||||
scale = scales[0];
|
||||
pitch = pitches[0];
|
||||
idirpyr(dirpyrLablo[0], dst, 0, irangefn_L, irangefn_ab, nrwt_l, nrwt_ab, pitch, scale, luma, chroma );
|
||||
idirpyr(dirpyrLablo[0], dst, 0, nrwt_l, nrwt_ab, pitch, scale, luma, chroma );
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
@@ -236,7 +228,6 @@ namespace rtengine {
|
||||
float igam = 1/gam;
|
||||
float igamthresh = gamthresh*gamslope;
|
||||
float igamslope = 1/gamslope;
|
||||
//unsigned short igamcurve[65536];
|
||||
for (int i=0; i<65536; i++) {
|
||||
int g = (int)(CurveFactory::gamma((float)i/65535.0, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0);
|
||||
gamcurve[i] = CLIP(g);
|
||||
@@ -247,10 +238,11 @@ namespace rtengine {
|
||||
for (int j=0; j<dst->W; j++) {
|
||||
|
||||
dst->L[i][j] = gamcurve[CLIP(dst->L[i][j]) ];
|
||||
|
||||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
for(int i = 0; i < maxlevel; i++)
|
||||
{
|
||||
@@ -263,7 +255,7 @@ namespace rtengine {
|
||||
delete [] irangefn_ab;
|
||||
delete [] nrwt_l;
|
||||
delete [] nrwt_ab;
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
};
|
||||
|
||||
@@ -284,31 +276,21 @@ namespace rtengine {
|
||||
int width = data_fine->W;
|
||||
int height = data_fine->H;
|
||||
|
||||
float norm_l, norm_ab;
|
||||
float dirwt_l, dirwt_ab, norm_l, norm_ab;
|
||||
//float lops,aops,bops;
|
||||
float dirwt_l, dirwt_ab;
|
||||
float Lout, aout, bout;
|
||||
//generate domain kernel (eg gaussian)
|
||||
|
||||
//float noisevar_L = SQR(25.0 * luma)/pow(2.0,(level+1)*(1-c[2]/100));
|
||||
//float noisevar_ab = SQR(100.0 * chroma);
|
||||
/*float noise_L = 25*abs(luma);
|
||||
float noisevar_L = SQR(25.0 * luma);
|
||||
float noise_ab = 25.0*abs(chroma);
|
||||
float noisevar_ab = SQR(25.0 * chroma);
|
||||
|
||||
float sig = 1.0;//MAX(0.5,(float)c[3]/10);*/
|
||||
|
||||
|
||||
//generate domain kernel
|
||||
int halfwin = 3;//MIN(ceil(2*sig),3);
|
||||
int scalewin = halfwin*scale;
|
||||
//int intfactor = 16384;
|
||||
|
||||
/*float domker[7][7];
|
||||
for (int i=-halfwin; i<=halfwin; i++)
|
||||
for (int j=-halfwin; j<=halfwin; j++) {
|
||||
domker[i+halfwin][j+halfwin] = (int)(exp(-(i*i+j*j)/(2*sig*sig))*intfactor); //or should we use a value that depends on sigma???
|
||||
}*/
|
||||
for (int i=-halfwin; i<=halfwin; i++)
|
||||
for (int j=-halfwin; j<=halfwin; j++) {
|
||||
domker[i+halfwin][j+halfwin] = (int)(exp(-(i*i+j*j)/(2*sig*sig))*intfactor); //or should we use a value that depends on sigma???
|
||||
}*/
|
||||
//float domker[5][5] = {{1,1,1,1,1},{1,2,2,2,1},{1,2,4,2,1},{1,2,2,2,1},{1,1,1,1,1}};
|
||||
|
||||
for(int i = 0, i1=0; i < height; i+=pitch, i1++) {
|
||||
@@ -339,7 +321,7 @@ namespace rtengine {
|
||||
//lops = Lout/norm;//diagnostic
|
||||
//aops = aout/normab;//diagnostic
|
||||
//bops = bout/normab;//diagnostic
|
||||
|
||||
|
||||
//data_coarse->L[i1][j1]=0.5*(data_fine->L[i][j]+Lout/norm_l);//low pass filter
|
||||
//data_coarse->a[i1][j1]=0.5*(data_fine->a[i][j]+aout/norm_ab);
|
||||
//data_coarse->b[i1][j1]=0.5*(data_fine->b[i][j]+bout/norm_ab);
|
||||
@@ -357,29 +339,26 @@ namespace rtengine {
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void ImProcFunctions::idirpyr(LabImage* data_coarse, LabImage* data_fine, int level, int * irangefn_L, int * irangefn_ab, float * nrwt_l, float * nrwt_ab, int pitch, int scale, const int luma, const int chroma )
|
||||
void ImProcFunctions::idirpyr(LabImage* data_coarse, LabImage* data_fine, int level, float * nrwt_l, float * nrwt_ab, int pitch, int scale, const int luma, const int chroma )
|
||||
{
|
||||
|
||||
int width = data_fine->W;
|
||||
int height = data_fine->H;
|
||||
|
||||
//float eps = 0.0;
|
||||
double wtdsum[3], dirwt_l, dirwt_ab, norm_l, norm_ab;
|
||||
float hipass[3], hpffluct[3], tonefactor=1, nrfactor;
|
||||
int dx, dy;
|
||||
double wtdsum[3], norm;
|
||||
float hipass[3], hpffluct[3], tonefactor, nrfactor;
|
||||
int i1, j1;
|
||||
|
||||
// c[0] = luma = noise_L
|
||||
// c[1] = chroma = noise_ab
|
||||
// c[0] noise_L
|
||||
// c[1] noise_ab (relative to noise_L)
|
||||
// c[2] decrease of noise var with scale
|
||||
// c[3] radius of domain blur at each level
|
||||
// c[4] shadow smoothing
|
||||
// c[5] edge preservation
|
||||
|
||||
|
||||
float noisevar_L = 4*SQR(25.0 * luma);
|
||||
float noisevar_ab = 2*SQR(100.0 * chroma);
|
||||
//float sig = 1.0;//MAX(0.5,(float)c[3]/10);
|
||||
float scalefactor = 1.0/pow(2.0,(level+1)*2);//change the last 2 to 1 for longer tail of higher scale NR
|
||||
//float shadowsmooth = ((float)c[4]/100);
|
||||
//float recontrast = (1+((float)(c[6])/100.0));
|
||||
//float resaturate = 10*(1+((float)(c[7])/100.0));
|
||||
noisevar_L *= scalefactor;
|
||||
@@ -388,10 +367,10 @@ namespace rtengine {
|
||||
//int intfactor= 16384;
|
||||
//int winwidth=1+2*halfwin;//this belongs in calling function
|
||||
/*float domker[7][7];
|
||||
for (int i=-halfwin; i<=halfwin; i++)
|
||||
for (int j=-halfwin; j<=halfwin; j++) {
|
||||
domker[i][j] = (int)(exp(-(i*i+j*j)/(2*sig*sig))*intfactor); //or should we use a value that depends on sigma???
|
||||
}*/
|
||||
for (int i=-halfwin; i<=halfwin; i++)
|
||||
for (int j=-halfwin; j<=halfwin; j++) {
|
||||
domker[i][j] = (int)(exp(-(i*i+j*j)/(2*sig*sig))*intfactor); //or should we use a value that depends on sigma???
|
||||
}*/
|
||||
//float domker[5][5] = {{1,1,1,1,1},{1,2,2,2,1},{1,2,4,2,1},{1,2,2,2,1},{1,1,1,1,1}};
|
||||
|
||||
LabImage* smooth;
|
||||
@@ -422,7 +401,6 @@ namespace rtengine {
|
||||
smooth->L[i][j] = data_coarse->L[i1][j1];
|
||||
smooth->a[i][j] = data_coarse->a[i1][j1];
|
||||
smooth->b[i][j] = data_coarse->b[i1][j1];
|
||||
//data_fine[i][j] = data_coarse[i1][j1];//for testing, when not subsampled
|
||||
}
|
||||
|
||||
if (pitch>1) {//pitch=2; expand coarse image, fill in missing data
|
||||
@@ -430,81 +408,64 @@ namespace rtengine {
|
||||
for(int i = 0; i < height-1; i+=2)
|
||||
for(int j = 0; j < width-1; j+=2) {
|
||||
//do midpoint first
|
||||
norm_l=norm_ab=0.0;
|
||||
norm=0;
|
||||
wtdsum[0]=wtdsum[1]=wtdsum[2]=0.0;
|
||||
for(dx=0; dx<=2; dx+=2)
|
||||
for (dy=0; dy<=2; dy+=2) {
|
||||
if (i+dy>=height || j+dx>=width ) continue;
|
||||
dirwt_l = 1;//IDIRWT_L(i+dy, j+dx, i+1, j+1);
|
||||
dirwt_ab = 1;//IDIRWT_AB(i+dy, j+dx, i+1, j+1);
|
||||
wtdsum[0] += dirwt_l*smooth->L[i+dy][j+dx];
|
||||
wtdsum[1] += dirwt_ab*smooth->a[i+dy][j+dx];
|
||||
wtdsum[2] += dirwt_ab*smooth->b[i+dy][j+dx];
|
||||
norm_l += dirwt_l;
|
||||
norm_ab += dirwt_ab;
|
||||
for(i1=i; i1<MIN(height,i+3); i1+=2)
|
||||
for (j1=j; j1<MIN(width,j+3); j1+=2) {
|
||||
wtdsum[0] += smooth->L[i1][j1];
|
||||
wtdsum[1] += smooth->a[i1][j1];
|
||||
wtdsum[2] += smooth->b[i1][j1];
|
||||
norm++;
|
||||
}
|
||||
smooth->L[i+1][j+1]=wtdsum[0]/norm_l;
|
||||
smooth->a[i+1][j+1]=wtdsum[1]/norm_ab;
|
||||
smooth->b[i+1][j+1]=wtdsum[2]/norm_ab;
|
||||
norm = 1/norm;
|
||||
smooth->L[i+1][j+1]=wtdsum[0]*norm;
|
||||
smooth->a[i+1][j+1]=wtdsum[1]*norm;
|
||||
smooth->b[i+1][j+1]=wtdsum[2]*norm;
|
||||
}
|
||||
|
||||
|
||||
for(int i = 0; i < height-1; i+=2)
|
||||
for(int j = 0; j < width-1; j+=2) {
|
||||
//now right neighbor
|
||||
if (j+1==width) continue;
|
||||
norm_l=norm_ab=0.0;
|
||||
norm=0;
|
||||
wtdsum[0]=wtdsum[1]=wtdsum[2]=0.0;
|
||||
for (dx=0; dx<=2; dx+=2) {
|
||||
if (j+dx>=width ) continue;
|
||||
dirwt_l = 1;//IDIRWT_L(i, j+dx, i, j+1);
|
||||
dirwt_ab = 1;//IDIRWT_AB(i, j+dx, i, j+1);
|
||||
wtdsum[0] += dirwt_l*smooth->L[i][j+dx];
|
||||
wtdsum[1] += dirwt_ab*smooth->a[i][j+dx];
|
||||
wtdsum[2] += dirwt_ab*smooth->b[i][j+dx];
|
||||
norm_l += dirwt_l;
|
||||
norm_ab += dirwt_ab;
|
||||
for (j1=j; j1<MIN(width,j+3); j1+=2) {
|
||||
wtdsum[0] += smooth->L[i][j1];
|
||||
wtdsum[1] += smooth->a[i][j1];
|
||||
wtdsum[2] += smooth->b[i][j1];
|
||||
norm++;
|
||||
}
|
||||
for (dy=-1; dy<=1; dy+=2) {
|
||||
if (i+dy<0 || i+dy>=height) continue;
|
||||
dirwt_l = 1;//IDIRWT_L(i+dy,j+1,i,j+1);
|
||||
dirwt_ab = 1;//IDIRWT_AB(i+dy,j+1,i,j+1);
|
||||
wtdsum[0] += dirwt_l*smooth->L[i+dy][j+1];
|
||||
wtdsum[1] += dirwt_ab*smooth->a[i+dy][j+1];
|
||||
wtdsum[2] += dirwt_ab*smooth->b[i+dy][j+1];
|
||||
norm_l += dirwt_l;
|
||||
norm_ab += dirwt_ab;
|
||||
for (i1=MAX(0,i-1); i1<MIN(height,i+2); i1+=2) {
|
||||
wtdsum[0] += smooth->L[i1][j+1];
|
||||
wtdsum[1] += smooth->a[i1][j+1];
|
||||
wtdsum[2] += smooth->b[i1][j+1];
|
||||
norm++;
|
||||
}
|
||||
smooth->L[i][j+1]=wtdsum[0]/norm_l;
|
||||
smooth->a[i][j+1]=wtdsum[1]/norm_ab;
|
||||
smooth->b[i][j+1]=wtdsum[2]/norm_ab;
|
||||
norm = 1/norm;
|
||||
smooth->L[i][j+1]=wtdsum[0]*norm;
|
||||
smooth->a[i][j+1]=wtdsum[1]*norm;
|
||||
smooth->b[i][j+1]=wtdsum[2]*norm;
|
||||
|
||||
//now down neighbor
|
||||
if (i+1==height) continue;
|
||||
norm_l=norm_ab=0.0;
|
||||
norm=0;
|
||||
wtdsum[0]=wtdsum[1]=wtdsum[2]=0.0;
|
||||
for (dy=0; dy<=2; dy+=2) {
|
||||
if (i+dy>=height) continue;
|
||||
dirwt_l = 1;//IDIRWT_L(i+dy,j,i+1,j);
|
||||
dirwt_ab = 1;//IDIRWT_AB(i+dy,j,i+1,j);
|
||||
wtdsum[0] += dirwt_l*smooth->L[i+dy][j];
|
||||
wtdsum[1] += dirwt_ab*smooth->a[i+dy][j];
|
||||
wtdsum[2] += dirwt_ab*smooth->b[i+dy][j];
|
||||
norm_l += dirwt_l;
|
||||
norm_ab += dirwt_ab;
|
||||
for (i1=i; i1<MIN(height,i+3); i1+=2) {
|
||||
wtdsum[0] += smooth->L[i1][j];
|
||||
wtdsum[1] += smooth->a[i1][j];
|
||||
wtdsum[2] += smooth->b[i1][j];
|
||||
norm++;
|
||||
}
|
||||
for (dx=-1; dx<=1; dx+=2) {
|
||||
if (j+dx<0 || j+dx>=width ) continue;
|
||||
dirwt_l = 1;//IDIRWT_L(i+1,j+dx,i+1,j);
|
||||
dirwt_ab = 1;//IDIRWT_AB(i+1,j+dx,i+1,j);
|
||||
wtdsum[0] += dirwt_l*smooth->L[i+1][j+dx];
|
||||
wtdsum[1] += dirwt_ab*smooth->a[i+1][j+dx];
|
||||
wtdsum[2] += dirwt_ab*smooth->b[i+1][j+dx];
|
||||
norm_l += dirwt_l;
|
||||
norm_ab += dirwt_ab;
|
||||
for (j1=j-1; j1<MIN(width,j+2); j1+=2) {
|
||||
wtdsum[0] += smooth->L[i+1][j1];
|
||||
wtdsum[1] += smooth->a[i+1][j1];
|
||||
wtdsum[2] += smooth->b[i+1][j1];
|
||||
norm++;
|
||||
}
|
||||
smooth->L[i+1][j]=wtdsum[0]/norm_l;
|
||||
smooth->a[i+1][j]=wtdsum[1]/norm_ab;
|
||||
smooth->b[i+1][j]=wtdsum[2]/norm_ab;
|
||||
norm=1/norm;
|
||||
smooth->L[i+1][j]=wtdsum[0]*norm;
|
||||
smooth->a[i+1][j]=wtdsum[1]*norm;
|
||||
smooth->b[i+1][j]=wtdsum[2]*norm;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -513,26 +474,30 @@ namespace rtengine {
|
||||
for(int i = 0; i < height; i++)
|
||||
for(int j = 0; j < width; j++) {
|
||||
|
||||
//tonefactor = ((NRWT_L(smooth->L[i][j])));
|
||||
hipass[0] = data_fine->L[i][j]-smooth->L[i][j];
|
||||
hipass[1] = data_fine->a[i][j]-smooth->a[i][j];
|
||||
hipass[2] = data_fine->b[i][j]-smooth->b[i][j];
|
||||
|
||||
tonefactor = ((NRWT_L(smooth->L[i][j])));
|
||||
|
||||
//Wiener filter
|
||||
hpffluct[0]=SQR(hipass[0])+0.001;
|
||||
hipass[0] *= hpffluct[0]/(hpffluct[0]+noisevar_L);
|
||||
hpffluct[1]=SQR(hipass[1]/*tonefactor*/)+0.001;
|
||||
hpffluct[2]=SQR(hipass[2]/*tonefactor*/)+0.001;
|
||||
//luma
|
||||
if (level<3) {
|
||||
hipass[0] = data_fine->L[i][j]-smooth->L[i][j];
|
||||
hpffluct[0]=SQR(hipass[0])+0.001;
|
||||
hipass[0] *= hpffluct[0]/(hpffluct[0]+noisevar_L);
|
||||
}
|
||||
|
||||
//chroma
|
||||
hipass[1] = data_fine->a[i][j]-smooth->a[i][j];
|
||||
hipass[2] = data_fine->b[i][j]-smooth->b[i][j];
|
||||
hpffluct[1]=SQR(hipass[1]*tonefactor)+0.001;
|
||||
hpffluct[2]=SQR(hipass[2]*tonefactor)+0.001;
|
||||
nrfactor = (hpffluct[1]+hpffluct[2]) /((hpffluct[1]+hpffluct[2]) + noisevar_ab * NRWT_AB);
|
||||
//nrfactor *= resaturate;
|
||||
/*if (level) {
|
||||
hipass[0] *= recontrast;
|
||||
nrfactor *= resaturate;
|
||||
}*/
|
||||
hipass[0] *= recontrast;
|
||||
nrfactor *= resaturate;
|
||||
}*/
|
||||
hipass[1] *= nrfactor;
|
||||
hipass[2] *= nrfactor;
|
||||
|
||||
|
||||
//hipass[0] = hipass[1] = hipass[2] = 0.0;//for testing
|
||||
|
||||
wtdsum[0]=data_fine->L[i][j] = CLIP(hipass[0]+smooth->L[i][j]);
|
||||
@@ -546,9 +511,9 @@ namespace rtengine {
|
||||
|
||||
#undef DIRWT_L
|
||||
#undef DIRWT_AB
|
||||
|
||||
|
||||
#undef NRWT_L
|
||||
#undef NRWT_AB
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -442,7 +442,7 @@ void ImProcFunctions::colorCurve (LabImage* lold, LabImage* lnew) {
|
||||
|
||||
if (params->dirpyrDenoise.enabled && lab->W>=8 && lab->H>=8)
|
||||
|
||||
dirpyrLab_denoise(lab, lab, params->dirpyrDenoise.luma, params->dirpyrDenoise.chroma );
|
||||
dirpyrLab_denoise(lab, lab, params->dirpyrDenoise.luma, params->dirpyrDenoise.chroma, params->dirpyrDenoise.gamma/3.0 );
|
||||
}
|
||||
|
||||
void ImProcFunctions::lumadenoise (LabImage* lab, int** b2) {
|
||||
|
@@ -95,9 +95,9 @@ class ImProcFunctions {
|
||||
void impulsedenoise (LabImage* lab);//Emil's impulse denoise
|
||||
void dirpyrdenoise (LabImage* lab);//Emil's impulse denoise
|
||||
|
||||
void dirpyrLab_denoise(LabImage * src, LabImage * dst, const int luma, const int chroma );//Emil's directional pyramid denoise
|
||||
void dirpyrLab_denoise(LabImage * src, LabImage * dst, const int luma, const int chroma, float gamma );//Emil's directional pyramid denoise
|
||||
void dirpyr(LabImage* data_fine, LabImage* data_coarse, int level, int * rangefn_L, int * rangefn_ab, int pitch, int scale, const int luma, const int chroma );
|
||||
void idirpyr(LabImage* data_coarse, LabImage* data_fine, int level, int * irangefn_L, int * irangefn_ab, float * nrwt_l, float * nrwt_ab, int pitch, int scale, const int luma, const int chroma );
|
||||
void idirpyr(LabImage* data_coarse, LabImage* data_fine, int level, float * nrwt_l, float * nrwt_ab, int pitch, int scale, const int luma, const int chroma );
|
||||
|
||||
|
||||
Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile);
|
||||
|
@@ -21,7 +21,7 @@
|
||||
|
||||
#include <rtengine.h>
|
||||
|
||||
#define NUMOFEVENTS 91
|
||||
#define NUMOFEVENTS 92
|
||||
|
||||
|
||||
namespace rtengine {
|
||||
@@ -117,7 +117,8 @@ enum ProcEvent {
|
||||
EvIDNThresh=87,
|
||||
EvDPDNEnabled=88,
|
||||
EvDPDNLuma=89,
|
||||
EvDPDNChroma=90
|
||||
EvDPDNChroma=90,
|
||||
EvDPDNGamma=91
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@@ -101,6 +101,7 @@ void ProcParams::setDefaults () {
|
||||
dirpyrDenoise.enabled = false;
|
||||
dirpyrDenoise.luma = 10;
|
||||
dirpyrDenoise.chroma = 10;
|
||||
dirpyrDenoise.gamma = 2.0;
|
||||
|
||||
sh.enabled = false;
|
||||
sh.hq = false;
|
||||
@@ -253,7 +254,8 @@ int ProcParams::save (Glib::ustring fname) const {
|
||||
keyFile.set_boolean ("Directional Pyramid Denoising", "Enabled", dirpyrDenoise.enabled);
|
||||
keyFile.set_integer ("Directional Pyramid Denoising", "Luma", dirpyrDenoise.luma);
|
||||
keyFile.set_integer ("Directional Pyramid Denoising", "Chroma", dirpyrDenoise.chroma);
|
||||
|
||||
keyFile.set_double ("Directional Pyramid Denoising", "Gamma", dirpyrDenoise.gamma);
|
||||
|
||||
// save lumaDenoise
|
||||
keyFile.set_boolean ("Luminance Denoising", "Enabled", lumaDenoise.enabled);
|
||||
keyFile.set_double ("Luminance Denoising", "Radius", lumaDenoise.radius);
|
||||
@@ -472,6 +474,7 @@ if (keyFile.has_group ("Directional Pyramid Denoising")) {
|
||||
if (keyFile.has_key ("Directional Pyramid Denoising", "Enabled")) dirpyrDenoise.enabled = keyFile.get_boolean ("Directional Pyramid Denoising", "Enabled");
|
||||
if (keyFile.has_key ("Directional Pyramid Denoising", "Luma")) dirpyrDenoise.luma = keyFile.get_integer ("Directional Pyramid Denoising", "Luma");
|
||||
if (keyFile.has_key ("Directional Pyramid Denoising", "Chroma")) dirpyrDenoise.chroma = keyFile.get_integer ("Directional Pyramid Denoising", "Chroma");
|
||||
if (keyFile.has_key ("Directional Pyramid Denoising", "Gamma")) dirpyrDenoise.gamma = keyFile.get_double ("Directional Pyramid Denoising", "Gamma");
|
||||
}
|
||||
|
||||
// load lumaDenoise
|
||||
@@ -683,6 +686,7 @@ bool ProcParams::operator== (const ProcParams& other) {
|
||||
&& dirpyrDenoise.enabled == other.dirpyrDenoise.enabled
|
||||
&& dirpyrDenoise.luma == other.dirpyrDenoise.luma
|
||||
&& dirpyrDenoise.chroma == other.dirpyrDenoise.chroma
|
||||
&& dirpyrDenoise.gamma == other.dirpyrDenoise.gamma
|
||||
&& lumaDenoise.enabled == other.lumaDenoise.enabled
|
||||
&& lumaDenoise.radius == other.lumaDenoise.radius
|
||||
&& lumaDenoise.edgetolerance == other.lumaDenoise.edgetolerance
|
||||
|
@@ -153,6 +153,7 @@ class ColorDenoiseParams {
|
||||
bool enabled;
|
||||
int luma;
|
||||
int chroma;
|
||||
float gamma;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -109,6 +109,7 @@ IMPULSEDENOISE, // EvIDNEnabled,
|
||||
IMPULSEDENOISE, // EvIDNThresh,
|
||||
DIRPYRDENOISE, // EvDPDNEnabled,
|
||||
DIRPYRDENOISE, // EvDPDNLuma,
|
||||
DIRPYRDENOISE // EvDPDNChroma,
|
||||
DIRPYRDENOISE, // EvDPDNChroma,
|
||||
DIRPYRDENOISE // EvDPDNGamma,
|
||||
};
|
||||
|
||||
|
@@ -24,92 +24,112 @@ using namespace rtengine;
|
||||
using namespace rtengine::procparams;
|
||||
|
||||
DirPyrDenoise::DirPyrDenoise () : ToolPanel () {
|
||||
|
||||
enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED")));
|
||||
enabled->set_active (false);
|
||||
enabled->show ();
|
||||
pack_start (*enabled);
|
||||
|
||||
Gtk::HSeparator *hsep1 = Gtk::manage (new Gtk::HSeparator());
|
||||
hsep1->show ();
|
||||
pack_start (*hsep1);
|
||||
|
||||
enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &DirPyrDenoise::enabledChanged) );
|
||||
|
||||
luma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_LUMA"), 0, 100, 1, 10));
|
||||
chroma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_CHROMA"), 0, 100, 1, 10));
|
||||
gamma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_GAMMA"), 1.0, 3.0, 0.01, 0.10));
|
||||
|
||||
luma->setAdjusterListener (this);
|
||||
chroma->setAdjusterListener (this);
|
||||
gamma->setAdjusterListener (this);
|
||||
|
||||
luma->show();
|
||||
chroma->show();
|
||||
gamma->show();
|
||||
|
||||
pack_start (*luma);
|
||||
pack_start (*chroma);
|
||||
pack_start (*gamma);
|
||||
|
||||
enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED")));
|
||||
enabled->set_active (false);
|
||||
enabled->show ();
|
||||
pack_start (*enabled);
|
||||
|
||||
Gtk::HSeparator *hsep1 = Gtk::manage (new Gtk::HSeparator());
|
||||
hsep1->show ();
|
||||
pack_start (*hsep1);
|
||||
|
||||
enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &DirPyrDenoise::enabledChanged) );
|
||||
|
||||
luma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_LUMA"), 0, 100, 1, 10));
|
||||
chroma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_CHROMA"), 0, 100, 1, 10));
|
||||
luma->setAdjusterListener (this);
|
||||
chroma->setAdjusterListener (this);
|
||||
luma->show();
|
||||
chroma->show();
|
||||
|
||||
pack_start (*luma);
|
||||
pack_start (*chroma);
|
||||
}
|
||||
|
||||
void DirPyrDenoise::read (const ProcParams* pp, const ParamsEdited* pedited) {
|
||||
|
||||
|
||||
disableListener ();
|
||||
|
||||
|
||||
if (pedited) {
|
||||
luma->setEditedState (pedited->dirpyrDenoise.luma ? Edited : UnEdited);
|
||||
chroma->setEditedState (pedited->dirpyrDenoise.chroma ? Edited : UnEdited);
|
||||
gamma->setEditedState (pedited->dirpyrDenoise.gamma ? Edited : UnEdited);
|
||||
enabled->set_inconsistent (!pedited->dirpyrDenoise.enabled);
|
||||
}
|
||||
|
||||
|
||||
enaConn.block (true);
|
||||
enabled->set_active (pp->dirpyrDenoise.enabled);
|
||||
enaConn.block (false);
|
||||
|
||||
lastEnabled = pp->dirpyrDenoise.enabled;
|
||||
|
||||
|
||||
luma->setValue (pp->dirpyrDenoise.luma);
|
||||
chroma->setValue (pp->dirpyrDenoise.chroma);
|
||||
gamma->setValue (pp->dirpyrDenoise.gamma);
|
||||
|
||||
enableListener ();
|
||||
}
|
||||
|
||||
void DirPyrDenoise::write (ProcParams* pp, ParamsEdited* pedited) {
|
||||
|
||||
pp->dirpyrDenoise.luma = luma->getValue ();
|
||||
pp->dirpyrDenoise.chroma = chroma->getValue ();
|
||||
pp->dirpyrDenoise.enabled = enabled->get_active();
|
||||
|
||||
|
||||
pp->dirpyrDenoise.luma = luma->getValue ();
|
||||
pp->dirpyrDenoise.chroma = chroma->getValue ();
|
||||
pp->dirpyrDenoise.gamma = gamma->getValue ();
|
||||
pp->dirpyrDenoise.enabled = enabled->get_active();
|
||||
|
||||
if (pedited) {
|
||||
pedited->dirpyrDenoise.luma = luma->getEditedState ();
|
||||
pedited->dirpyrDenoise.chroma = chroma->getEditedState ();
|
||||
pedited->dirpyrDenoise.enabled = !enabled->get_inconsistent();
|
||||
pedited->dirpyrDenoise.gamma = gamma->getEditedState ();
|
||||
pedited->dirpyrDenoise.enabled = !enabled->get_inconsistent();
|
||||
}
|
||||
}
|
||||
|
||||
void DirPyrDenoise::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) {
|
||||
|
||||
|
||||
luma->setDefault (defParams->dirpyrDenoise.luma);
|
||||
chroma->setDefault (defParams->dirpyrDenoise.chroma);
|
||||
gamma->setDefault (defParams->dirpyrDenoise.chroma);
|
||||
|
||||
if (pedited) {
|
||||
luma->setDefaultEditedState (pedited->dirpyrDenoise.luma ? Edited : UnEdited);
|
||||
chroma->setDefaultEditedState (pedited->dirpyrDenoise.chroma ? Edited : UnEdited);
|
||||
}
|
||||
gamma->setDefaultEditedState (pedited->dirpyrDenoise.gamma ? Edited : UnEdited);
|
||||
}
|
||||
else {
|
||||
luma->setDefaultEditedState (Irrelevant);
|
||||
chroma->setDefaultEditedState (Irrelevant);
|
||||
gamma->setDefaultEditedState (Irrelevant);
|
||||
}
|
||||
}
|
||||
|
||||
void DirPyrDenoise::adjusterChanged (Adjuster* a, double newval) {
|
||||
|
||||
|
||||
if (listener && enabled->get_active()) {
|
||||
|
||||
if (a==luma)
|
||||
listener->panelChanged (EvDPDNLuma, Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(1), a->getValue()));
|
||||
else if (a==chroma)
|
||||
if (a==luma) {
|
||||
listener->panelChanged (EvDPDNLuma, Glib::ustring::format ((int)a->getValue()));
|
||||
} else {
|
||||
if (a==chroma) {
|
||||
listener->panelChanged (EvDPDNChroma, Glib::ustring::format ((int)a->getValue()));
|
||||
}
|
||||
} else {
|
||||
if (a==gamma)
|
||||
listener->panelChanged (EvDPDNGamma, Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(2), a->getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DirPyrDenoise::enabledChanged () {
|
||||
|
||||
|
||||
if (batchMode) {
|
||||
if (enabled->get_inconsistent()) {
|
||||
enabled->set_inconsistent (false);
|
||||
@@ -119,10 +139,10 @@ void DirPyrDenoise::enabledChanged () {
|
||||
}
|
||||
else if (lastEnabled)
|
||||
enabled->set_inconsistent (true);
|
||||
|
||||
|
||||
lastEnabled = enabled->get_active ();
|
||||
}
|
||||
|
||||
|
||||
if (listener) {
|
||||
if (enabled->get_active ())
|
||||
listener->panelChanged (EvDPDNEnabled, M("GENERAL_ENABLED"));
|
||||
@@ -132,18 +152,18 @@ void DirPyrDenoise::enabledChanged () {
|
||||
}
|
||||
|
||||
void DirPyrDenoise::setBatchMode (bool batchMode) {
|
||||
|
||||
|
||||
ToolPanel::setBatchMode (batchMode);
|
||||
luma->showEditedCB ();
|
||||
chroma->showEditedCB ();
|
||||
}
|
||||
|
||||
/*void DirPyrDenoise::setAdjusterBehavior (bool bedgetoladd) {
|
||||
|
||||
if (!edgetolAdd && bedgetoladd)
|
||||
edge->setLimits (-10000, 10000, 100, 0);
|
||||
else if (edgetolAdd && !bedgetoladd)
|
||||
edge->setLimits (10, 30000, 100, 1500);
|
||||
|
||||
edgetolAdd = bedgetoladd;
|
||||
}*/
|
||||
|
||||
if (!edgetolAdd && bedgetoladd)
|
||||
edge->setLimits (-10000, 10000, 100, 0);
|
||||
else if (edgetolAdd && !bedgetoladd)
|
||||
edge->setLimits (10, 30000, 100, 1500);
|
||||
|
||||
edgetolAdd = bedgetoladd;
|
||||
}*/
|
||||
|
@@ -28,6 +28,8 @@ class DirPyrDenoise : public Gtk::VBox, public AdjusterListener, public ToolPane
|
||||
protected:
|
||||
Adjuster* luma;
|
||||
Adjuster* chroma;
|
||||
Adjuster* gamma;
|
||||
|
||||
Gtk::CheckButton* enabled;
|
||||
bool lastEnabled;
|
||||
sigc::connection enaConn;
|
||||
|
@@ -73,7 +73,8 @@ void ParamsEdited::set (bool v) {
|
||||
dirpyrDenoise.enabled = v;
|
||||
dirpyrDenoise.luma = v;
|
||||
dirpyrDenoise.chroma = v;
|
||||
sh.enabled = v;
|
||||
dirpyrDenoise.gamma = v;
|
||||
sh.enabled = v;
|
||||
sh.hq = v;
|
||||
sh.highlights = v;
|
||||
sh.htonalwidth = v;
|
||||
@@ -192,7 +193,8 @@ void ParamsEdited::initFrom (const std::vector<rtengine::procparams::ProcParams>
|
||||
dirpyrDenoise.enabled = dirpyrDenoise.enabled && p.dirpyrDenoise.enabled == other.dirpyrDenoise.enabled;
|
||||
dirpyrDenoise.luma = dirpyrDenoise.luma && p.dirpyrDenoise.luma == other.dirpyrDenoise.luma;
|
||||
dirpyrDenoise.chroma = dirpyrDenoise.chroma && p.dirpyrDenoise.chroma == other.dirpyrDenoise.chroma;
|
||||
|
||||
dirpyrDenoise.gamma = dirpyrDenoise.gamma && p.dirpyrDenoise.gamma == other.dirpyrDenoise.gamma;
|
||||
|
||||
sh.enabled = sh.enabled && p.sh.enabled == other.sh.enabled;
|
||||
sh.hq = sh.hq && p.sh.hq == other.sh.hq;
|
||||
sh.highlights = sh.highlights && p.sh.highlights == other.sh.highlights;
|
||||
@@ -302,7 +304,8 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
|
||||
if (dirpyrDenoise.enabled) toEdit.dirpyrDenoise.enabled = mods.dirpyrDenoise.enabled;
|
||||
if (dirpyrDenoise.luma) toEdit.dirpyrDenoise.luma = mods.dirpyrDenoise.luma;
|
||||
if (dirpyrDenoise.chroma) toEdit.dirpyrDenoise.chroma = mods.dirpyrDenoise.chroma;
|
||||
|
||||
if (dirpyrDenoise.gamma) toEdit.dirpyrDenoise.gamma = mods.dirpyrDenoise.gamma;
|
||||
|
||||
if (sh.enabled) toEdit.sh.enabled = mods.sh.enabled;
|
||||
if (sh.hq) toEdit.sh.hq = mods.sh.hq;
|
||||
if (sh.highlights) toEdit.sh.highlights = options.baBehav[ADDSET_SH_HIGHLIGHTS] ? toEdit.sh.highlights + mods.sh.highlights : mods.sh.highlights;
|
||||
|
@@ -119,6 +119,7 @@ public:
|
||||
bool enabled;
|
||||
bool luma;
|
||||
bool chroma;
|
||||
bool gamma;
|
||||
};
|
||||
|
||||
class SHParamsEdited {
|
||||
|
Reference in New Issue
Block a user