Adding luminance impulse denoising and directional pyramid denoising.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
554
rtengine/dirpyrLab_denoise.cc
Normal file
554
rtengine/dirpyrLab_denoise.cc
Normal 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
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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
164
rtengine/impulse_denoise.h
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
135
rtengine/slicer.cc
Normal 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;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
149
rtgui/dirpyrdenoise.cc
Normal 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
51
rtgui/dirpyrdenoise.h
Normal 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
120
rtgui/impulsedenoise.cc
Normal 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
51
rtgui/impulsedenoise.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user