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;