Adding luminance impulse denoising and directional pyramid denoising.

This commit is contained in:
Emil Martinec
2010-09-13 03:35:02 -05:00
parent f33fd05b4e
commit f52e8a69b4
22 changed files with 1366 additions and 7 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* © 2010 Emil Martinec <ejmartin@uchicago.edu>
*
*/
//#include <rtengine.h>
#include <cstddef>
#include <math.h>
#include <curves.h>
#include <labimage.h>
#include <improcfun.h>
#ifdef _OPENMP
#include <omp.h>
#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; i<src->H; i++) {
for (int j=0; j<src->W; 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<maxlevel; level++) {
w = (int)((w-1)/pitches[level])+1;
h = (int)((h-1)/pitches[level])+1;
dirpyrLablo[level] = new LabImage(w, h);
};
//////////////////////////////////////////////////////////////////////////////
// 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
level = 0;
int scale = scales[level];
int pitch = pitches[level];
//int thresh = 10 * c[8];
//impulse_nr (src, src, m_w1, m_h1, thresh, noisevar);
dirpyr(src, dirpyrLablo[0], 0, rangefn_L, rangefn_ab, pitch, scale, luma, chroma );
level = 1;
while(level < maxlevel)
{
scale = scales[level];
pitch = pitches[level];
dirpyr(dirpyrLablo[level-1], dirpyrLablo[level], level, rangefn_L, rangefn_ab, pitch, scale, luma, chroma );
level ++;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for(int level = maxlevel - 1; level > 0; level--)
{
//float noisevar_L = SQR(25.0 * luma)/pow(2.0,(level+1)*(1+c[2]/100));
//float noisevar_ab = SQR(100.0 * chroma);
int scale = scales[level];
int pitch = pitches[level];
idirpyr(dirpyrLablo[level], dirpyrLablo[level-1], level, irangefn_L, irangefn_ab, nrwt_l, nrwt_ab, pitch, scale, luma, chroma );
}
//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; i<dst->H; i++)
for (int j=0; j<dst->W; j++) {
dst->L[i][j] = gamcurve[CLIP(dst->L[i][j]) ];
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for(int i = 0; i < maxlevel; i++)
{
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
}

View File

@@ -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);

View File

@@ -27,6 +27,8 @@
#include <mytime.h>
#include <glibmm.h>
#include <iccstore.h>
#include <impulse_denoise.h>
#ifdef _OPENMP
#include <omp.h>
#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) {

View File

@@ -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);

164
rtengine/impulse_denoise.h Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
*
* 2010 Emil Martinec <ejmartin@uchicago.edu>
*
*/
#define SQR(x) ((x)*(x))
#include <cstddef>
#include <algorithm>
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// 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<H; i++) \
for (int j=0; j<W; j++) \
if (i<rstart || j<cstart || 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<rend; i++) { \
for (int j=cstart; j<cend; j++) { \
A v = NBRWT(-2,-2) + NBRWT(-2,-1) + NBRWT(-2,0) + NBRWT(-2,1) + NBRWT(-2,2) + \
NBRWT(-1,-2) + NBRWT(-1,-1) + NBRWT(-1,0) + NBRWT(-1,1) + NBRWT(-1,2) + \
NBRWT(0,-2) + NBRWT(0,-1) /*+ NBRWT(0,0)*/ + NBRWT(0,1) + NBRWT(0,2) + \
NBRWT(1,-2) + NBRWT(1,-1) + NBRWT(1,0) + NBRWT(1,1) + NBRWT(1,2) + \
NBRWT(2,-2) + NBRWT(2,-1) + NBRWT(2,0) + NBRWT(2,1) + NBRWT(2,2); \
v /= NORM(-2,-2) + NORM(-2,-1) + NORM(-2,0) + NORM(-2,1) + NORM(-2,2) + \
NORM(-1,-2) + NORM(-1,-1) + NORM(-1,0) + NORM(-1,1) + NORM(-1,2) + \
NORM(0,-2) + NORM(0,-1) /*+ NORM(0,0)*/ + NORM(0,1) + NORM(0,2) + \
NORM(1,-2) + NORM(1,-1) + NORM(1,0) + NORM(1,1) + NORM(1,2) + \
NORM(2,-2) + NORM(2,-1) + NORM(2,0) + NORM(2,1) + NORM(2,2);
template<class T, class A> 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<class T> 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<height; i++) {
lpf[i] = new unsigned short [width];
//memset (lpf[i], 0, width*sizeof(float));
}
// buffer for the highpass image
unsigned short ** impish = new unsigned short *[height];
for (int i=0; i<height; i++) {
impish[i] = new unsigned short [width];
//memset (impish[i], 0, width*sizeof(unsigned short));
}
//The cleaning algorithm starts here
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// modified bilateral filter for lowpass image, omitting input pixel
static float eps = 1.0;
float wtdsum, dirwt, norm;
int i1, j1;
rangeblur<unsigned short, unsigned int> (src, lpf, impish /*used as buffer here*/, width, height, thresh, false);
//AlignedBuffer<double>* buffer = new AlignedBuffer<double> (MAX(width,height));
//gaussHorizontal<unsigned short> (src, lpf, buffer, width, height, 2.0, false /*multiThread*/);
//gaussVertical<unsigned short> (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<height; i++)
delete [] lpf[i];
delete [] lpf;
for (int i=0; i<height; i++)
delete [] impish[i];
delete [] impish;
}

View File

@@ -85,7 +85,7 @@ void ProcParams::setDefaults () {
colorShift.a = 0;
colorShift.b = 0;
lumaDenoise.enabled = false;
lumaDenoise.radius = 1.9;
lumaDenoise.edgetolerance = 2000;
@@ -94,6 +94,12 @@ void ProcParams::setDefaults () {
colorDenoise.edgesensitive = false;
colorDenoise.radius = 1.9;
colorDenoise.edgetolerance = 2000;
impulseDenoise.enabled = false;
dirpyrDenoise.enabled = false;
dirpyrDenoise.luma = 10;
dirpyrDenoise.chroma = 10;
sh.enabled = false;
sh.hq = false;
@@ -236,6 +242,14 @@ int ProcParams::save (Glib::ustring fname) const {
// save colorShift
keyFile.set_double ("Color Shift", "ChannelA", colorShift.a);
keyFile.set_double ("Color Shift", "ChannelB", colorShift.b);
// save impulseDenoise
keyFile.set_boolean ("Impulse Denoising", "Enabled", impulseDenoise.enabled);
// save dirpyrDenoise
keyFile.set_boolean ("Directional Pyramid Denoising", "Enabled", dirpyrDenoise.enabled);
keyFile.set_integer ("Directional Pyramid Denoising", "Luma", dirpyrDenoise.luma);
keyFile.set_integer ("Directional Pyramid Denoising", "Chroma", dirpyrDenoise.chroma);
// save lumaDenoise
keyFile.set_boolean ("Luminance Denoising", "Enabled", lumaDenoise.enabled);
@@ -443,6 +457,18 @@ if (keyFile.has_group ("Color Shift")) {
if (keyFile.has_key ("Color Shift", "ChannelA")) colorShift.a = keyFile.get_double ("Color Shift", "ChannelA");
if (keyFile.has_key ("Color Shift", "ChannelB")) colorShift.b = keyFile.get_double ("Color Shift", "ChannelB");
}
// load impulseDenoise
if (keyFile.has_group ("Impulse Denoising")) {
if (keyFile.has_key ("Impulse Denoising", "Enabled")) impulseDenoise.enabled = keyFile.get_boolean ("Impulse Denoising", "Enabled");
}
// load dirpyrDenoise
if (keyFile.has_group ("Directional Pyramid Denoising")) {
if (keyFile.has_key ("Directional Pyramid Denoising", "Enabled")) dirpyrDenoise.enabled = keyFile.get_boolean ("Directional Pyramid Denoising", "Enabled");
if (keyFile.has_key ("Directional Pyramid Denoising", "Luma")) dirpyrDenoise.luma = keyFile.get_integer ("Directional Pyramid Denoising", "Luma");
if (keyFile.has_key ("Directional Pyramid Denoising", "Chroma")) dirpyrDenoise.chroma = keyFile.get_integer ("Directional Pyramid Denoising", "Chroma");
}
// load lumaDenoise
if (keyFile.has_group ("Luminance Denoising")) {
@@ -648,6 +674,10 @@ bool ProcParams::operator== (const ProcParams& other) {
&& wb.temperature == other.wb.temperature
&& colorShift.a == other.colorShift.a
&& colorShift.b == other.colorShift.b
&& impulseDenoise.enabled == other.impulseDenoise.enabled
&& dirpyrDenoise.enabled == other.dirpyrDenoise.enabled
&& dirpyrDenoise.luma == other.dirpyrDenoise.luma
&& dirpyrDenoise.chroma == other.dirpyrDenoise.chroma
&& lumaDenoise.enabled == other.lumaDenoise.enabled
&& lumaDenoise.radius == other.lumaDenoise.radius
&& lumaDenoise.edgetolerance == other.lumaDenoise.edgetolerance

View File

@@ -132,6 +132,26 @@ class ColorDenoiseParams {
bool edgesensitive;
int amount;
};
/**
* Parameters of impulse denoising
*/
class ImpulseDenoiseParams {
public:
bool enabled;
};
/**
* Parameters of the directional pyramid denoising
*/
class DirPyrDenoiseParams {
public:
bool enabled;
int luma;
int chroma;
};
/**
* Parameters of the shadow/highlight enhancement
@@ -326,6 +346,8 @@ class ProcParams {
ColorShiftParams colorShift; ///< Color shift parameters
LumaDenoiseParams lumaDenoise; ///< Luminance denoising parameters
ColorDenoiseParams colorDenoise; ///< Color denoising parameters
ImpulseDenoiseParams impulseDenoise; ///< Impulse denoising parameters
DirPyrDenoiseParams dirpyrDenoise; ///< Directional Pyramid denoising parameters
SHParams sh; ///< Shadow/highlight enhancement parameters
CropParams crop; ///< Crop parameters
CoarseTransformParams coarse; ///< Coarse transformation (90, 180, 270 deg rotation, h/v flipping) parameters

135
rtengine/slicer.cc Normal file
View File

@@ -0,0 +1,135 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#ifdef _OPENMP
#include <omp.h>
#endif
#include <slicer.h>
#include <gtkmm.h>
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;
}
}

View File

@@ -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

149
rtgui/dirpyrdenoise.cc Normal file
View File

@@ -0,0 +1,149 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <dirpyrdenoise.h>
#include <iomanip>
#include <math.h>
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;
}*/

51
rtgui/dirpyrdenoise.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _DIRPYRDENOISE_H_
#define _DIRPYRDENOISE_H_
#include <gtkmm.h>
#include <adjuster.h>
#include <toolpanel.h>
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

120
rtgui/impulsedenoise.cc Normal file
View File

@@ -0,0 +1,120 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <impulsedenoise.h>
#include <math.h>
#include <iomanip>
#include <guiutils.h>
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 ();
}

51
rtgui/impulsedenoise.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _IMPULSEDENOISE_H_
#define _IMPULSEDENOISE_H_
#include <gtkmm.h>
#include <adjuster.h>
#include <toolpanel.h>
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

View File

@@ -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<rtengine::procparams::ProcParams>
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;

View File

@@ -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;

View File

@@ -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 ();

View File

@@ -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; i<toolPanels.size(); i++)
toolPanels[i]->write (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);

View File

@@ -33,6 +33,8 @@
#include <shadowshighlights.h>
#include <lumadenoise.h>
#include <colordenoise.h>
#include <impulsedenoise.h>
#include <dirpyrdenoise.h>
#include <sharpening.h>
#include <lcurve.h>
#include <exifpanel.h>
@@ -85,6 +87,8 @@ class ToolPanelCoordinator : public ToolPanelListener,
ShadowsHighlights* shadowshighlights;
LumaDenoise* lumadenoise;
ColorDenoise* colordenoise;
ImpulseDenoise* impulsedenoise;
DirPyrDenoise* dirpyrdenoise;
Sharpening* sharpening;
LCurve* lcurve;
Equalizer * equalizer;