diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 8d9df5973..b3decd1ad 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -14,7 +14,7 @@ set (RTENGINESOURCEFILES safegtk.cc colortemp.cc curves.cc flatcurves.cc diagona jpeg_memsrc.cc jdatasrc.cc EdgePreserveLab.cc EdgePreservingDecomposition.cc cplx_wavelet_dec.cc FTblockDN.cc PF_correct_RT.cc - dirpyrLab_denoise.cc dirpyr_equalizer.cc + dirpyr_equalizer.cc calc_distort.cc klt/convolve.cc klt/error.cc klt/klt.cc klt/klt_util.cc klt/pnmio.cc klt/pyramid.cc klt/selectGoodFeatures.cc klt/storeFeatures.cc klt/trackFeatures.cc klt/writeFeatures.cc diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index f85948cb2..61388b74c 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -208,11 +208,13 @@ namespace rtengine { int height = tilebottom-tiletop; //input L channel - array2D Lin(width,height); + array2D Lin(width,height,ARRAY2D_CLEAR_DATA); //wavelet denoised image LabImage * labdn = new LabImage(width,height); //residual between input and denoised L channel - array2D Ldetail(width,height); + array2D Ldetail(width,height,ARRAY2D_CLEAR_DATA); + //pixel weight + array2D totwt(width,height,ARRAY2D_CLEAR_DATA);//weight for combining DCT blocks //fill tile from image for (int i=tiletop, i1=0; i Lwavdn(width,height,ARRAY2D_CLEAR_DATA); + array2D Lwavdn(width,height); float * Lwavdnptr = Lwavdn; memcpy (Lwavdnptr, labdn->data, width*height*sizeof(float)); @@ -274,8 +277,6 @@ namespace rtengine { // missed by wavelet denoise // blocks are not the same thing as tiles! - //pixel weight - array2D totwt(width,height,ARRAY2D_CLEAR_DATA);//weight for combining blocks // allocate DCT data structures @@ -305,7 +306,6 @@ namespace rtengine { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // Main detail recovery algorithm: Block loop -#pragma omp parallel for schedule(dynamic) for (int vblk=0; vblk -// -// -// code dated: December 24, 2011 -// -// FTblockDNchroma.cc 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. -// -// This program 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 this program. If not, see . -// -//////////////////////////////////////////////////////////////// - - -#include -#include - -//#include "bilateral2.h" -#include "gauss.h" - -#include "rtengine.h" -#include "improcfun.h" -#include "LUT.h" -#include "array2D.h" -#include "iccmatrices.h" -#include "boxblur.h" - -#ifdef _OPENMP -#include -#endif - -#include "cplx_wavelet_dec.h" - - -#define SQR(x) ((x)*(x)) -//#define MIN(a,b) ((a) < (b) ? (a) : (b)) -//#define MAX(a,b) ((a) > (b) ? (a) : (b)) -//#define LIM(x,min,max) MAX(min,MIN(x,max)) -//#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) -//#define CLIP(x) LIM(x,0,65535) - -#define TS 64 // Tile size -#define offset 25 // shift between tiles -#define fTS ((TS/2+1)) // second dimension of Fourier tiles -#define blkrad 0 // radius of block averaging -//#define eps 0.01f/(TS*TS) //tolerance - -namespace rtengine { - -// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -/* - Structure of the algorithm: - - 1. Compute a high pass filter of the image via bilateral filter with user input range - 2. Decompose the image into TSxTS size tiles, shifting by 'offset' each step (so roughly - each pixel is in (TS/offset)^2 tiles); Fourier transform the tiles after applying a mask - to prevent long range tails in the FT data due to boundary discontinuities. - 3. Compute the average size of Fourier coefficients. - 4. Damp the FT data of the tile by a Wiener filter factor - (image_variance)/(image_variance + noise_control) - where noise_control is the user specified noise reduction amount. - Noise_control is altered according to neighbor average. - 6. Inverse FT the denoised tile data and combine the tiles into a denoised output - image. - -*/ - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - void ImProcFunctions::RGB_InputTransf(Imagefloat * src, LabImage * dst, const procparams::DirPyrDenoiseParams & dnparams, const procparams::DefringeParams & defringe) { - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // gamma transform input channel data - float gam = dnparams.gamma; - float gamthresh = 0.03; - float gamslope = exp(log((double)gamthresh)/gam)/gamthresh; - - LUTf gamcurve(65536,0); - - for (int i=0; i<65536; i++) { - gamcurve[i] = (gamma((double)i/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)) * 32768.0f; - } - - //srand((unsigned)time(0));//test with random data - - //int max; - //float median = MadMax(src->data, max, src->width*src->height); - //gain = sqrt(MAX(1.0f,(0.15f*65535.0f/median))*(65535.0f/max));//'gain' is public float allocated in improcfun.h; - const float gain = pow (2.0, dnparams.expcomp); - -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (int i=0; iheight; i++) - for (int j=0; jwidth; j++) { - - float X = gain*src->r[i][j];//xyz_prophoto[0][0]*src->r[i][j] + xyz_prophoto[0][1]*src->g[i][j] + xyz_prophoto[0][2]*src->b[i][j]; - float Y = gain*src->g[i][j];//xyz_prophoto[1][0]*src->r[i][j] + xyz_prophoto[1][1]*src->g[i][j] + xyz_prophoto[1][2]*src->b[i][j]; - float Z = gain*src->b[i][j];//xyz_prophoto[2][0]*src->r[i][j] + xyz_prophoto[2][1]*src->g[i][j] + xyz_prophoto[2][2]*src->b[i][j]; - - X = X<65535.0f ? gamcurve[X] : (gamma((double)X/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - Y = Y<65535.0f ? gamcurve[Y] : (gamma((double)Y/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - Z = Z<65535.0f ? gamcurve[Z] : (gamma((double)Z/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - - dst->L[i][j] = Y; - dst->a[i][j] = 0.2f*(X-Y); - dst->b[i][j] = 0.2f*(Y-Z); - - //Y = 0.05+0.1*((float)rand()/(float)RAND_MAX);//test with random data - //dst->L[i][j] = gamcurve[65535.0f*Y]; - - } - - - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - void ImProcFunctions::RGB_OutputTransf(LabImage * src, Imagefloat * dst, const procparams::DirPyrDenoiseParams & dnparams) { - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // gamma transform output channel data - float gam = dnparams.gamma; - float gamthresh = 0.03; - float gamslope = exp(log((double)gamthresh)/gam)/gamthresh; - float igam = 1/gam; - float igamthresh = gamthresh*gamslope; - float igamslope = 1/gamslope; - - LUTf igamcurve(65536,0); - - for (int i=0; i<65536; i++) { - igamcurve[i] = (gamma((float)i/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); - } - - const float gain = pow (2.0, dnparams.expcomp); - -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (int i=0; iH; i++) { - float X,Y,Z; - for (int j=0; jW; j++) { - //input normalized to (0,1) - //Y = igamcurveL[ src->L[i][j] ]; - Y = src->L[i][j]; - X = (5.0f*(src->a[i][j])) + Y; - Z = Y - (5.0f*(src->b[i][j])); - - X = X<32768.0f ? igamcurve[X] : (gamma((float)X/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); - Y = Y<32768.0f ? igamcurve[Y] : (gamma((float)Y/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); - Z = Z<32768.0f ? igamcurve[Z] : (gamma((float)Z/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); - - //Y = 65535.0f*(0.05+0.1*((float)rand()/(float)RAND_MAX));//test with random data - - dst->r[i][j] = X/gain;//prophoto_xyz[0][0]*X + prophoto_xyz[0][1]*Y + prophoto_xyz[0][2]*Z; - dst->g[i][j] = Y/gain;//prophoto_xyz[1][0]*X + prophoto_xyz[1][1]*Y + prophoto_xyz[1][2]*Z; - dst->b[i][j] = Z/gain;//prophoto_xyz[2][0]*X + prophoto_xyz[2][1]*Y + prophoto_xyz[2][2]*Z; - - } - } - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - void ImProcFunctions::RGB_denoise(Imagefloat * src, Imagefloat * dst, /*int Roffset,*/ const procparams::DirPyrDenoiseParams & dnparams, const procparams::DefringeParams & defringe) - { - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - /*if (plistener) { - plistener->setProgressStr ("Denoise..."); - plistener->setProgress (0.0); - }*/ - - volatile double progress = 0.0; - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - const short int height=src->height, width=src->width; - const short int hfh=(height+1)/2, hfw=(width+1)/2; - - if (dnparams.luma==0) {//nothing to do; copy src to dst - for (int i=0; ir[i][j] = src->r[i][j]; - dst->r[i][j] = src->r[i][j]; - dst->r[i][j] = src->r[i][j]; - } - } - return; - } - - //const int blkrad=2; - float noisevar_Ldetail = SQR((100-dnparams.Ldetail) * TS * 100.0f); - - - array2D tilemask_in(TS,TS); - array2D tilemask_out(TS,TS); - - array2D totwt(width,height,ARRAY2D_CLEAR_DATA); - - const int border = MAX(2,TS/16); - - for (int i=0; iTS/2 ? i-TS+1 : i)); - float vmask = (i1TS/2 ? j-TS+1 : j)); - tilemask_in[i][j] = (vmask * (j1tilesize and height>tilesize) { - const int numtiles_W = ceil(((float)(width))/(tilesize-overlap)); - const int numtiles_H = ceil(((float)(height))/(tilesize-overlap)); - int tilewidth = ceil(((float)(width))/(numtiles_W)); - int tileheight = ceil(((float)(height))/(numtiles_H)); - tilewidth = tilewidth + (tilewidth&1); - tileheight = tileheight + (tileheight&1); - - for (int tiletop=0; tiletop Ldn(width,height); - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // transform RGB input to ersatz Lab - - RGB_InputTransf(src, labin, dnparams, defringe); - - memcpy (labdn->data, labin->data, 3*width*height*sizeof(float)); - - //initial impulse denoise - impulse_nr (labdn, 50.0f/20.0f); - - int datalen = labin->W * labin->H; - - //now perform basic wavelet denoise - wavelet_decomposition Ldecomp(labin->data, labin->W, labin->H, 5/*maxlevels*/, 0/*subsampling*/ ); - wavelet_decomposition adecomp(labin->data+datalen, labin->W, labin->H, 5, 1 );//last args are maxlevels, subsampling - wavelet_decomposition bdecomp(labin->data+2*datalen, labin->W, labin->H, 5, 1 );//last args are maxlevels, subsampling - - float noisevarL = SQR(dnparams.luma/25.0f); - float noisevarab = SQR(dnparams.chroma/10.0f); - - WaveletDenoiseAll_BiShrink(Ldecomp, adecomp, bdecomp, noisevarL, noisevarab); - - Ldecomp.reconstruct(labdn->data); - adecomp.reconstruct(labdn->data+datalen); - bdecomp.reconstruct(labdn->data+2*datalen); - - //TODO: at this point wavelet coefficients storage can be freed - - //second impulse denoise - impulse_nr (labdn, 50.0f/20.0f); - //PF_correct_RT(dst, dst, defringe.radius, defringe.threshold); - - - float * Ldnptr = Ldn; - memcpy (Ldnptr, labdn->data, width*height*sizeof(float)); - for (int i=0; iW*labdn->H; i++) { - labdn->data[i] = 0.0f; - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // now do detail recovery using block DCT to detect patterns - // missed by wavelet denoise - - - // allocate DCT data structures - - // calculation for detail recovery tiling - const int numblox_W = ceil(((float)(width))/(offset))+2*blkrad; - const int numblox_H = ceil(((float)(height))/(offset))+2*blkrad; - //const int nrtiles = numblox_W*numblox_H; - // end of tiling calc - - float ** Lblox = new float *[8] ; - - float ** fLblox = new float *[8] ; //for DCT - - for( int i = 0 ; i < 8 ; i++ ) { - Lblox[i] = (float *) fftwf_malloc (numblox_W*TS*TS * sizeof (float)); - fLblox[i] = (float *) fftwf_malloc (numblox_W*TS*TS * sizeof (float)); //for DCT - - } - - //make a plan for FFTW - fftwf_plan plan_forward_blox, plan_backward_blox; - - int nfwd[2]={TS,TS}; - - - //for DCT: - const fftw_r2r_kind fwdkind[2] = {FFTW_REDFT10, FFTW_REDFT10}; - const fftw_r2r_kind bwdkind[2] = {FFTW_REDFT01, FFTW_REDFT01}; - - plan_forward_blox = fftwf_plan_many_r2r(2, nfwd, numblox_W, Lblox[0], NULL, 1, TS*TS, fLblox[0], NULL, 1, TS*TS, fwdkind, FFTW_ESTIMATE ); - plan_backward_blox = fftwf_plan_many_r2r(2, nfwd, numblox_W, fLblox[0], NULL, 1, TS*TS, Lblox[0], NULL, 1, TS*TS, bwdkind, FFTW_ESTIMATE ); - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // Main algorithm: Tile loop -#pragma omp parallel for schedule(dynamic) - //int vblock=0, hblock=0; - for (int vblk=0; vblk=height) { - rr = MAX(0,2*height-2-row); - } - - for (int j=0; jW; j++) { - datarow[j] = (labin->L[rr][j]-Ldn[rr][j]); - } - - for (int j=-blkrad*offset; j<0; j++) { - datarow[j] = datarow[MIN(-j,width-1)]; - } - for (int j=width; j=0 && top+i=0 && left+jL[i][j]/totwt[i][j];//note that labdn initially stores the denoised hipass data - - labdn->L[i][j] = Ldn[i][j] + hpdn; - - } - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // transform denoised "Lab" to output RGB - - RGB_OutputTransf(labdn, dst, dnparams); - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - delete labin; - delete labdn; - - }//end of main RGB_denoise - - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - void ImProcFunctions::RGBtile_denoise (float ** fLblox, int vblproc, int hblproc, int numblox_H, int numblox_W, float noisevar_Ldetail ) //for DCT - { - int vblprocmod=vblproc%8; - - float * nbrwt = new float[TS*TS]; //for DCT - - int blkstart = hblproc*TS*TS; - - boxabsblur(fLblox[vblprocmod]+blkstart, nbrwt, 3, 3, TS, TS);//blur neighbor weights for more robust estimation //for DCT - - for (int n=0; nL[top+i][left+j] += tilemask_out[i][j]*bloxrow_L[(indx + i)*TS+j]*DCTnorm; //for DCT - - } - } - - } - -#undef TS -#undef fTS -#undef offset - //#undef eps - - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -/* -void ImProcFunctions::FixImpulse_ab(LabImage * src, LabImage * dst, double radius, int thresh) { - - - float threshsqr = SQR(thresh); - int halfwin = ceil(2*radius)+1; - - // local variables - int width=src->W, height=src->H; - //temporary array to store chromaticity - float *fringe = float * calloc ((height)*(width), sizeof *fringe); - - LabImage * tmp1; - tmp1 = new LabImage(width, height); - -#ifdef _OPENMP -#pragma omp parallel -#endif - { - AlignedBuffer* buffer = new AlignedBuffer (MAX(src->W,src->H)); - gaussHorizontal (src->a, tmp1->a, buffer, src->W, src->H, radius, multiThread); - gaussHorizontal (src->b, tmp1->b, buffer, src->W, src->H, radius, multiThread); - gaussVertical (tmp1->a, tmp1->a, buffer, src->W, src->H, radius, multiThread); - gaussVertical (tmp1->b, tmp1->b, buffer, src->W, src->H, radius, multiThread); - - //gaussHorizontal (src->L, tmp1->L, buffer, src->W, src->H, radius, multiThread); - //gaussVertical (tmp1->L, tmp1->L, buffer, src->W, src->H, radius, multiThread); - - delete buffer; - } - - //#ifdef _OPENMP - //#pragma omp parallel for - //#endif - float chromave=0; - for(int i = 0; i < height; i++ ) { - for(int j = 0; j < width; j++) { - float chroma = SQR(src->a[i][j]-tmp1->a[i][j])+SQR(src->b[i][j]-tmp1->b[i][j]); - chromave += chroma; - fringe[i*width+j]=chroma; - } - } - chromave /= (height*width); - -#ifdef _OPENMP -#pragma omp parallel for -#endif - - for(int i = 0; i < height; i++ ) { - for(int j = 0; j < width; j++) { - tmp1->a[i][j] = src->a[i][j]; - tmp1->b[i][j] = src->b[i][j]; - if (33*fringe[i*width+j]>thresh*chromave) { - float atot=0; - float btot=0; - float norm=0; - float wt; - for (int i1=MAX(0,i-halfwin+1); i1a[i1][j1]; - btot += wt*src->b[i1][j1]; - norm += wt; - } - tmp1->a[i][j] = (int)(atot/norm); - tmp1->b[i][j] = (int)(btot/norm); - }//end of ab channel averaging - } - } - -#ifdef _OPENMP -#pragma omp parallel for -#endif - - for(int i = 0; i < height; i++ ) { - for(int j = 0; j < width; j++) { - dst->L[i][j] = src->L[i][j]; - dst->a[i][j] = tmp1->a[i][j]; - dst->b[i][j] = tmp1->b[i][j]; - } - } - - delete tmp1; - free(fringe); - -} -*/ - - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - void ImProcFunctions::WaveletDenoise(cplx_wavelet_decomposition &DualTreeCoeffs, float noisevar ) - { - int maxlvl = DualTreeCoeffs.maxlevel(); - int rad_stage1[8] = {3,2,1,1,1,1,1,1}; - int rad_stage2[8] = {2,1,1,1,1,1,1,1}; - - for (int lvl=0; lvl wiener1(Wlvl,Hlvl); - - for (int m=0; m<2; m++) { - float ** ReCoeffs = DualTreeCoeffs.level_coeffs(lvl,0+m); - float ** ImCoeffs = DualTreeCoeffs.level_coeffs(lvl,2+m); - float ** ReParents = DualTreeCoeffs.level_coeffs(lvl+1,0+m); - float ** ImParents = DualTreeCoeffs.level_coeffs(lvl+1,2+m); - int ParentPadding = DualTreeCoeffs.level_pad(lvl+1,0+m); - for (int dir=1; dir<4; dir++) { - //FirstStageWiener (ReCoeffs[dir],ImCoeffs[dir],wiener1,Wlvl,Hlvl,rad_stage1[lvl], noisevar); - //SecondStageWiener(ReCoeffs[dir],ImCoeffs[dir],wiener1,Wlvl,Hlvl,rad_stage2[lvl], noisevar); - - BiShrink(ReCoeffs[dir], ImCoeffs[dir], ReParents[dir], ImParents[dir], Wlvl, Hlvl, lvl, ParentPadding, noisevar); - } - } - } - - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - void ImProcFunctions::WaveletDenoise(wavelet_decomposition &WaveletCoeffs, float noisevar ) - { - int maxlvl = WaveletCoeffs.maxlevel(); - int rad_stage1[8] = {3,2,1,1,1,1,1,1}; - int rad_stage2[8] = {2,1,1,1,1,1,1,1}; - - for (int lvl=0; lvl wiener1(Wlvl,Hlvl); - int ParentPadding; - float ** WavParents; - float ** WavCoeffs = WaveletCoeffs.level_coeffs(lvl); - if (lvl2*thresh_a ? 1 : (coeff_a2*thresh_b ? 1 : (coeff_b2*thresh_L ? 1 : (coeff_L2*thresh_L ? 1 : (coeff_L=0; lvl--) {//for levels less than max, use level diff to make edge mask - //for (int lvl=0; lvl edge(Wlvl_L,Hlvl_L); - AlignedBuffer* buffer = new AlignedBuffer (MAX(Wlvl_L,Hlvl_L)); - - printf("\n level=%d \n",lvl); - - for (int dir=1; dir<4; dir++) { - float mad_L = madL[lvl][dir-1]; - float mad_a = noisevar_ab*mada[lvl][dir-1]; - float mad_b = noisevar_ab*madb[lvl][dir-1]; - //float mad_Lpar = madL[lvl+1][dir-1]; - //float mad_apar = mada[lvl+1][dir-1]; - //float mad_bpar = mada[lvl+1][dir-1]; - - //float skip_ab_ratio = WaveletCoeffs_a.level_stride(lvl+1)/skip_ab; - float skip_L_ratio = WaveletCoeffs_L.level_stride(lvl+1)/skip_L; - - printf(" dir=%d mad_L=%f mad_a=%f mad_b=%f \n",dir,sqrt(mad_L),sqrt(mad_a),sqrt(mad_b)); - - for (int i=0; i2 ? 1 : (coeff_a<1 ? 0 : (coeff_a - 1))); - //WavCoeffs_b[dir][coeffloc_ab] *= edgefactor*(coeff_b>2 ? 1 : (coeff_b<1 ? 0 : (coeff_b - 1))); - - //float satfactor_a = mad_a/(mad_a+0.5*SQR(WavCoeffs_a[0][coeffloc_ab])); - //float satfactor_b = mad_b/(mad_b+0.5*SQR(WavCoeffs_b[0][coeffloc_ab])); - - WavCoeffs_a[dir][coeffloc_ab] *= SQR(1-exp(-(mag_a/mad_a)-(mag_L/(9*mad_L)))/*satfactor_a*/); - WavCoeffs_b[dir][coeffloc_ab] *= SQR(1-exp(-(mag_b/mad_b)-(mag_L/(9*mad_L)))/*satfactor_b*/); - - } - }//now chrominance coefficients are denoised - - mad_L *= noisevar_L*5/(lvl+1); - - for (int i=0; i (edge, edge, buffer, Wlvl_L, Hlvl_L, 1<<(lvl+1), false /*multiThread*/); - gaussVertical (edge, edge, buffer, Wlvl_L, Hlvl_L, 1<<(lvl+1), false); - - boxblur(sfave, sfave, lvl+2, lvl+2, Wlvl_L, Hlvl_L);//increase smoothness by locally averaging shrinkage - - for (int i=0; i +void copy_out(A * a, A * b, size_t datalen) +{// for standard wavelet decomposition + memcpy(b, a, datalen*sizeof(A)); +} template void copy_out(A ** a, B * b, size_t datalen) diff --git a/rtengine/cplx_wavelet_filter_coeffs.h b/rtengine/cplx_wavelet_filter_coeffs.h index 199606762..ac537d0a1 100644 --- a/rtengine/cplx_wavelet_filter_coeffs.h +++ b/rtengine/cplx_wavelet_filter_coeffs.h @@ -116,10 +116,14 @@ const int LeGall_len=6; const int LeGall_offset=2; const float LeGall_anal[2][6] = {{0, 0.25, 0.5, 0.25, 0, 0}, {0, -0.125, -0.25, 0.75, -0.25, -0.125}}; const float LeGall_synth[2][6] = {{-0.125, 0.25, 0.75, 0.25, -0.125, 0}, {0, 0, -0.25, 0.5, -0.25, 0}}; - - //{{{-1, 0.25}, {0, 0.5}, {1, 0.25}}, {{-1, -0.125}, {0, -0.25}, {1, 0.75}, {2, -0.25}, {3, -0.125}}} - //{{{-2, -0.125}, {-1, 0.25}, {0, 0.75}, {1, 0.25}, {2, -0.125}}, {{0, -0.25}, {1, 0.5}, {2, -0.25}}} +/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */ + +const int Daub4_len=6; +const int Daub4_offset=2; +const float Daub4_anal[2][6] = {//analysis filter + {0, 0, 0.34150635, 0.59150635, 0.15849365, -0.091506351}, + {-0.091506351, -0.15849365, 0.59150635, -0.34150635, 0, 0}}; }; diff --git a/rtengine/cplx_wavelet_level.h b/rtengine/cplx_wavelet_level.h index 8140a1a12..759fa3e2c 100644 --- a/rtengine/cplx_wavelet_level.h +++ b/rtengine/cplx_wavelet_level.h @@ -407,6 +407,7 @@ namespace rtengine { for(size_t i = m_pad; i < (dstlen+m_pad); i++) { float tot=0; + //TODO: this is correct only if skip=1; otherwise, want to work with cosets of length 'skip' int i_src = (i+shift)/2; int begin = (i+shift)%2; if (i>skip*taps && i<(srclen-skip*taps)) {//bulk @@ -448,7 +449,7 @@ namespace rtengine { dstHi[(pitch*(i/2))] = 0.5*(srcbuffer[i] - srcbuffer[i+skip]); } - for(size_t i = (srclen-skip)-(srclen-skip)&1; i < (srclen); i+=2) { + for(size_t i = (srclen-skip)-((srclen-skip)&1); i < (srclen); i+=2) { dstLo[(pitch*(i/2))] = 0.5*(srcbuffer[i] + srcbuffer[i-skip]); dstHi[(pitch*(i/2))] = 0.5*(srcbuffer[i] - srcbuffer[i-skip]); } @@ -469,17 +470,22 @@ namespace rtengine { // calculate coefficients //TODO: this code is buggy... - for(size_t i = m_pad; i < (dstlen+m_pad-skip); i+=2*skip) { - dst[pitch*(i-m_pad)] = srcLo[i/2]+srcHi[i/2]; - dst[pitch*(i+skip-m_pad)] = srcLo[i/2]-srcHi[i/2]; - } - - if ((dstlen+m_pad-skip) Ldn(cropw,croph); - //parent->ipf.L_denoise(origCrop, laboCrop, params.dirpyrDenoise); - //parent->ipf.dirpyrLab_denoise(laboCrop, origCrop, params.dirpyrDenoise); parent->ipf.RGB_denoise(origCrop, origCrop, /*Roffset,*/ params.dirpyrDenoise, params.defringe); } } @@ -154,7 +151,6 @@ void Crop::update (int todo) { if (skip==1) { parent->ipf.impulsedenoise (labnCrop); parent->ipf.defringe (labnCrop); - //parent->ipf.dirpyrdenoise (labnCrop); parent->ipf.MLsharpen (labnCrop); parent->ipf.MLmicrocontrast (labnCrop); //parent->ipf.MLmicrocontrast (labnCrop); diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 9c1aa83d0..4b9df1fee 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -320,9 +320,6 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { readyphase++; progress ("Defringing...",100*readyphase/numofphases); ipf.defringe (nprevl); - readyphase++; - progress ("Denoising luma/chroma...",100*readyphase/numofphases); - //ipf.dirpyrdenoise (nprevl); readyphase++; if (params.sharpenEdge.enabled) { progress ("Edge sharpening...",100*readyphase/numofphases); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 39590b1a2..e5b7f208f 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -570,15 +570,6 @@ void ImProcFunctions::colorCurve (LabImage* lold, LabImage* lnew) { PF_correct_RT(lab, lab, params->defringe.radius, params->defringe.threshold); } - void ImProcFunctions::dirpyrdenoise (LabImage* lab) { - - if (params->dirpyrDenoise.enabled && lab->W>=8 && lab->H>=8) { - - //L_denoise(lab, lab, params->dirpyrDenoise); - if (params->dirpyrDenoise.chroma) - dirpyrLab_denoise(lab, lab, params->dirpyrDenoise ); - } - } void ImProcFunctions::dirpyrequalizer (LabImage* lab) { diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index ca8a07bb9..c24ad6c42 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -216,9 +216,9 @@ void ProcParams::setDefaults () { defringe.threshold = 25; dirpyrDenoise.enabled = false; - dirpyrDenoise.luma = 20; + dirpyrDenoise.luma = 30; dirpyrDenoise.Ldetail = 50; - dirpyrDenoise.chroma = 20; + dirpyrDenoise.chroma = 30; dirpyrDenoise.gamma = 1.7; dirpyrDenoise.expcomp = 0.0; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index de7be828e..420976520 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -111,11 +111,10 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p imgsrc->getImage (currWB, tr, baseImg, pp, params.hlrecovery, params.icm, params.raw); if (pl) pl->setProgress (0.45); - // perform luma denoise + // perform luma/chroma denoise LabImage* labView = new LabImage (fw,fh); if (params.dirpyrDenoise.enabled) { - //ipf.L_denoise(baseImg, labView, params.dirpyrDenoise); - //ipf.dirpyrLab_denoise(labView, baseImg, params.dirpyrDenoise); + ipf.RGB_denoise(baseImg, baseImg, params.dirpyrDenoise, params.defringe); } imgsrc->convertColorSpace(baseImg, params.icm); @@ -214,7 +213,6 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p ipf.impulsedenoise (labView); ipf.defringe (labView); - //ipf.dirpyrdenoise (labView); if (params.sharpenEdge.enabled) { ipf.MLsharpen(labView); } diff --git a/rtgui/dirpyrdenoise.cc b/rtgui/dirpyrdenoise.cc index 545b14b0e..0ec496858 100644 --- a/rtgui/dirpyrdenoise.cc +++ b/rtgui/dirpyrdenoise.cc @@ -36,10 +36,12 @@ DirPyrDenoise::DirPyrDenoise () : Gtk::VBox(), FoldableToolPanel(this) { enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &DirPyrDenoise::enabledChanged) ); - luma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_LUMA"), 0, 100, 0.01, 20)); + + luma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_LUMA"), 0, 100, 0.01, 30)); Ldetail = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_LDETAIL"), 0, 100, 0.01, 50)); - chroma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_CHROMA"), 0, 100, 0.01, 20)); - gamma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_GAMMA"), 1.0, 3.0, 0.01, 1.7)); + chroma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_CHROMA"), 0, 100, 0.01, 30)); + gamma = Gtk::manage (new Adjuster (M("TP_DIRPYRDENOISE_GAMMA"), 1.0, 3.0, 0.01, 1.7)); + luma->setAdjusterListener (this); Ldetail->setAdjusterListener (this);