diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 4c417fd44..d741e0428 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -81,7 +81,7 @@ namespace rtengine { - void ImProcFunctions::RGB_denoise(Imagefloat * src, Imagefloat * dst, const procparams::DirPyrDenoiseParams & dnparams, const procparams::DefringeParams & defringe) + void ImProcFunctions::RGB_denoise(Imagefloat * src, Imagefloat * dst, bool isRAW, const procparams::DirPyrDenoiseParams & dnparams, const procparams::DefringeParams & defringe) { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -139,7 +139,7 @@ namespace rtengine { array2D tilemask_out(TS,TS); const int border = MAX(2,TS/16); - + #ifdef _OPENMP #pragma omp parallel for #endif @@ -166,9 +166,9 @@ namespace rtengine { const int tilesize = 1024; const int overlap = 128; - + int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; - + if (imwidth Ldetail(width,height,ARRAY2D_CLEAR_DATA); //pixel weight array2D totwt(width,height,ARRAY2D_CLEAR_DATA);//weight for combining DCT blocks - -//#ifdef _OPENMP -//#pragma omp parallel for -//#endif -//TODO: implement using AlignedBufferMP + + //#ifdef _OPENMP + //#pragma omp parallel for + //#endif + //TODO: implement using AlignedBufferMP //fill tile from image; convert RGB to "luma/chroma" - for (int i=tiletop/*, i1=0*/; ir[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] : (Color::gamma((double)X/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - Y = Y<65535.0f ? gamcurve[Y] : (Color::gamma((double)Y/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - Z = Z<65535.0f ? gamcurve[Z] : (Color::gamma((double)Z/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); - - labdn->L[i1][j1] = Y; - labdn->a[i1][j1] = (X-Y); - labdn->b[i1][j1] = (Y-Z); - - Ldetail[i1][j1] = 0; - Lin[i1][j1] = Y; - totwt[i1][j1] = 0; + if (isRAW) {//image is raw; use channel differences for chroma channels + for (int i=tiletop/*, i1=0*/; ir[i][j]; + float Y = gain*src->g[i][j]; + float Z = gain*src->b[i][j]; + + X = X<65535.0f ? gamcurve[X] : (Color::gamma((double)X/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + Y = Y<65535.0f ? gamcurve[Y] : (Color::gamma((double)Y/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + Z = Z<65535.0f ? gamcurve[Z] : (Color::gamma((double)Z/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + + labdn->L[i1][j1] = Y; + labdn->a[i1][j1] = (X-Y); + labdn->b[i1][j1] = (Y-Z); + + Ldetail[i1][j1] = 0; + Lin[i1][j1] = Y; + totwt[i1][j1] = 0; + } + } + } else {//image is not raw; use Lab parametrization + for (int i=tiletop/*, i1=0*/; ir[i][j] ]; + float gtmp = Color::igammatab_srgb[ src->g[i][j] ]; + float btmp = Color::igammatab_srgb[ src->b[i][j] ]; + + //perhaps use LCH or YCrCb ??? + float X = xyz_sRGB[0][0]*rtmp + xyz_sRGB[0][1]*gtmp + xyz_sRGB[0][2]*btmp; + float Y = xyz_sRGB[1][0]*rtmp + xyz_sRGB[1][1]*gtmp + xyz_sRGB[1][2]*btmp; + float Z = xyz_sRGB[2][0]*rtmp + xyz_sRGB[2][1]*gtmp + xyz_sRGB[2][2]*btmp; + + X = X<65535.0f ? gamcurve[X] : (Color::gamma((double)X/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + Y = Y<65535.0f ? gamcurve[Y] : (Color::gamma((double)Y/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + Z = Z<65535.0f ? gamcurve[Z] : (Color::gamma((double)Z/65535.0, gam, gamthresh, gamslope, 1.0, 0.0)*32768.0f); + + labdn->L[i1][j1] = Y; + labdn->a[i1][j1] = (X-Y); + labdn->b[i1][j1] = (Y-Z); + + Ldetail[i1][j1] = 0; + Lin[i1][j1] = Y; + totwt[i1][j1] = 0; + } } } + //initial impulse denoise if (dnparams.luma>0.01) { impulse_nr (labdn, MIN(50.0f,dnparams.luma)/20.0f); @@ -259,7 +291,7 @@ namespace rtengine { //WaveletDenoiseAll_BiShrink(Ldecomp, adecomp, bdecomp, noisevarL, noisevarab); WaveletDenoiseAll(Ldecomp, adecomp, bdecomp, noisevarL, noisevarab); - + Ldecomp.reconstruct(labdn->data); adecomp.reconstruct(labdn->data+datalen); bdecomp.reconstruct(labdn->data+2*datalen); @@ -312,8 +344,8 @@ namespace rtengine { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // Main detail recovery algorithm: Block loop -//OpenMP here -//adding omp here leads to artifacts + //OpenMP here + //adding omp here leads to artifacts for (int vblk=0; vblk0) Hmask[i] = mask; if (tilerightL[i1][j1]; - X = (labdn->a[i1][j1]) + Y; - Z = Y - (labdn->b[i1][j1]); - - X = X<32768.0f ? igamcurve[X] : (Color::gamma((float)X/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); - Y = Y<32768.0f ? igamcurve[Y] : (Color::gamma((float)Y/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); - Z = Z<32768.0f ? igamcurve[Z] : (Color::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 - - float factor = Vmask[i1]*Hmask[j1]/gain; - - dsttmp->r[i][j] += factor*X;//prophoto_xyz[0][0]*X + prophoto_xyz[0][1]*Y + prophoto_xyz[0][2]*Z; - dsttmp->g[i][j] += factor*Y;//prophoto_xyz[1][0]*X + prophoto_xyz[1][1]*Y + prophoto_xyz[1][2]*Z; - dsttmp->b[i][j] += factor*Z;//prophoto_xyz[2][0]*X + prophoto_xyz[2][1]*Y + prophoto_xyz[2][2]*Z; - + for (int i=tiletop; iL[i1][j1]; + X = (labdn->a[i1][j1]) + Y; + Z = Y - (labdn->b[i1][j1]); + + X = X<32768.0f ? igamcurve[X] : (Color::gamma((float)X/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); + Y = Y<32768.0f ? igamcurve[Y] : (Color::gamma((float)Y/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); + Z = Z<32768.0f ? igamcurve[Z] : (Color::gamma((float)Z/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); + + float factor = Vmask[i1]*Hmask[j1]/gain; + + dsttmp->r[i][j] += factor*X; + dsttmp->g[i][j] += factor*Y; + dsttmp->b[i][j] += factor*Z; + + } + } + } else { +#ifdef _OPENMP +#pragma omp parallel for +#endif + for (int i=tiletop; iL[i1][j1]; + X = (labdn->a[i1][j1]) + Y; + Z = Y - (labdn->b[i1][j1]); + + X = X<32768.0f ? igamcurve[X] : (Color::gamma((float)X/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); + Y = Y<32768.0f ? igamcurve[Y] : (Color::gamma((float)Y/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); + Z = Z<32768.0f ? igamcurve[Z] : (Color::gamma((float)Z/32768.0f, igam, igamthresh, igamslope, 1.0, 0.0) * 65535.0f); + + float factor = Vmask[i1]*Hmask[j1]; + + float rtmp = sRGB_xyz[0][0]*X + sRGB_xyz[0][1]*Y + sRGB_xyz[0][2]*Z; + float gtmp = sRGB_xyz[1][0]*X + sRGB_xyz[1][1]*Y + sRGB_xyz[1][2]*Z; + float btmp = sRGB_xyz[2][0]*X + sRGB_xyz[2][1]*Y + sRGB_xyz[2][2]*Z; + + dsttmp->r[i][j] += factor*rtmp; + dsttmp->g[i][j] += factor*gtmp; + dsttmp->b[i][j] += factor*btmp; + + } } } @@ -473,12 +535,21 @@ namespace rtengine { }//end of tile row }//end of tile loop - //copy denoised image to output - memcpy (dst->data, dsttmp->data, 3*dst->width*dst->height*sizeof(float)); - - delete dsttmp; - -}//end of main RGB_denoise + //copy denoised image to output + memcpy (dst->data, dsttmp->data, 3*dst->width*dst->height*sizeof(float)); + + if (!isRAW) {//restore original image gamma +#ifdef _OPENMP +#pragma omp parallel for +#endif + for (int i=0; i<3*dst->width*dst->height; i++) { + dst->data[i] = Color::gammatab_srgb[ dst->data[i] ]; + } + } + + delete dsttmp; + + }//end of main RGB_denoise //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 4221b35d4..cf1391594 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -106,7 +106,7 @@ void Crop::update (int todo) { if (todo & M_LINDENOISE) { if (skip==1 && params.dirpyrDenoise.enabled) { - parent->ipf.RGB_denoise(origCrop, origCrop, /*Roffset,*/ params.dirpyrDenoise, params.defringe); + parent->ipf.RGB_denoise(origCrop, origCrop, parent->imgsrc->isRAW(), /*Roffset,*/ params.dirpyrDenoise, params.defringe); } } parent->imgsrc->convertColorSpace(origCrop, params.icm, params.raw); diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 83c9f2eff..a0cdd2782 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -107,6 +107,7 @@ class ImageSource : public InitialImage { virtual ImageData* getImageData () =0; virtual ImageMatrices* getImageMatrices () =0; + virtual bool isRAW() const =0; virtual void setProgressListener (ProgressListener* pl) {} diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 9804b60b7..8b18650cc 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -223,7 +223,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { if (todo & M_LINDENOISE) { //printf("denoising!\n"); if (scale==1 && params.dirpyrDenoise.enabled) { - ipf.RGB_denoise(orig_prev, orig_prev, params.dirpyrDenoise, params.defringe); + ipf.RGB_denoise(orig_prev, orig_prev, imgsrc->isRAW(), params.dirpyrDenoise, params.defringe); } ImageMatrices* imatrices = imgsrc->getImageMatrices (); } diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index f50b4b26b..e31f4a3b1 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -122,7 +122,7 @@ class ImProcFunctions { //void RGB_InputTransf(Imagefloat * src, LabImage * dst, const procparams::DirPyrDenoiseParams & dnparams, const procparams::DefringeParams & defringe); //void RGB_OutputTransf(LabImage * src, Imagefloat * dst, const procparams::DirPyrDenoiseParams & dnparams); //void output_tile_row (float *Lbloxrow, float ** Lhipassdn, float ** tilemask, int height, int width, int top, int blkrad ); - void RGB_denoise(Imagefloat * src, Imagefloat * dst, const procparams::DirPyrDenoiseParams & dnparams, const procparams::DefringeParams & defringe); + void RGB_denoise(Imagefloat * src, Imagefloat * dst, bool isRAW, const procparams::DirPyrDenoiseParams & dnparams, const procparams::DefringeParams & defringe); void RGBtile_denoise (float * fLblox, int vblproc, int hblproc, int numblox_H, int numblox_W, float noisevar_L ); //for DCT void RGBoutput_tile_row (float *Lbloxrow, float ** Ldetail, float ** tilemask_out, int height, int width, int top ); //void WaveletDenoise(cplx_wavelet_decomposition &DualTreeCoeffs, float noisevar ); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 2c29ad396..e8794801f 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -164,6 +164,8 @@ class RawImageSource : public ImageSource { ImageData* getImageData () { return idata; } ImageMatrices* getImageMatrices () { return &imatrices; } + bool isRAW() const { return true; } + void setProgressListener (ProgressListener* pl) { plistener = pl; } void getAutoExpHistogram (LUTu & histogram, int& histcompr); void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 5c437f4d7..2e728b437 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -110,7 +110,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // perform luma/chroma denoise LabImage* labView = new LabImage (fw,fh); if (params.dirpyrDenoise.enabled) { - ipf.RGB_denoise(baseImg, baseImg, params.dirpyrDenoise, params.defringe); + ipf.RGB_denoise(baseImg, baseImg, imgsrc->isRAW(), params.dirpyrDenoise, params.defringe); } imgsrc->convertColorSpace(baseImg, params.icm, params.raw); diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 220fa8ff1..25eb71cde 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -58,6 +58,8 @@ class StdImageSource : public ImageSource { ImageData* getImageData () { return idata; } ImageMatrices* getImageMatrices () { return (ImageMatrices*)NULL; } + bool isRAW() const { return false; } + void setProgressListener (ProgressListener* pl) { plistener = pl; } void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, RAWParams raw);// RAWParams raw will not be used for non-raw files (see imagesource.h)