diff --git a/rtdata/languages/default b/rtdata/languages/default index 059aaa914..92c0ec959 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -525,6 +525,9 @@ TP_CROP_SELECTCROP; Select Crop TP_CROP_W;W TP_CROP_X;x TP_CROP_Y;y +TP_DIRPYRDENOISE_CHROMA;Chrominance +TP_DIRPYRDENOISE_LABEL;Directional Pyramid Noise Reduction +TP_DIRPYRDENOISE_LUMA;Luminance TP_DISTORTION_AMOUNT;Amount TP_DISTORTION_LABEL;Distortion TP_EQUALIZER_LABEL;Wavelet equalizer @@ -562,6 +565,7 @@ TP_ICM_OUTPUTDLGLABEL;Select Output ICC Profile... TP_ICM_OUTPUTPROFILE;Output Profile TP_ICM_SAVEREFERENCE;Save reference image for profiling TP_ICM_WORKINGPROFILE;Working Profile +TP_IMPULSEDENOISE_LABEL;Impulse Noise Reduction TP_LENSGEOM_AUTOCROP;Auto Crop TP_LENSGEOM_FILL;Auto Fill TP_LENSGEOM_LABEL;Lens / Geometry diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index 4da57c5f5..81fcf13cb 100644 --- a/rtengine/CA_correct_RT.cc +++ b/rtengine/CA_correct_RT.cc @@ -109,7 +109,7 @@ void RawImageSource::CA_correct_RT() { /*static const float pre_mul[3] = {MIN(ri->red_multiplier,ri->green_multiplier), ri->green_multiplier, \ MIN(ri->blue_multiplier,ri->green_multiplier)};*/ - static const float clip_pt = ri->defgain; + const float clip_pt = ri->defgain; // local variables int width=W, height=H; diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index d5cae4e78..299cf9ed3 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -13,7 +13,7 @@ set (RTENGINESOURCEFILES colortemp.cc curves.cc dcraw.cc iccstore.cc stdimagesource.cc myfile.cc iccjpeg.c hlmultipliers.cc improccoordinator.cc processingjob.cc rtthumbnail.cc utils.cc labimage.cc iplab2rgb.cc ipsharpen.cc iptransform.cc ipresize.cc - wavelet_dec.cc ipequalizer.cc) + wavelet_dec.cc ipequalizer.cc dirpyrLab_denoise.cc ) add_library (rtengine ${RTENGINESOURCEFILES}) #It may be nice to store library version too diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 9b665ca0b..c578976e9 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -164,6 +164,7 @@ void Crop::update (int todo, bool internal) { if (todo & M_LUMINANCE) { parent->ipf.luminanceCurve (laboCrop, labnCrop, parent->lumacurve, 0, croph); if (skip==1) { + parent->ipf.impulsedenoise (labnCrop); parent->ipf.lumadenoise (labnCrop, cbuffer); parent->ipf.sharpening (labnCrop, (unsigned short**)cbuffer); parent->ipf.waveletEqualizer(labnCrop, true, false); @@ -175,6 +176,7 @@ void Crop::update (int todo, bool internal) { parent->ipf.colorCurve (laboCrop, labnCrop); if (skip==1) { parent->ipf.colordenoise (labnCrop, cbuffer); + parent->ipf.dirpyrdenoise (labnCrop); parent->ipf.waveletEqualizer(labnCrop, false, true); } } diff --git a/rtengine/dirpyrLab_denoise.cc b/rtengine/dirpyrLab_denoise.cc new file mode 100644 index 000000000..f6f750092 --- /dev/null +++ b/rtengine/dirpyrLab_denoise.cc @@ -0,0 +1,554 @@ +/* + * This file is part of RawTherapee. + * + * 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 . + * + * © 2010 Emil Martinec + * + */ + +//#include +#include +#include +#include +#include +#include + +#ifdef _OPENMP +#include +#endif + +#define SQR(x) ((x)*(x)) +#define CLIPTO(a,b,c) ((a)>(b)?((a)<(c)?(a):(c)):(b)) +#define CLIPC(a) ((a)>-32000?((a)<32000?(a):32000):-32000) +#define CLIP(a) (CLIPTO(a,0,65535)) + + + +#define DIRWT_L(i1,j1,i,j) (/*domker[(i1-i)/scale+halfwin][(j1-j)/scale+halfwin] */ rangefn_L[(int)(data_fine->L[i1][j1]-data_fine->L[i][j]+0x10000)] ) + +#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*/)]) + + + +namespace rtengine { + + static const int maxlevel = 4; + + //sequence of scales + //static const int scales[8] = {1,2,4,8,16,32,64,128}; + //sequence of pitches + //static const int pitches[8] = {1,1,1,1,1,1,1,1}; + + //sequence of scales + //static const int scales[8] = {1,1,1,1,1,1,1,1}; + //sequence of pitches + //static const int pitches[8] = {2,2,2,2,2,2,2,2}; + + //sequence of scales + //static const int scales[8] = {1,1,2,2,4,4,8,8}; + //sequence of pitches + //static const int pitches[8] = {2,1,2,1,2,1,2,1}; + + //sequence of scales + static const int scales[8] = {1,1,2,4,8,16,32,64}; + //sequence of pitches + static const int pitches[8] = {2,1,1,1,1,1,1,1}; + + //pitch is spacing of subsampling + //scale is spacing of directional averaging weights + //example 1: no subsampling at any level -- pitch=1, scale=2^n + //example 2: subsampling by 2 every level -- pitch=2, scale=1 at each level + //example 3: no subsampling at first level, subsampling by 2 thereafter -- + // pitch =1, scale=1 at first level; pitch=2, scale=2 thereafter + + + + + void ImProcFunctions :: dirpyrLab_denoise(LabImage * src, LabImage * dst, const int luma, const int chroma ) + { + 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]; + for (int i=0; i<65536; i++) { + int g = (int)(CurveFactory::gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0) * 65535.0); + //if (i<500) printf("%d %d \n",i,g); + gamcurve[i] = CLIP(g); + } + + + //#pragma omp parallel for if (multiThread) + for (int i=0; iH; i++) { + for (int j=0; jW; j++) { + src->L[i][j] = gamcurve[src->L[i][j] ]; + } + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + 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); + + 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 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); + 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); + + 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); + + //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) ) ); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + int level; + + LabImage * dirpyrLablo[maxlevel]; + int w = (int)((src->W-1)/pitches[0])+1; + int h = (int)((src->H-1)/pitches[0])+1; + dirpyrLablo[0] = new LabImage(w, h); + for (level=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 ); + } + + //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 ); + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + 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); + } + + + for (int i=0; iH; i++) + for (int j=0; jW; j++) { + + dst->L[i][j] = gamcurve[CLIP(dst->L[i][j]) ]; + + } + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + for(int i = 0; i < maxlevel; i++) + { + delete dirpyrLablo[i]; + } + + delete [] rangefn_L; + delete [] rangefn_ab; + delete [] irangefn_L; + delete [] irangefn_ab; + delete [] nrwt_l; + delete [] nrwt_ab; + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + }; + + void ImProcFunctions::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 ) + { + + //pitch is spacing of subsampling + //scale is spacing of directional averaging weights + //example 1: no subsampling at any level -- pitch=1, scale=2^n + //example 2: subsampling by 2 every level -- pitch=2, scale=1 at each level + //example 3: no subsampling at first level, subsampling by 2 thereafter -- + // pitch =1, scale=1 at first level; pitch=2, scale=2 thereafter + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // calculate weights, compute directionally weighted average + + int width = data_fine->W; + int height = data_fine->H; + + float 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);*/ + + + 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??? + }*/ + //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++) { + for(int j = 0, j1=0; j < width; j+=pitch, j1++) + { + //norm = DIRWT(i, j, i, j); + //Lout = -norm*data_fine->L[i][j];//if we don't want to include the input pixel in the sum + //aout = -norm*data_fine->a[i][j]; + //bout = -norm*data_fine->b[i][j]; + //or + norm_l = norm_ab = 0;//if we do want to include the input pixel in the sum + Lout = 0; + aout = 0; + bout = 0; + //normab = 0; + + for(int inbr=MAX(0,i-scalewin); inbr<=MIN(height-1,i+scalewin); inbr+=scale) { + for (int jnbr=MAX(0,j-scalewin); jnbr<=MIN(width-1,j+scalewin); jnbr+=scale) { + dirwt_l = DIRWT_L(inbr, jnbr, i, j); + dirwt_ab = DIRWT_AB(inbr, jnbr, i, j); + Lout += dirwt_l*data_fine->L[inbr][jnbr]; + aout += dirwt_ab*data_fine->a[inbr][jnbr]; + bout += dirwt_ab*data_fine->b[inbr][jnbr]; + norm_l += dirwt_l; + norm_ab += dirwt_ab; + } + } + //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); + //or + data_coarse->L[i1][j1]=Lout/norm_l;//low pass filter + data_coarse->a[i1][j1]=aout/norm_ab; + data_coarse->b[i1][j1]=bout/norm_ab; + } + } + + + + + }; + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + 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 ) + { + + 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; + + // c[0] = luma = noise_L + // c[1] = chroma = noise_ab + // 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; + + //int halfwin = 3;//MIN(ceil(2*sig),3); + //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??? + }*/ + //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; + + smooth = new LabImage(width, height); + + // for coarsest level, take non-subsampled lopass image and subtract from lopass_fine to generate hipass image + + // denoise hipass image, add back into lopass_fine to generate denoised image at fine scale + + // now iterate: + // (1) take denoised image at level n, expand and smooth using gradient weights from lopass image at level n-1 + // the result is the smoothed image at level n-1 + // (2) subtract smoothed image at level n-1 from lopass image at level n-1 to make hipass image at level n-1 + // (3) denoise the hipass image at level n-1 + // (4) add the denoised image at level n-1 to the smoothed image at level n-1 to make the denoised image at level n-1 + + // note that the coarsest level amounts to skipping step (1) and doing (2,3,4). + // in other words, skip step one if pitch=1 + + // step (1) + + + for(int i = 0, i1=0; i < height; i+=pitch, i1++) + for(int j = 0, j1=0; j < width; j+=pitch, j1++) { + + //copy common pixels + 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 + + 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; + 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; + } + 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; + } + + 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; + 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 (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; + } + 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; + + //now down neighbor + if (i+1==height) continue; + norm_l=norm_ab=0.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 (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; + } + 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; + + } + } + + // step (2-3-4) + 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]; + + + //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; + nrfactor = (hpffluct[1]+hpffluct[2]) /((hpffluct[1]+hpffluct[2]) + noisevar_ab * NRWT_AB); + //nrfactor *= resaturate; + /*if (level) { + 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]); + wtdsum[1]=data_fine->a[i][j] = hipass[1]+smooth->a[i][j]; + wtdsum[2]=data_fine->b[i][j] = hipass[2]+smooth->b[i][j]; + } + + delete smooth; + }; + + +#undef DIRWT_L +#undef DIRWT_AB + +#undef NRWT_L +#undef NRWT_AB + +} + diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index d9458024a..af3265155 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -161,6 +161,10 @@ void ImProcCoordinator::updatePreviewImage (int todo) { progress ("Applying Luminance Curve...",100*readyphase/numofphases); ipf.luminanceCurve (oprevl, nprevl, lumacurve, 0, pH); readyphase++; + if (scale==1) { + progress ("Denoising luminance impulse...",100*readyphase/numofphases); + ipf.impulsedenoise (nprevl); + } if (scale==1) { progress ("Denoising luminance...",100*readyphase/numofphases); ipf.lumadenoise (nprevl, buffer); @@ -185,6 +189,10 @@ void ImProcCoordinator::updatePreviewImage (int todo) { if (scale==1) { progress ("Denoising color...",100*readyphase/numofphases); ipf.colordenoise (nprevl, buffer); + } + if (scale==1) { + progress ("Denoising luma/chroma...",100*readyphase/numofphases); + ipf.dirpyrdenoise (nprevl); } if (scale==1) { progress ("Wavelet...",100*readyphase/numofphases); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index eb37cffb2..cfa746a62 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -27,6 +27,8 @@ #include #include #include +#include + #ifdef _OPENMP #include #endif @@ -427,6 +429,20 @@ void ImProcFunctions::colorCurve (LabImage* lold, LabImage* lnew) { delete [] cmultiplier; } + + void ImProcFunctions::impulsedenoise (LabImage* lab) { + + if (params->impulseDenoise.enabled && lab->W>=8 && lab->H>=8) + + impulse_nr (lab->L, lab->L, lab->W, lab->H, 1024); + } + + void ImProcFunctions::dirpyrdenoise (LabImage* lab) { + + if (params->dirpyrDenoise.enabled && lab->W>=8 && lab->H>=8) + + dirpyrLab_denoise(lab, lab, params->dirpyrDenoise.luma, params->dirpyrDenoise.chroma ); + } void ImProcFunctions::lumadenoise (LabImage* lab, int** b2) { diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index d82f5f6d9..36e0b0e1d 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -91,6 +91,14 @@ class ImProcFunctions { void deconvsharpening(LabImage* lab, unsigned short** buffer); void waveletEqualizer(Image16 * image); void waveletEqualizer(LabImage * image, bool luminance, bool chromaticity); + + 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 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 ); + Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile); Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile); diff --git a/rtengine/impulse_denoise.h b/rtengine/impulse_denoise.h new file mode 100644 index 000000000..340d2100c --- /dev/null +++ b/rtengine/impulse_denoise.h @@ -0,0 +1,164 @@ +/* + * This file is part of RawTherapee. + * + * 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 widthITheightOUT ANY widthARRANTY; without even the implied warranty of + * MERCheightANTABILITY 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 . + * + * 2010 Emil Martinec + * + */ + +#define SQR(x) ((x)*(x)) + +#include +#include + +// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// Gabor's implementation of bilateral filtering, without input pixel + +#define NBRWT(a,b) (src[i - a][j - b] * ec[src[i - a][j - b]-src[i][j]+0x10000]) +#define NORM(a,b) (1 + ec[src[i - a][j - b]-src[i][j]+0x10000]) + +#define RB_BEGIN(a,b) double scale = (a); \ + int* ec = new int [0x20000]; \ + for (int i=0; i<0x20000; i++) \ + ec[i] = (int)(exp(-(double)(i-0x10000)*(double)(i-0x10000) / (2.0*rangewidth*rangewidth))*scale); \ + int rstart = b; \ + int rend = H-b; \ + int cstart = b; \ + int cend = W-b; + +#define RB_END(b) buffer[i][j] = v; }} delete [] ec; \ + for (int i=0; i=rend || j>=cend) \ + dst[i][j] = src[i][j]; \ + else \ + dst[i][j] = buffer[i][j]; + +#define RB_OPER5 for (int i=rstart; i void rangeblur (T** src, T** dst, T** buffer, int W, int H, double rangewidth, bool multiThread) { + + RB_BEGIN(753,2) +#pragma omp parallel for if (multiThread) + RB_OPER5 + RB_END(2) + +} + + + +template void impulse_nr (T** src, T** dst, int width, int height, double thresh) { + + + // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // impulse noise removal + // local variables + + float hpfabs, hfnbrave; + + // buffer for the lowpass image + unsigned short ** lpf = new unsigned short *[height]; + for (int i=0; i (src, lpf, impish /*used as buffer here*/, width, height, thresh, false); + + //AlignedBuffer* buffer = new AlignedBuffer (MAX(width,height)); + + //gaussHorizontal (src, lpf, buffer, width, height, 2.0, false /*multiThread*/); + //gaussVertical (lpf, lpf, buffer, width, height, 2.0, false); + + //delete buffer; + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + for (int i=0; i < height; i++) + for (int j=0; j < width; j++) { + + hpfabs = fabs(src[i][j]-lpf[i][j]); + //block average of high pass data + for (i1=MAX(0,i-2), hfnbrave=0; i1<=MIN(i+2,height-1); i1++ ) + for (j1=MAX(0,j-2); j1<=MIN(j+2,width-1); j1++ ) { + hfnbrave += fabs(src[i1][j1]-lpf[i1][j1]); + } + hfnbrave = (hfnbrave-hpfabs)/24; + hpfabs>(hfnbrave*3) ? impish[i][j]=1 : impish[i][j]=0; + + }//now impulsive values have been corrected + + for (int i=0; i < height; i++) + for (int j=0; j < width; j++) { + if (!impish[i][j]) continue; + norm=0.0; + wtdsum=0.0; + for (i1=MAX(0,i-2), hfnbrave=0; i1<=MIN(i+2,height-1); i1++ ) + for (j1=MAX(0,j-2); j1<=MIN(j+2,width-1); j1++ ) { + if (i1==i && j1==j) continue; + if (impish[i1][j1]) continue; + dirwt = 1/(SQR(src[i1][j1]-src[i][j])+eps);//use more sophisticated rangefn??? + wtdsum += dirwt*src[i1][j1]; + norm += dirwt; + } + //wtdsum /= norm; + if (norm) { + src[i][j]=wtdsum/norm;//low pass filter + } + + }//now impulsive values have been corrected + + for (int i=0; i + * + * 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 +#ifdef _OPENMP +#include +#endif +#include +#include + +using namespace rtengine; + +// If no parameter set, everything = 0 -> process all the image +Block::Block() { + posX = 0; + posY = 0; + width = 0; + height = 0; +} + +Block::Block(unsigned int x, unsigned int y, unsigned int w, unsigned int h) { + posX = x; + posY = y; + width = w; + height = h; +} + +/* + * Slice a sub-region to process in blocks who's size is given by the number of processor + * and the number of pixel per block (and hence the memory footprint) + */ +Slicer::Slicer(unsigned int imageWidth, unsigned int imageHeight, Block *subRegion, unsigned int pixels, const char* nomFichier) { + // If the sub-region has a portrait shape, X and Y coordinates are swapped for better result + // It will be swapped back when sending back the block coordinates + region.width = !(subRegion->width) ? imageWidth : subRegion->width; + region.height = !(subRegion->height) ? imageHeight : subRegion->height; // Assuming that the sub-region is under posY + if (region.width < region.height) { + region.width = !(subRegion->height) ? imageHeight : subRegion->height; + region.height = !(subRegion->width) ? imageWidth : subRegion->width; // Assuming that the sub-region is under posY + portrait = true; + imWidth = imageHeight; + imHeight = imageWidth; + region.posX = subRegion->posY; + region.posY = subRegion->posX; + } + else { + portrait = false; + imWidth = imageWidth; + imHeight = imageHeight; + region.posX = subRegion->posX; + region.posY = subRegion->posY; + } + double subRegionRatio = (double)(region.width) / (double)(region.height); + + //total number of core/processor +#ifdef _OPENMP + unsigned int procNumber = omp_get_num_procs(); +#else + unsigned int procNumber = 1; +#endif + + //calculate the number of block + blockNumber = (double(region.width*region.height) / (double)pixels); + blockNumber = int((MAX(blockNumber, 1) + (double)procNumber/2.)/procNumber)*procNumber; + vBlockNumber = (unsigned int)(sqrt((double)blockNumber / subRegionRatio)+0.5); + vBlockNumber = CLAMP(vBlockNumber, 1, blockNumber); + hBlockNumber = (double)blockNumber / (double)vBlockNumber; + blockWidth = 1.0 / hBlockNumber; + + double maxPixelNumberX = (double)region.height / (double)vBlockNumber; + double maxPixelNumberY = (double)region.width / (double)((unsigned int)hBlockNumber); + if (maxPixelNumberX - (double)((unsigned int)maxPixelNumberX) != 0.) maxPixelNumberX += 1.; + if (maxPixelNumberY - (double)((unsigned int)maxPixelNumberY) != 0.) maxPixelNumberY += 1.; + maxPixelNumber = (unsigned int)maxPixelNumberX * (unsigned int)maxPixelNumberY; + +} + +// return the absolute position and size of the requested block +void Slicer::get_block(unsigned int numBlock, Block *block) { + double roundingTradeOff = (hBlockNumber - (double)((int)hBlockNumber)) == 0.5 ? 2.1 : 2.0; + unsigned int alreadyCompletedLineNbr = (unsigned int)((double)(numBlock) * blockWidth + (blockWidth/roundingTradeOff)); + + unsigned int prevLineEnd = (unsigned int)((double)alreadyCompletedLineNbr * hBlockNumber + 0.5); + unsigned int myLineEnd = (unsigned int)((double)(alreadyCompletedLineNbr+1) * hBlockNumber + 0.5); + + unsigned int nbrCellsOnMyLine = myLineEnd - prevLineEnd; + unsigned int cellOnMyLine = numBlock - prevLineEnd; + + unsigned int blockStart = (unsigned int)(((double)region.width / (double)nbrCellsOnMyLine)*(double)(cellOnMyLine)); + unsigned int blockEnd = (unsigned int)(((double)region.width / (double)nbrCellsOnMyLine)*(double)(cellOnMyLine+1)); + block->width = blockEnd - blockStart; + block->posX = region.posX + blockStart; + if (cellOnMyLine == (nbrCellsOnMyLine-1)) { + // We make sure that the last block of the row take the rest of the remaining X space + block->width = region.posX + region.width - block->posX; + } + + blockStart = (unsigned int)(((double)region.height / (double)vBlockNumber)*(double)(alreadyCompletedLineNbr)); + blockEnd = (unsigned int)(((double)region.height / (double)vBlockNumber)*(double)(alreadyCompletedLineNbr+1)); + block->height = blockEnd - blockStart; + block->posY = region.posY + blockStart; + if (alreadyCompletedLineNbr == (vBlockNumber-1)) { + block->height = region.posY + region.height - block->posY; + } + + if (portrait) { + // we swap back the X/Y coordinates + unsigned int temp; + + temp = block->posX; + block->posX = block->posY; + block->posY = temp; + + temp = block->width; + block->width = block->height; + block->height = temp; + + } +} diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 5a96dfceb..620df9d75 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -8,6 +8,7 @@ set (BASESOURCEFILES coarsepanel.cc cacorrection.cc colorshift.cc hlrec.cc chmixer.cc colorboost.cc resize.cc icmpanel.cc crop.cc shadowshighlights.cc colordenoise.cc + impulsedenoise.cc dirpyrdenoise.cc exifpanel.cc sharpening.cc whitebalance.cc vignetting.cc rotate.cc distortion.cc diff --git a/rtgui/dirpyrdenoise.cc b/rtgui/dirpyrdenoise.cc new file mode 100644 index 000000000..8f02fb8f4 --- /dev/null +++ b/rtgui/dirpyrdenoise.cc @@ -0,0 +1,149 @@ +/* + * 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 + +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)); + 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); + 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); + + enableListener (); +} + +void DirPyrDenoise::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->dirpyrDenoise.luma = luma->getValue (); + pp->dirpyrDenoise.chroma = (int)chroma->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(); + } +} + +void DirPyrDenoise::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + luma->setDefault (defParams->dirpyrDenoise.luma); + chroma->setDefault (defParams->dirpyrDenoise.chroma); + + if (pedited) { + luma->setDefaultEditedState (pedited->dirpyrDenoise.luma ? Edited : UnEdited); + chroma->setDefaultEditedState (pedited->dirpyrDenoise.chroma ? Edited : UnEdited); + } + else { + luma->setDefaultEditedState (Irrelevant); + chroma->setDefaultEditedState (Irrelevant); + } +} + +void DirPyrDenoise::adjusterChanged (Adjuster* a, double newval) { + + if (listener && enabled->get_active()) { + + if (a==luma) + listener->panelChanged (EvLDNRadius, Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(1), a->getValue())); + else if (a==chroma) + listener->panelChanged (EvLDNEdgeTolerance, Glib::ustring::format ((int)a->getValue())); + } +} + +void DirPyrDenoise::enabledChanged () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + enaConn.block (true); + enabled->set_active (false); + enaConn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvLDNEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvLDNEnabled, M("GENERAL_DISABLED")); + } +} + +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; +}*/ diff --git a/rtgui/dirpyrdenoise.h b/rtgui/dirpyrdenoise.h new file mode 100644 index 000000000..862417386 --- /dev/null +++ b/rtgui/dirpyrdenoise.h @@ -0,0 +1,51 @@ +/* + * 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 . + */ +#ifndef _DIRPYRDENOISE_H_ +#define _DIRPYRDENOISE_H_ + +#include +#include +#include + +class DirPyrDenoise : public Gtk::VBox, public AdjusterListener, public ToolPanel { + + protected: + Adjuster* luma; + Adjuster* chroma; + Gtk::CheckButton* enabled; + bool lastEnabled; + sigc::connection enaConn; + bool edgetolAdd; + + public: + + DirPyrDenoise (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void enabledChanged (); + + void setAdjusterBehavior (bool bedgetoladd); +}; + +#endif diff --git a/rtgui/impulsedenoise.cc b/rtgui/impulsedenoise.cc new file mode 100644 index 000000000..803e48614 --- /dev/null +++ b/rtgui/impulsedenoise.cc @@ -0,0 +1,120 @@ +/* + * 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 + +using namespace rtengine; +using namespace rtengine::procparams; + +ImpulseDenoise::ImpulseDenoise () : ToolPanel() { + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + enabled->set_active (false); + + //amount = Gtk::manage (new Adjuster (M("TP_DETAIL_AMOUNT"), 1, 100, 1, 30)); + + pack_start (*enabled); + pack_start (*Gtk::manage (new Gtk::HSeparator())); + //pack_start (*amount); + + enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &ImpulseDenoise::enabledChanged) ); + //amount->setAdjusterListener (this); + + show_all_children (); +} + +void ImpulseDenoise::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + //amount->setEditedState (pedited->impulseDenoise.amount ? Edited : UnEdited); + enabled->set_inconsistent (!pedited->impulseDenoise.enabled); + } + + enaConn.block (true); + enabled->set_active (pp->impulseDenoise.enabled); + enaConn.block (false); + + lastEnabled = pp->impulseDenoise.enabled; + + //amount->setValue (pp->impulseDenoise.amount); + + enableListener (); +} + +void ImpulseDenoise::write (ProcParams* pp, ParamsEdited* pedited) { + + //pp->impulseDenoise.amount = amount->getValue (); + pp->impulseDenoise.enabled = enabled->get_active(); + + if (pedited) { + //pedited->impulseDenoise.amount = amount->getEditedState (); + pedited->impulseDenoise.enabled = !enabled->get_inconsistent(); + } +} + +void ImpulseDenoise::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + //amount->setDefault (defParams->impulseDenoise.amount); + + /*if (pedited) + amount->setDefaultEditedState (pedited->impulseDenoise.amount ? Edited : UnEdited); + else + amount->setDefaultEditedState (Irrelevant);*/ +} + +/*void ImpulseDenoise::adjusterChanged (Adjuster* a, double newval) { + + if (listener && enabled->get_active()) { + + listener->panelChanged (EvCDNRadius, Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(1), a->getValue())); + } +}*/ + +void ImpulseDenoise::enabledChanged () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + enaConn.block (true); + enabled->set_active (false); + enaConn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvCDNEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvCDNEnabled, M("GENERAL_DISABLED")); + } +} + +void ImpulseDenoise::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + //amount->showEditedCB (); +} diff --git a/rtgui/impulsedenoise.h b/rtgui/impulsedenoise.h new file mode 100644 index 000000000..d769c3995 --- /dev/null +++ b/rtgui/impulsedenoise.h @@ -0,0 +1,51 @@ +/* + * 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 . + */ +#ifndef _IMPULSEDENOISE_H_ +#define _IMPULSEDENOISE_H_ + +#include +#include +#include + +class ImpulseDenoise : public Gtk::VBox, /*public AdjusterListener,*/ public ToolPanel { + + protected: + //Adjuster* radius; + //Adjuster* edge; + Gtk::CheckButton* enabled; + bool lastEnabled; + sigc::connection enaConn; + bool edgetolAdd; + + public: + + ImpulseDenoise (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + //void adjusterChanged (Adjuster* a, double newval); + void enabledChanged (); + + //void setAdjusterBehavior (bool bedgetoladd); +}; + +#endif diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index a0ca51c38..782312dce 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -68,6 +68,10 @@ void ParamsEdited::set (bool v) { lumaDenoise.edgetolerance = v; colorDenoise.enabled = v; colorDenoise.amount = v; + impulseDenoise.enabled = v; + dirpyrDenoise.enabled = v; + dirpyrDenoise.luma = v; + dirpyrDenoise.chroma = v; sh.enabled = v; sh.hq = v; sh.highlights = v; @@ -180,6 +184,13 @@ void ParamsEdited::initFrom (const std::vector lumaDenoise.edgetolerance = lumaDenoise.edgetolerance && p.lumaDenoise.edgetolerance == other.lumaDenoise.edgetolerance; colorDenoise.enabled = colorDenoise.enabled && p.colorDenoise.enabled == other.colorDenoise.enabled; colorDenoise.amount = colorDenoise.amount && p.colorDenoise.amount == other.colorDenoise.amount; + + impulseDenoise.enabled = impulseDenoise.enabled && p.impulseDenoise.enabled == other.impulseDenoise.enabled; + + 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; + 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; @@ -282,6 +293,13 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (lumaDenoise.edgetolerance) toEdit.lumaDenoise.edgetolerance = options.baBehav[ADDSET_LD_EDGETOLERANCE] ? toEdit.lumaDenoise.edgetolerance + mods.lumaDenoise.edgetolerance : mods.lumaDenoise.edgetolerance; if (colorDenoise.enabled) toEdit.colorDenoise.enabled = mods.colorDenoise.enabled; if (colorDenoise.amount) toEdit.colorDenoise.amount = mods.colorDenoise.amount; + + if (impulseDenoise.enabled) toEdit.impulseDenoise.enabled = mods.impulseDenoise.enabled; + + 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 (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; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index c8dd43085..ad8b2a68a 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -105,6 +105,20 @@ class ColorDenoiseParamsEdited { bool amount; }; +class ImpulseDenoiseParamsEdited { + +public: + bool enabled; +}; + +class DirPyrDenoiseParamsEdited { + +public: + bool enabled; + bool luma; + bool chroma; +}; + class SHParamsEdited { public: @@ -246,7 +260,11 @@ class ParamsEdited { WBParamsEdited wb; ColorShiftParamsEdited colorShift; LumaDenoiseParamsEdited lumaDenoise; - ColorDenoiseParamsEdited colorDenoise; + ColorDenoiseParamsEdited colorDenoise; + + DirPyrDenoiseParamsEdited dirpyrDenoise; + ImpulseDenoiseParamsEdited impulseDenoise; + SHParamsEdited sh; CropParamsEdited crop; CoarseTransformParamsEdited coarse; diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index a35b6ad56..7e1967225 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -218,8 +218,8 @@ bool RTWindow::on_delete_event(GdkEventAny* event) { options.fbArrangement = fileBrowser->getFileCatalog()->getArrangement (); options.firstRun = false; */ - options.windowWidth = get_width(); - options.windowHeight = get_height(); + //options.windowWidth = get_width(); + //options.windowHeight = get_height(); Options::save (); diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index f01cc2105..51a0024a2 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -35,6 +35,8 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { shadowshighlights = Gtk::manage (new ShadowsHighlights ()); lumadenoise = Gtk::manage (new LumaDenoise ()); colordenoise = Gtk::manage (new ColorDenoise ()); + impulsedenoise = Gtk::manage (new ImpulseDenoise ()); + dirpyrdenoise = Gtk::manage (new DirPyrDenoise ()); sharpening = Gtk::manage (new Sharpening ()); lcurve = Gtk::manage (new LCurve ()); colorboost = Gtk::manage (new ColorBoost ()); @@ -64,8 +66,10 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { addPanel (colorPanel, colorboost, M("TP_COLORBOOST_LABEL")); toolPanels.push_back (colorboost); addPanel (colorPanel, colorshift, M("TP_COLORSHIFT_LABEL")); toolPanels.push_back (colorshift); addPanel (exposurePanel, lcurve, M("TP_LUMACURVE_LABEL")); toolPanels.push_back (lcurve); + addPanel (detailsPanel, impulsedenoise, M("TP_IMPULSEDENOISE_LABEL")); toolPanels.push_back (impulsedenoise); addPanel (detailsPanel, lumadenoise, M("TP_LUMADENOISE_LABEL")); toolPanels.push_back (lumadenoise); addPanel (detailsPanel, colordenoise, M("TP_COLORDENOISE_LABEL")); toolPanels.push_back (colordenoise); + addPanel (detailsPanel, dirpyrdenoise, M("TP_DIRPYRDENOISE_LABEL")); toolPanels.push_back (dirpyrdenoise); addPanel (detailsPanel, equalizer, M("TP_EQUALIZER_LABEL")); toolPanels.push_back (equalizer); addPanel (transformPanel, crop, M("TP_CROP_LABEL")); toolPanels.push_back (crop); addPanel (transformPanel, resize, M("TP_RESIZE_LABEL")); toolPanels.push_back (resize); @@ -168,7 +172,7 @@ void ToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib:: for (int i=0; iwrite (params); - // some transformations make the crop change for convinience + // some transformations make the crop change for convenience if (event==rtengine::EvResizeScale) { crop->resizeScaleChanged (params->resize.scale); crop->write (params); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 6407b4a47..363c4a358 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -85,6 +87,8 @@ class ToolPanelCoordinator : public ToolPanelListener, ShadowsHighlights* shadowshighlights; LumaDenoise* lumadenoise; ColorDenoise* colordenoise; + ImpulseDenoise* impulsedenoise; + DirPyrDenoise* dirpyrdenoise; Sharpening* sharpening; LCurve* lcurve; Equalizer * equalizer;