From 200e6dd882603c0caf761a8258add299c425045e Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 7 Mar 2017 17:38:32 +0100 Subject: [PATCH 01/18] experimental hacks on simpleprocess.cc --- rtengine/simpleprocess.cc | 2486 ++++++++++++++++++++----------------- 1 file changed, 1373 insertions(+), 1113 deletions(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 9f1ca3c5c..e027968a5 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -35,641 +35,729 @@ namespace rtengine { extern const Settings* settings; -IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool tunnelMetaData, bool flush) -{ +namespace { - errorCode = 0; - - ProcessingJobImpl* job = static_cast(pjob); - - if (pl) { - pl->setProgressStr ("PROGRESSBAR_PROCESSING"); - pl->setProgress (0.0); +class ImageProcessor { +public: + ImageProcessor(ProcessingJob* pjob, int& errorCode, + ProgressListener* pl, bool tunnelMetaData, bool flush): + pjob(pjob), + errorCode(errorCode), + pl(pl), + tunnelMetaData(tunnelMetaData), + flush(flush), + // internal state + ii(nullptr), + imgsrc(nullptr), + fw(-1), + fh(-1), + pp(0, 0, 0, 0, 0) + { } - InitialImage* ii = job->initialImage; + Image16 *operator()(bool fast) + { + if (!fast) { + return normal_pipeline(); + } else { + return fast_pipeline(); + } + } - if (!ii) { - ii = InitialImage::load (job->fname, job->isRaw, &errorCode); - - if (errorCode) { - delete job; +private: + Image16 *normal_pipeline() + { + if (!stage_1()) { return nullptr; } + stage_calc_denoise(); + stage_2(); + stage_3(); + stage_4(); + stage_5(); + stage_6(); + return stage_7(); } - procparams::ProcParams& params = job->pparams; + Image16 *fast_pipeline() + { + ProcessingJobImpl* job = static_cast(pjob); + if (!job->pparams.resize.enabled) { + return normal_pipeline(); + } + + if (!stage_1()) { + return nullptr; + } + stage_2(); + stage_4(); + stage_early_resize(); + stage_calc_denoise(); + stage_3(); + stage_5(); + stage_6(); + return stage_7(); + } - // acquire image from imagesource - ImageSource* imgsrc = ii->getImageSource (); + bool stage_1() + { + errorCode = 0; - int tr = getCoarseBitMask(params.coarse); - int fw, fh; - imgsrc->getFullSize (fw, fh, tr); + ProcessingJobImpl* job = static_cast(pjob); - // check the crop params - if (params.crop.x > fw || params.crop.y > fh) { - // the crop is completely out of the image, so we disable the crop - params.crop.enabled = false; - // and we set the values to the defaults - params.crop.x = 0; - params.crop.y = 0; - params.crop.w = fw; - params.crop.h = fh; - } else { - if (params.crop.x < 0) { + if (pl) { + pl->setProgressStr ("PROGRESSBAR_PROCESSING"); + pl->setProgress (0.0); + } + + ii = job->initialImage; + + if (!ii) { + ii = InitialImage::load (job->fname, job->isRaw, &errorCode); + + if (errorCode) { + delete job; + return false; //return nullptr; + } + } + + procparams::ProcParams& params = job->pparams; + + // acquire image from imagesource + imgsrc = ii->getImageSource (); + + tr = getCoarseBitMask(params.coarse); + imgsrc->getFullSize (fw, fh, tr); + + // check the crop params + if (params.crop.x > fw || params.crop.y > fh) { + // the crop is completely out of the image, so we disable the crop + params.crop.enabled = false; + // and we set the values to the defaults params.crop.x = 0; - } - - if (params.crop.y < 0) { params.crop.y = 0; - } + params.crop.w = fw; + params.crop.h = fh; + } else { + if (params.crop.x < 0) { + params.crop.x = 0; + } - if ((params.crop.x + params.crop.w) > fw) { - // crop overflow in the width dimension ; we trim it - params.crop.w = fw - params.crop.x; - } + if (params.crop.y < 0) { + params.crop.y = 0; + } - if ((params.crop.y + params.crop.h) > fh) { - // crop overflow in the height dimension ; we trim it - params.crop.h = fh - params.crop.y; + if ((params.crop.x + params.crop.w) > fw) { + // crop overflow in the width dimension ; we trim it + params.crop.w = fw - params.crop.x; + } + + if ((params.crop.y + params.crop.h) > fh) { + // crop overflow in the height dimension ; we trim it + params.crop.h = fh - params.crop.y; + } } - } // MyTime t1,t2; // t1.set(); - ImProcFunctions ipf (¶ms, true); + ImProcFunctions ipf (¶ms, true); - PreviewProps pp (0, 0, fw, fh, 1); - imgsrc->preprocess( params.raw, params.lensProf, params.coarse, params.dirpyrDenoise.enabled); + pp = PreviewProps(0, 0, fw, fh, 1); + imgsrc->preprocess( params.raw, params.lensProf, params.coarse, params.dirpyrDenoise.enabled); - if (params.toneCurve.autoexp) {// this enabled HLRecovery - LUTu histRedRaw(256), histGreenRaw(256), histBlueRaw(256); - imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw); + if (params.toneCurve.autoexp) {// this enabled HLRecovery + LUTu histRedRaw(256), histGreenRaw(256), histBlueRaw(256); + imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw); - if (ToneCurveParams::HLReconstructionNecessary(histRedRaw, histGreenRaw, histBlueRaw) && !params.toneCurve.hrenabled) { - params.toneCurve.hrenabled = true; - // WARNING: Highlight Reconstruction is being forced 'on', should we force a method here too? + if (ToneCurveParams::HLReconstructionNecessary(histRedRaw, histGreenRaw, histBlueRaw) && !params.toneCurve.hrenabled) { + params.toneCurve.hrenabled = true; + // WARNING: Highlight Reconstruction is being forced 'on', should we force a method here too? + } } - } - if (pl) { - pl->setProgress (0.20); - } + if (pl) { + pl->setProgress (0.20); + } - imgsrc->demosaic( params.raw); + imgsrc->demosaic( params.raw); - if (pl) { - pl->setProgress (0.30); - } + if (pl) { + pl->setProgress (0.30); + } - if(params.retinex.enabled) { //enabled Retinex - LUTf cdcurve (65536, 0); - LUTf mapcurve (65536, 0); - LUTu dummy; - RetinextransmissionCurve dehatransmissionCurve; - RetinexgaintransmissionCurve dehagaintransmissionCurve; - bool dehacontlutili = false; - bool mapcontlutili = false; - bool useHsl = false; + if(params.retinex.enabled) { //enabled Retinex + LUTf cdcurve (65536, 0); + LUTf mapcurve (65536, 0); + LUTu dummy; + RetinextransmissionCurve dehatransmissionCurve; + RetinexgaintransmissionCurve dehagaintransmissionCurve; + bool dehacontlutili = false; + bool mapcontlutili = false; + bool useHsl = false; // multi_array2D conversionBuffer(1, 1); - multi_array2D conversionBuffer(1, 1); - imgsrc->retinexPrepareBuffers(params.icm, params.retinex, conversionBuffer, dummy); - imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, dehacontlutili, mapcontlutili, useHsl, dummy, dummy ); - float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; - imgsrc->retinex( params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, dummy); - } - - if (pl) { - pl->setProgress (0.40); - } - - imgsrc->HLRecovery_Global( params.toneCurve ); - - - if (pl) { - pl->setProgress (0.45); - } - - // set the color temperature - ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method); - - if (params.wb.method == "Camera") { - currWB = imgsrc->getWB (); - } else if (params.wb.method == "Auto") { - double rm, gm, bm; - imgsrc->getAutoWBMultipliers(rm, gm, bm); - currWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias); - } - - NoiseCurve noiseLCurve; - NoiseCurve noiseCCurve; - Imagefloat *calclum = nullptr ; - params.dirpyrDenoise.getCurves(noiseLCurve, noiseCCurve); - float autoNR = (float) settings->nrauto;// - float autoNRmax = (float) settings->nrautomax;// - int tilesize; - int overlap; - - if(settings->leveldnti == 0) { - tilesize = 1024; - overlap = 128; - } - - if(settings->leveldnti == 1) { - tilesize = 768; - overlap = 96; - } - - // const int tilesize = 768; - // const int overlap = 96; - int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; - ipf.Tile_calc (tilesize, overlap, 2, fw, fh, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip); - int nbtl = numtiles_W * numtiles_H; - - if((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { - nbtl = 9; - } - - float *ch_M = new float [nbtl];//allocate memory - float *max_r = new float [nbtl]; - float *max_b = new float [nbtl]; - float *min_b = new float [9]; - float *min_r = new float [9]; - float *lumL = new float [nbtl]; - float *chromC = new float [nbtl]; - float *ry = new float [nbtl]; - float *sk = new float [nbtl]; - float *pcsk = new float [nbtl]; - - // printf("expert=%d\n",settings->leveldnautsimpl); - if(settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "PON") { - MyTime t1pone, t2pone; - t1pone.set(); - int crW, crH; - - if(settings->leveldnv == 0) { - crW = 100; - crH = 100; + multi_array2D conversionBuffer(1, 1); + imgsrc->retinexPrepareBuffers(params.icm, params.retinex, conversionBuffer, dummy); + imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, dehacontlutili, mapcontlutili, useHsl, dummy, dummy ); + float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; + imgsrc->retinex( params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, dummy); } - if(settings->leveldnv == 1) { - crW = 250; - crH = 250; + if (pl) { + pl->setProgress (0.40); } - if(settings->leveldnv == 2) { - crW = int(tileWskip / 2); - crH = int(tileHskip / 2); + imgsrc->HLRecovery_Global( params.toneCurve ); + + + if (pl) { + pl->setProgress (0.45); } - // if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int(1.15f*(tileWskip/2));}//adapted to scale of preview - if(settings->leveldnv == 3) { - crW = tileWskip - 10; - crH = tileHskip - 10; + // set the color temperature + currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method); + + if (params.wb.method == "Camera") { + currWB = imgsrc->getWB (); + } else if (params.wb.method == "Auto") { + double rm, gm, bm; + imgsrc->getAutoWBMultipliers(rm, gm, bm); + currWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias); } - float lowdenoise = 1.f; - int levaut = settings->leveldnaut; + // // AG begin + // baseImg = new Imagefloat (fw, fh); + // imgsrc->getImage (currWB, tr, baseImg, pp, params.toneCurve, params.icm, params.raw); + // // AG end - if(levaut == 1) { //Standard - lowdenoise = 0.7f; + return true; + } + + void stage_calc_denoise() + { + ProcessingJobImpl* job = static_cast(pjob); + procparams::ProcParams& params = job->pparams; + ImProcFunctions ipf (¶ms, true); + + calclum = nullptr ; + params.dirpyrDenoise.getCurves(noiseLCurve, noiseCCurve); + autoNR = (float) settings->nrauto;// + autoNRmax = (float) settings->nrautomax;// + + if(settings->leveldnti == 0) { + tilesize = 1024; + overlap = 128; } - // int crW=tileWskip-10;//crop noise width - // int crH=tileHskip-10;//crop noise height + if(settings->leveldnti == 1) { + tilesize = 768; + overlap = 96; + } + + // const int tilesize = 768; + // const int overlap = 96; + int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; + ipf.Tile_calc (tilesize, overlap, 2, fw, fh, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip); + int nbtl = numtiles_W * numtiles_H; + + if((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { + nbtl = 9; + } + + ch_M = new float [nbtl];//allocate memory + max_r = new float [nbtl]; + max_b = new float [nbtl]; + min_b = new float [9]; + min_r = new float [9]; + lumL = new float [nbtl]; + chromC = new float [nbtl]; + ry = new float [nbtl]; + sk = new float [nbtl]; + pcsk = new float [nbtl]; + + // printf("expert=%d\n",settings->leveldnautsimpl); + if(settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "PON") { + MyTime t1pone, t2pone; + t1pone.set(); + int crW, crH; + + if(settings->leveldnv == 0) { + crW = 100; + crH = 100; + } + + if(settings->leveldnv == 1) { + crW = 250; + crH = 250; + } + + if(settings->leveldnv == 2) { + crW = int(tileWskip / 2); + crH = int(tileHskip / 2); + } + + // if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int(1.15f*(tileWskip/2));}//adapted to scale of preview + if(settings->leveldnv == 3) { + crW = tileWskip - 10; + crH = tileHskip - 10; + } + + float lowdenoise = 1.f; + int levaut = settings->leveldnaut; + + if(levaut == 1) { //Standard + lowdenoise = 0.7f; + } + + // int crW=tileWskip-10;//crop noise width + // int crH=tileHskip-10;//crop noise height // Imagefloat *origCropPart;//init auto noise // origCropPart = new Imagefloat (crW, crH);//allocate memory - if (params.dirpyrDenoise.enabled) {//evaluate Noise - LUTf gamcurve(65536, 0); - float gam, gamthresh, gamslope; - ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope); - #pragma omp parallel - { - Imagefloat *origCropPart;//init auto noise - origCropPart = new Imagefloat (crW, crH);//allocate memory - Imagefloat *provicalc = new Imagefloat ((crW + 1) / 2, (crH + 1) / 2); //for denoise curves - int skipP = 1; - #pragma omp for schedule(dynamic) collapse(2) nowait + if (params.dirpyrDenoise.enabled) {//evaluate Noise + LUTf gamcurve(65536, 0); + float gam, gamthresh, gamslope; + ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope); +#pragma omp parallel + { + Imagefloat *origCropPart;//init auto noise + origCropPart = new Imagefloat (crW, crH);//allocate memory + Imagefloat *provicalc = new Imagefloat ((crW + 1) / 2, (crH + 1) / 2); //for denoise curves + int skipP = 1; +#pragma omp for schedule(dynamic) collapse(2) nowait - for(int wcr = 0; wcr < numtiles_W; wcr++) { - for(int hcr = 0; hcr < numtiles_H; hcr++) { - int beg_tileW = wcr * tileWskip + tileWskip / 2.f - crW / 2.f; - int beg_tileH = hcr * tileHskip + tileHskip / 2.f - crH / 2.f; - PreviewProps ppP (beg_tileW , beg_tileH, crW, crH, skipP); - imgsrc->getImage (currWB, tr, origCropPart, ppP, params.toneCurve, params.icm, params.raw ); + for(int wcr = 0; wcr < numtiles_W; wcr++) { + for(int hcr = 0; hcr < numtiles_H; hcr++) { + int beg_tileW = wcr * tileWskip + tileWskip / 2.f - crW / 2.f; + int beg_tileH = hcr * tileHskip + tileHskip / 2.f - crH / 2.f; + PreviewProps ppP (beg_tileW , beg_tileH, crW, crH, skipP); + imgsrc->getImage (currWB, tr, origCropPart, ppP, params.toneCurve, params.icm, params.raw ); + //baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve); - // we only need image reduced to 1/4 here - for(int ii = 0; ii < crH; ii += 2) { - for(int jj = 0; jj < crW; jj += 2) { - provicalc->r(ii >> 1, jj >> 1) = origCropPart->r(ii, jj); - provicalc->g(ii >> 1, jj >> 1) = origCropPart->g(ii, jj); - provicalc->b(ii >> 1, jj >> 1) = origCropPart->b(ii, jj); + // we only need image reduced to 1/4 here + for(int ii = 0; ii < crH; ii += 2) { + for(int jj = 0; jj < crW; jj += 2) { + provicalc->r(ii >> 1, jj >> 1) = origCropPart->r(ii, jj); + provicalc->g(ii >> 1, jj >> 1) = origCropPart->g(ii, jj); + provicalc->b(ii >> 1, jj >> 1) = origCropPart->b(ii, jj); + } } - } - imgsrc->convertColorSpace(provicalc, params.icm, currWB);//for denoise luminance curve - float maxr = 0.f; - float maxb = 0.f; - float pondcorrec = 1.0f; - float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc; - int Nb; - chaut = 0.f; - redaut = 0.f; - blueaut = 0.f; - maxredaut = 0.f; - maxblueaut = 0.f; - chromina = 0.f; - sigma = 0.f; - ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc); - float multip = 1.f; - float adjustr = 1.f; + imgsrc->convertColorSpace(provicalc, params.icm, currWB);//for denoise luminance curve + float maxr = 0.f; + float maxb = 0.f; + float pondcorrec = 1.0f; + float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc; + int Nb; + chaut = 0.f; + redaut = 0.f; + blueaut = 0.f; + maxredaut = 0.f; + maxblueaut = 0.f; + chromina = 0.f; + sigma = 0.f; + ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc); + float multip = 1.f; + float adjustr = 1.f; - if (params.icm.working == "ProPhoto") { - adjustr = 1.f; // - } else if (params.icm.working == "Adobe RGB") { - adjustr = 1.f / 1.3f; - } else if (params.icm.working == "sRGB") { - adjustr = 1.f / 1.3f; - } else if (params.icm.working == "WideGamut") { - adjustr = 1.f / 1.1f; - } else if (params.icm.working == "Rec2020") { - adjustr = 1.f / 1.1f; - } else if (params.icm.working == "Beta RGB") { - adjustr = 1.f / 1.2f; - } else if (params.icm.working == "BestRGB") { - adjustr = 1.f / 1.2f; - } else if (params.icm.working == "BruceRGB") { - adjustr = 1.f / 1.2f; - } - - if(!imgsrc->isRAW()) { - multip = 2.f; //take into account gamma for TIF / JPG approximate value...not good fot gamma=1 - } - - float maxmax = max(maxredaut, maxblueaut); - float delta; - int mode = 2; - int lissage = settings->leveldnliss; - ipf.calcautodn_info (chaut, delta, Nb, levaut, maxmax, lumema, chromina, mode, lissage, redyel, skinc, nsknc); - - // printf("PROCESS cha=%f red=%f bl=%f redM=%f bluM=%f chrom=%f sigm=%f lum=%f sigL=%f\n",chaut,redaut,blueaut, maxredaut, maxblueaut, chromina, sigma, lumema, sigma_L); - if(maxredaut > maxblueaut) { - maxr = (delta) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f); - - if(minblueaut <= minredaut && minblueaut < chaut) { - maxb = (-chaut + minblueaut) / (autoNRmax * multip * adjustr * lowdenoise); + if (params.icm.working == "ProPhoto") { + adjustr = 1.f; // + } else if (params.icm.working == "Adobe RGB") { + adjustr = 1.f / 1.3f; + } else if (params.icm.working == "sRGB") { + adjustr = 1.f / 1.3f; + } else if (params.icm.working == "WideGamut") { + adjustr = 1.f / 1.1f; + } else if (params.icm.working == "Rec2020") { + adjustr = 1.f / 1.1f; + } else if (params.icm.working == "Beta RGB") { + adjustr = 1.f / 1.2f; + } else if (params.icm.working == "BestRGB") { + adjustr = 1.f / 1.2f; + } else if (params.icm.working == "BruceRGB") { + adjustr = 1.f / 1.2f; } + + if(!imgsrc->isRAW()) { + multip = 2.f; //take into account gamma for TIF / JPG approximate value...not good fot gamma=1 + } + + float maxmax = max(maxredaut, maxblueaut); + float delta; + int mode = 2; + int lissage = settings->leveldnliss; + ipf.calcautodn_info (chaut, delta, Nb, levaut, maxmax, lumema, chromina, mode, lissage, redyel, skinc, nsknc); + + // printf("PROCESS cha=%f red=%f bl=%f redM=%f bluM=%f chrom=%f sigm=%f lum=%f sigL=%f\n",chaut,redaut,blueaut, maxredaut, maxblueaut, chromina, sigma, lumema, sigma_L); + if(maxredaut > maxblueaut) { + maxr = (delta) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f); + + if(minblueaut <= minredaut && minblueaut < chaut) { + maxb = (-chaut + minblueaut) / (autoNRmax * multip * adjustr * lowdenoise); + } + } else { + maxb = (delta) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f); + + if(minredaut <= minblueaut && minredaut < chaut) { + maxr = (-chaut + minredaut) / (autoNRmax * multip * adjustr * lowdenoise); + } + }//maxb mxr - empirical evaluation red / blue + + ch_M[hcr * numtiles_W + wcr] = pondcorrec * chaut / (autoNR * multip * adjustr * lowdenoise); + max_r[hcr * numtiles_W + wcr] = pondcorrec * maxr; + max_b[hcr * numtiles_W + wcr] = pondcorrec * maxb; + lumL[hcr * numtiles_W + wcr] = lumema; + chromC[hcr * numtiles_W + wcr] = chromina; + ry[hcr * numtiles_W + wcr] = redyel; + sk[hcr * numtiles_W + wcr] = skinc; + pcsk[hcr * numtiles_W + wcr] = nsknc; + + } + } + + delete provicalc; + delete origCropPart; + } + + int liss = settings->leveldnliss; //smooth result around mean + + if(liss == 2 || liss == 3) { + // I smooth only mean and not delta (max) + float nchm = 0.f; + float koef = 0.4f; //between 0.1 to 0.9 + + if(liss == 3) { + koef = 0.0f; //quasi auto for mean Ch + } + + for(int wcr = 0; wcr < numtiles_W; wcr++) { + for(int hcr = 0; hcr < numtiles_H; hcr++) { + nchm += ch_M[hcr * numtiles_W + wcr]; + } + } + + nchm /= (numtiles_H * numtiles_W); + + for(int wcr = 0; wcr < numtiles_W; wcr++) { + for(int hcr = 0; hcr < numtiles_H; hcr++) { + ch_M[hcr * numtiles_W + wcr] = nchm + (ch_M[hcr * numtiles_W + wcr] - nchm) * koef; + } + } + } + + if(liss == 3) { //same as auto but with much cells + float MaxR = 0.f; + float MaxB = 0.f; + float MaxRMoy = 0.f; + float MaxBMoy = 0.f; + + for(int k = 0; k < nbtl; k++) { + MaxBMoy += max_b[k]; + MaxRMoy += max_r[k]; + + if(max_r[k] > MaxR) { + MaxR = max_r[k]; + } + + if(max_b[k] > MaxB) { + MaxB = max_b[k]; + } + + } + + MaxBMoy /= nbtl; + MaxRMoy /= nbtl; + + for(int k = 0; k < nbtl; k++) { + if(MaxR > MaxB) { + max_r[k] = MaxRMoy + (MaxR - MaxRMoy) * 0.66f; //#std Dev + //max_b[k]=MinB; + max_b[k] = MaxBMoy + (MaxB - MaxBMoy) * 0.66f; + } else { - maxb = (delta) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f); + max_b[k] = MaxBMoy + (MaxB - MaxBMoy) * 0.66f; + //max_r[k]=MinR; + max_r[k] = MaxRMoy + (MaxR - MaxRMoy) * 0.66f; - if(minredaut <= minblueaut && minredaut < chaut) { - maxr = (-chaut + minredaut) / (autoNRmax * multip * adjustr * lowdenoise); + } + } + } + + if (settings->verbose) { + t2pone.set(); + printf("Info denoise ponderated performed in %d usec:\n", t2pone.etime(t1pone)); + } + + } + } + + + if((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { + MyTime t1aue, t2aue; + t1aue.set(); + int crW, crH; + + if(settings->leveldnv == 0) { + crW = 100; + crH = 100; + } + + if(settings->leveldnv == 1) { + crW = 250; + crH = 250; + } + + if(settings->leveldnv == 2) { + crW = int(tileWskip / 2); + crH = int(tileHskip / 2); + } + + // if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int(1.15f*(tileWskip/2));}//adapted to scale of preview + if(settings->leveldnv == 3) { + crW = tileWskip - 10; + crH = tileHskip - 10; + } + + float lowdenoise = 1.f; + int levaut = settings->leveldnaut; + + if(levaut == 1) { //Standard + lowdenoise = 0.7f; + } + + if (params.dirpyrDenoise.enabled) {//evaluate Noise + LUTf gamcurve(65536, 0); + float gam, gamthresh, gamslope; + ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope); + int Nb[9]; + int coordW[3];//coordonate of part of image to mesure noise + int coordH[3]; + int begW = 50; + int begH = 50; + coordW[0] = begW; + coordW[1] = fw / 2 - crW / 2; + coordW[2] = fw - crW - begW; + coordH[0] = begH; + coordH[1] = fh / 2 - crH / 2; + coordH[2] = fh - crH - begH; +#pragma omp parallel + { + Imagefloat *origCropPart;//init auto noise + origCropPart = new Imagefloat (crW, crH);//allocate memory + Imagefloat *provicalc = new Imagefloat ((crW + 1) / 2, (crH + 1) / 2); //for denoise curves + +#pragma omp for schedule(dynamic) collapse(2) nowait + + for(int wcr = 0; wcr <= 2; wcr++) { + for(int hcr = 0; hcr <= 2; hcr++) { + PreviewProps ppP (coordW[wcr] , coordH[hcr], crW, crH, 1); + imgsrc->getImage (currWB, tr, origCropPart, ppP, params.toneCurve, params.icm, params.raw); + //baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve); + + + // we only need image reduced to 1/4 here + for(int ii = 0; ii < crH; ii += 2) { + for(int jj = 0; jj < crW; jj += 2) { + provicalc->r(ii >> 1, jj >> 1) = origCropPart->r(ii, jj); + provicalc->g(ii >> 1, jj >> 1) = origCropPart->g(ii, jj); + provicalc->b(ii >> 1, jj >> 1) = origCropPart->b(ii, jj); + } } - }//maxb mxr - empirical evaluation red / blue - - ch_M[hcr * numtiles_W + wcr] = pondcorrec * chaut / (autoNR * multip * adjustr * lowdenoise); - max_r[hcr * numtiles_W + wcr] = pondcorrec * maxr; - max_b[hcr * numtiles_W + wcr] = pondcorrec * maxb; - lumL[hcr * numtiles_W + wcr] = lumema; - chromC[hcr * numtiles_W + wcr] = chromina; - ry[hcr * numtiles_W + wcr] = redyel; - sk[hcr * numtiles_W + wcr] = skinc; - pcsk[hcr * numtiles_W + wcr] = nsknc; + imgsrc->convertColorSpace(provicalc, params.icm, currWB);//for denoise luminance curve + int nb = 0; + float chaut = 0.f, redaut = 0.f, blueaut = 0.f, maxredaut = 0.f, maxblueaut = 0.f, minredaut = 0.f, minblueaut = 0.f, chromina = 0.f, sigma = 0.f, lumema = 0.f, sigma_L = 0.f, redyel = 0.f, skinc = 0.f, nsknc = 0.f; + ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc); + Nb[hcr * 3 + wcr] = nb; + ch_M[hcr * 3 + wcr] = chaut; + max_r[hcr * 3 + wcr] = maxredaut; + max_b[hcr * 3 + wcr] = maxblueaut; + min_r[hcr * 3 + wcr] = minredaut; + min_b[hcr * 3 + wcr] = minblueaut; + lumL[hcr * 3 + wcr] = lumema; + chromC[hcr * 3 + wcr] = chromina; + ry[hcr * 3 + wcr] = redyel; + sk[hcr * 3 + wcr] = skinc; + pcsk[hcr * 3 + wcr] = nsknc; + } } + + delete provicalc; + delete origCropPart; } - - delete provicalc; - delete origCropPart; - } - - int liss = settings->leveldnliss; //smooth result around mean - - if(liss == 2 || liss == 3) { - // I smooth only mean and not delta (max) - float nchm = 0.f; - float koef = 0.4f; //between 0.1 to 0.9 - - if(liss == 3) { - koef = 0.0f; //quasi auto for mean Ch - } - - for(int wcr = 0; wcr < numtiles_W; wcr++) { - for(int hcr = 0; hcr < numtiles_H; hcr++) { - nchm += ch_M[hcr * numtiles_W + wcr]; - } - } - - nchm /= (numtiles_H * numtiles_W); - - for(int wcr = 0; wcr < numtiles_W; wcr++) { - for(int hcr = 0; hcr < numtiles_H; hcr++) { - ch_M[hcr * numtiles_W + wcr] = nchm + (ch_M[hcr * numtiles_W + wcr] - nchm) * koef; - } - } - } - - if(liss == 3) { //same as auto but with much cells + float chM = 0.f; float MaxR = 0.f; float MaxB = 0.f; + float MinR = 100000000.f; + float MinB = 100000000.f; + float maxr = 0.f; + float maxb = 0.f; + float multip = 1.f; + float adjustr = 1.f; + float Max_R[9] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; + float Max_B[9] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; + float Min_R[9]; + float Min_B[9]; float MaxRMoy = 0.f; float MaxBMoy = 0.f; + float MinRMoy = 0.f; + float MinBMoy = 0.f; - for(int k = 0; k < nbtl; k++) { - MaxBMoy += max_b[k]; - MaxRMoy += max_r[k]; - - if(max_r[k] > MaxR) { - MaxR = max_r[k]; - } - - if(max_b[k] > MaxB) { - MaxB = max_b[k]; - } - + if (params.icm.working == "ProPhoto") { + adjustr = 1.f; + } else if (params.icm.working == "Adobe RGB") { + adjustr = 1.f / 1.3f; + } else if (params.icm.working == "sRGB") { + adjustr = 1.f / 1.3f; + } else if (params.icm.working == "WideGamut") { + adjustr = 1.f / 1.1f; + } else if (params.icm.working == "Rec2020") { + adjustr = 1.f / 1.1f; + } else if (params.icm.working == "Beta RGB") { + adjustr = 1.f / 1.2f; + } else if (params.icm.working == "BestRGB") { + adjustr = 1.f / 1.2f; + } else if (params.icm.working == "BruceRGB") { + adjustr = 1.f / 1.2f; } - MaxBMoy /= nbtl; - MaxRMoy /= nbtl; + if(!imgsrc->isRAW()) { + multip = 2.f; //take into account gamma for TIF / JPG approximate value...not good fot gamma=1 + } - for(int k = 0; k < nbtl; k++) { - if(MaxR > MaxB) { - max_r[k] = MaxRMoy + (MaxR - MaxRMoy) * 0.66f; //#std Dev - //max_b[k]=MinB; - max_b[k] = MaxBMoy + (MaxB - MaxBMoy) * 0.66f; + float delta[9]; + int mode = 1; + int lissage = settings->leveldnliss; + for(int k = 0; k < 9; k++) { + float maxmax = max(max_r[k], max_b[k]); + ipf.calcautodn_info (ch_M[k], delta[k], Nb[k], levaut, maxmax, lumL[k], chromC[k], mode, lissage, ry[k], sk[k], pcsk[k] ); + // printf("ch_M=%f delta=%f\n",ch_M[k], delta[k]); + } + + for(int k = 0; k < 9; k++) { + if(max_r[k] > max_b[k]) { + //printf("R delta=%f koef=%f\n",delta[k],autoNRmax*multip*adjustr*lowdenoise); + Max_R[k] = (delta[k]) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f); + Min_B[k] = -(ch_M[k] - min_b[k]) / (autoNRmax * multip * adjustr * lowdenoise); + Max_B[k] = 0.f; + Min_R[k] = 0.f; } else { - max_b[k] = MaxBMoy + (MaxB - MaxBMoy) * 0.66f; - //max_r[k]=MinR; - max_r[k] = MaxRMoy + (MaxR - MaxRMoy) * 0.66f; - - } - } - } - - if (settings->verbose) { - t2pone.set(); - printf("Info denoise ponderated performed in %d usec:\n", t2pone.etime(t1pone)); - } - - } - } - - - if((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { - MyTime t1aue, t2aue; - t1aue.set(); - int crW, crH; - - if(settings->leveldnv == 0) { - crW = 100; - crH = 100; - } - - if(settings->leveldnv == 1) { - crW = 250; - crH = 250; - } - - if(settings->leveldnv == 2) { - crW = int(tileWskip / 2); - crH = int(tileHskip / 2); - } - - // if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int(1.15f*(tileWskip/2));}//adapted to scale of preview - if(settings->leveldnv == 3) { - crW = tileWskip - 10; - crH = tileHskip - 10; - } - - float lowdenoise = 1.f; - int levaut = settings->leveldnaut; - - if(levaut == 1) { //Standard - lowdenoise = 0.7f; - } - - if (params.dirpyrDenoise.enabled) {//evaluate Noise - LUTf gamcurve(65536, 0); - float gam, gamthresh, gamslope; - ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope); - int Nb[9]; - int coordW[3];//coordonate of part of image to mesure noise - int coordH[3]; - int begW = 50; - int begH = 50; - coordW[0] = begW; - coordW[1] = fw / 2 - crW / 2; - coordW[2] = fw - crW - begW; - coordH[0] = begH; - coordH[1] = fh / 2 - crH / 2; - coordH[2] = fh - crH - begH; - #pragma omp parallel - { - Imagefloat *origCropPart;//init auto noise - origCropPart = new Imagefloat (crW, crH);//allocate memory - Imagefloat *provicalc = new Imagefloat ((crW + 1) / 2, (crH + 1) / 2); //for denoise curves - - #pragma omp for schedule(dynamic) collapse(2) nowait - - for(int wcr = 0; wcr <= 2; wcr++) { - for(int hcr = 0; hcr <= 2; hcr++) { - PreviewProps ppP (coordW[wcr] , coordH[hcr], crW, crH, 1); - imgsrc->getImage (currWB, tr, origCropPart, ppP, params.toneCurve, params.icm, params.raw); - - // we only need image reduced to 1/4 here - for(int ii = 0; ii < crH; ii += 2) { - for(int jj = 0; jj < crW; jj += 2) { - provicalc->r(ii >> 1, jj >> 1) = origCropPart->r(ii, jj); - provicalc->g(ii >> 1, jj >> 1) = origCropPart->g(ii, jj); - provicalc->b(ii >> 1, jj >> 1) = origCropPart->b(ii, jj); - } - } - - imgsrc->convertColorSpace(provicalc, params.icm, currWB);//for denoise luminance curve - int nb = 0; - float chaut = 0.f, redaut = 0.f, blueaut = 0.f, maxredaut = 0.f, maxblueaut = 0.f, minredaut = 0.f, minblueaut = 0.f, chromina = 0.f, sigma = 0.f, lumema = 0.f, sigma_L = 0.f, redyel = 0.f, skinc = 0.f, nsknc = 0.f; - ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc); - Nb[hcr * 3 + wcr] = nb; - ch_M[hcr * 3 + wcr] = chaut; - max_r[hcr * 3 + wcr] = maxredaut; - max_b[hcr * 3 + wcr] = maxblueaut; - min_r[hcr * 3 + wcr] = minredaut; - min_b[hcr * 3 + wcr] = minblueaut; - lumL[hcr * 3 + wcr] = lumema; - chromC[hcr * 3 + wcr] = chromina; - ry[hcr * 3 + wcr] = redyel; - sk[hcr * 3 + wcr] = skinc; - pcsk[hcr * 3 + wcr] = nsknc; + //printf("B delta=%f koef=%f\n",delta[k],autoNRmax*multip*adjustr*lowdenoise); + Max_B[k] = (delta[k]) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f); + Min_R[k] = - (ch_M[k] - min_r[k]) / (autoNRmax * multip * adjustr * lowdenoise); + Min_B[k] = 0.f; + Max_R[k] = 0.f; } } - delete provicalc; - delete origCropPart; - } - float chM = 0.f; - float MaxR = 0.f; - float MaxB = 0.f; - float MinR = 100000000.f; - float MinB = 100000000.f; - float maxr = 0.f; - float maxb = 0.f; - float multip = 1.f; - float adjustr = 1.f; - float Max_R[9] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; - float Max_B[9] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; - float Min_R[9]; - float Min_B[9]; - float MaxRMoy = 0.f; - float MaxBMoy = 0.f; - float MinRMoy = 0.f; - float MinBMoy = 0.f; + for(int k = 0; k < 9; k++) { + // printf("ch_M= %f Max_R=%f Max_B=%f min_r=%f min_b=%f\n",ch_M[k],Max_R[k], Max_B[k],Min_R[k], Min_B[k]); + chM += ch_M[k]; + MaxBMoy += Max_B[k]; + MaxRMoy += Max_R[k]; + MinRMoy += Min_R[k]; + MinBMoy += Min_B[k]; - if (params.icm.working == "ProPhoto") { - adjustr = 1.f; - } else if (params.icm.working == "Adobe RGB") { - adjustr = 1.f / 1.3f; - } else if (params.icm.working == "sRGB") { - adjustr = 1.f / 1.3f; - } else if (params.icm.working == "WideGamut") { - adjustr = 1.f / 1.1f; - } else if (params.icm.working == "Rec2020") { - adjustr = 1.f / 1.1f; - } else if (params.icm.working == "Beta RGB") { - adjustr = 1.f / 1.2f; - } else if (params.icm.working == "BestRGB") { - adjustr = 1.f / 1.2f; - } else if (params.icm.working == "BruceRGB") { - adjustr = 1.f / 1.2f; - } + if(Max_R[k] > MaxR) { + MaxR = Max_R[k]; + } - if(!imgsrc->isRAW()) { - multip = 2.f; //take into account gamma for TIF / JPG approximate value...not good fot gamma=1 - } + if(Max_B[k] > MaxB) { + MaxB = Max_B[k]; + } - float delta[9]; - int mode = 1; - int lissage = settings->leveldnliss; + if(Min_R[k] < MinR) { + MinR = Min_R[k]; + } - for(int k = 0; k < 9; k++) { - float maxmax = max(max_r[k], max_b[k]); - ipf.calcautodn_info (ch_M[k], delta[k], Nb[k], levaut, maxmax, lumL[k], chromC[k], mode, lissage, ry[k], sk[k], pcsk[k] ); - // printf("ch_M=%f delta=%f\n",ch_M[k], delta[k]); - } + if(Min_B[k] < MinB) { + MinB = Min_B[k]; + } + + } + + chM /= 9; + MaxBMoy /= 9; + MaxRMoy /= 9; + MinBMoy /= 9; + MinRMoy /= 9; + + if(MaxR > MaxB) { + maxr = MaxRMoy + (MaxR - MaxRMoy) * 0.66f; //#std Dev + // maxb=MinB; + maxb = MinBMoy + (MinB - MinBMoy) * 0.66f; - for(int k = 0; k < 9; k++) { - if(max_r[k] > max_b[k]) { - //printf("R delta=%f koef=%f\n",delta[k],autoNRmax*multip*adjustr*lowdenoise); - Max_R[k] = (delta[k]) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f); - Min_B[k] = -(ch_M[k] - min_b[k]) / (autoNRmax * multip * adjustr * lowdenoise); - Max_B[k] = 0.f; - Min_R[k] = 0.f; } else { - //printf("B delta=%f koef=%f\n",delta[k],autoNRmax*multip*adjustr*lowdenoise); - Max_B[k] = (delta[k]) / ((autoNRmax * multip * adjustr * lowdenoise) / 2.f); - Min_R[k] = - (ch_M[k] - min_r[k]) / (autoNRmax * multip * adjustr * lowdenoise); - Min_B[k] = 0.f; - Max_R[k] = 0.f; + maxb = MaxBMoy + (MaxB - MaxBMoy) * 0.66f; + // maxr=MinR; + maxr = MinRMoy + (MinR - MinRMoy) * 0.66f; + } - } - - for(int k = 0; k < 9; k++) { - // printf("ch_M= %f Max_R=%f Max_B=%f min_r=%f min_b=%f\n",ch_M[k],Max_R[k], Max_B[k],Min_R[k], Min_B[k]); - chM += ch_M[k]; - MaxBMoy += Max_B[k]; - MaxRMoy += Max_R[k]; - MinRMoy += Min_R[k]; - MinBMoy += Min_B[k]; - - if(Max_R[k] > MaxR) { - MaxR = Max_R[k]; - } - - if(Max_B[k] > MaxB) { - MaxB = Max_B[k]; - } - - if(Min_R[k] < MinR) { - MinR = Min_R[k]; - } - - if(Min_B[k] < MinB) { - MinB = Min_B[k]; - } - - } - - chM /= 9; - MaxBMoy /= 9; - MaxRMoy /= 9; - MinBMoy /= 9; - MinRMoy /= 9; - - if(MaxR > MaxB) { - maxr = MaxRMoy + (MaxR - MaxRMoy) * 0.66f; //#std Dev - // maxb=MinB; - maxb = MinBMoy + (MinB - MinBMoy) * 0.66f; - - } else { - maxb = MaxBMoy + (MaxB - MaxBMoy) * 0.66f; - // maxr=MinR; - maxr = MinRMoy + (MinR - MinRMoy) * 0.66f; - - } // printf("SIMPL cha=%f red=%f bl=%f \n",chM,maxr,maxb); - params.dirpyrDenoise.chroma = chM / (autoNR * multip * adjustr); - params.dirpyrDenoise.redchro = maxr; - params.dirpyrDenoise.bluechro = maxb; + params.dirpyrDenoise.chroma = chM / (autoNR * multip * adjustr); + params.dirpyrDenoise.redchro = maxr; + params.dirpyrDenoise.bluechro = maxb; + } + + if (settings->verbose) { + t2aue.set(); + printf("Info denoise auto performed in %d usec:\n", t2aue.etime(t1aue)); + } + + //end evaluate noise } - if (settings->verbose) { - t2aue.set(); - printf("Info denoise auto performed in %d usec:\n", t2aue.etime(t1aue)); + // return true; + } + + void stage_2() + { + ProcessingJobImpl* job = static_cast(pjob); + procparams::ProcParams& params = job->pparams; + ImProcFunctions ipf (¶ms, true); + + baseImg = new Imagefloat (fw, fh); + imgsrc->getImage (currWB, tr, baseImg, pp, params.toneCurve, params.icm, params.raw); + + if (pl) { + pl->setProgress (0.50); } - //end evaluate noise - } - - - - - - Imagefloat* baseImg = new Imagefloat (fw, fh); - imgsrc->getImage (currWB, tr, baseImg, pp, params.toneCurve, params.icm, params.raw); - - if (pl) { - pl->setProgress (0.50); - } - // LUTf Noisecurve (65536,0); //!!!// auto exposure!!! - double expcomp = params.toneCurve.expcomp; - int bright = params.toneCurve.brightness; - int contr = params.toneCurve.contrast; - int black = params.toneCurve.black; - int hlcompr = params.toneCurve.hlcompr; - int hlcomprthresh = params.toneCurve.hlcomprthresh; + expcomp = params.toneCurve.expcomp; + bright = params.toneCurve.brightness; + contr = params.toneCurve.contrast; + black = params.toneCurve.black; + hlcompr = params.toneCurve.hlcompr; + hlcomprthresh = params.toneCurve.hlcomprthresh; - if (params.toneCurve.autoexp) { - LUTu aehist; - int aehistcompr; - imgsrc->getAutoExpHistogram (aehist, aehistcompr); - ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, expcomp, bright, contr, black, hlcompr, hlcomprthresh); + + if (params.toneCurve.autoexp) { + LUTu aehist; + int aehistcompr; + imgsrc->getAutoExpHistogram (aehist, aehistcompr); + ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, expcomp, bright, contr, black, hlcompr, hlcomprthresh); + } + + // at this stage, we can flush the raw data to free up quite an important amount of memory + // commented out because it makes the application crash when batch processing... + // TODO: find a better place to flush rawData and rawRGB + if(flush) { + imgsrc->flushRawData(); + imgsrc->flushRGB(); + } } - // at this stage, we can flush the raw data to free up quite an important amount of memory - // commented out because it makes the application crash when batch processing... - // TODO: find a better place to flush rawData and rawRGB - if(flush) { - imgsrc->flushRawData(); - imgsrc->flushRGB(); - } - - // perform luma/chroma denoise + void stage_3() + { + ProcessingJobImpl* job = static_cast(pjob); + procparams::ProcParams& params = job->pparams; + ImProcFunctions ipf (¶ms, true); + + // perform luma/chroma denoise // CieImage *cieView; // NoisCurve noiseLCurve; // bool lldenoiseutili=false; @@ -677,604 +765,776 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // params.dirpyrDenoise.getCurves(noiseLCurve, lldenoiseutili); // if (params.dirpyrDenoise.enabled && lldenoiseutili) { - DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; // make a copy because we cheat here + DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; // make a copy because we cheat here - if(denoiseParams.Lmethod == "CUR") { - if(noiseLCurve) { - denoiseParams.luma = 0.5f; - } else { - denoiseParams.luma = 0.0f; + if(denoiseParams.Lmethod == "CUR") { + if(noiseLCurve) { + denoiseParams.luma = 0.5f; + } else { + denoiseParams.luma = 0.0f; + } + } else if(denoiseParams.Lmethod == "SLI") { + noiseLCurve.Reset(); } - } else if(denoiseParams.Lmethod == "SLI") { - noiseLCurve.Reset(); + + if (denoiseParams.enabled && (noiseLCurve || noiseCCurve )) { + // we only need image reduced to 1/4 here + calclum = new Imagefloat ((fw + 1) / 2, (fh + 1) / 2); //for luminance denoise curve +#pragma omp parallel for + + for(int ii = 0; ii < fh; ii += 2) { + for(int jj = 0; jj < fw; jj += 2) { + calclum->r(ii >> 1, jj >> 1) = baseImg->r(ii, jj); + calclum->g(ii >> 1, jj >> 1) = baseImg->g(ii, jj); + calclum->b(ii >> 1, jj >> 1) = baseImg->b(ii, jj); + } + } + + imgsrc->convertColorSpace(calclum, params.icm, currWB); + } + + if (denoiseParams.enabled) { + // CurveFactory::denoiseLL(lldenoiseutili, denoiseParams.lcurve, Noisecurve,1); + //denoiseParams.getCurves(noiseLCurve); +// ipf.RGB_denoise(baseImg, baseImg, calclum, imgsrc->isRAW(), denoiseParams, params.defringe, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, lldenoiseutili); + float chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi; + int kall = 2; + ipf.RGB_denoise(kall, baseImg, baseImg, calclum, ch_M, max_r, max_b, imgsrc->isRAW(), denoiseParams, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi); + + } + +// delete calclum; + delete [] ch_M; + delete [] max_r; + delete [] max_b; + delete [] min_r; + delete [] min_b; + delete [] lumL; + delete [] chromC; + delete [] ry; + delete [] sk; + delete [] pcsk; + + // imgsrc->convertColorSpace(baseImg, params.icm, currWB); + + // // perform first analysis + // hist16 (65536); + + // ipf.firstAnalysis (baseImg, params, hist16); } - if (denoiseParams.enabled && (noiseLCurve || noiseCCurve )) { - // we only need image reduced to 1/4 here - calclum = new Imagefloat ((fw + 1) / 2, (fh + 1) / 2); //for luminance denoise curve - #pragma omp parallel for - for(int ii = 0; ii < fh; ii += 2) { - for(int jj = 0; jj < fw; jj += 2) { - calclum->r(ii >> 1, jj >> 1) = baseImg->r(ii, jj); - calclum->g(ii >> 1, jj >> 1) = baseImg->g(ii, jj); - calclum->b(ii >> 1, jj >> 1) = baseImg->b(ii, jj); + void stage_4() + { + ProcessingJobImpl* job = static_cast(pjob); + procparams::ProcParams& params = job->pparams; + ImProcFunctions ipf (¶ms, true); + + imgsrc->convertColorSpace(baseImg, params.icm, currWB); + + // perform first analysis + hist16 (65536); + + ipf.firstAnalysis (baseImg, params, hist16); + + // perform transform (excepted resizing) + if (ipf.needsTransform()) { + Imagefloat* trImg = new Imagefloat (fw, fh); + ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, fw, fh, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(), + imgsrc->getMetaData()->getFocusDist(), imgsrc->getRotateDegree(), true); + delete baseImg; + baseImg = trImg; + } + } + + void stage_5() + { + ProcessingJobImpl* job = static_cast(pjob); + procparams::ProcParams& params = job->pparams; + ImProcFunctions ipf (¶ms, true); + + if (params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) { + const int W = baseImg->getWidth(); + const int H = baseImg->getHeight(); + LabImage labcbdl(W, H); + ipf.rgb2lab(*baseImg, labcbdl, params.icm.working); + ipf.dirpyrequalizer (&labcbdl, 1); + ipf.lab2rgb(labcbdl, *baseImg, params.icm.working); + } + + // update blurmap + SHMap* shmap = nullptr; + + if (params.sh.enabled) { + shmap = new SHMap (fw, fh, true); + double radius = sqrt (double(fw * fw + fh * fh)) / 2.0; + double shradius = params.sh.radius; + + if (!params.sh.hq) { + shradius *= radius / 1800.0; + } + + shmap->update (baseImg, shradius, ipf.lumimul, params.sh.hq, 1); + } + + // RGB processing + + curve1(65536); + curve2(65536); + curve(65536, 0); + satcurve(65536, 0); + lhskcurve(65536, 0); + lumacurve(32770, 0); // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation + clcurve(65536, 0); + wavclCurve(65536, 0); + + //if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; + + CurveFactory::complexCurve (expcomp, black / 65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, + params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, + hist16, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2 ); + + CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, 1); + CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, 1); + CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, 1); + + bool opautili = false; + + if(params.colorToning.enabled) { + TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + double wp[3][3] = { + {wprof[0][0], wprof[0][1], wprof[0][2]}, + {wprof[1][0], wprof[1][1], wprof[1][2]}, + {wprof[2][0], wprof[2][1], wprof[2][2]} + }; + TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); + double wip[3][3] = { + {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, + {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, + {wiprof[2][0], wiprof[2][1], wiprof[2][2]} + }; + params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, wip, opautili); + clToningcurve (65536, 0); + CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, 1); + cl2Toningcurve (65536, 0); + CurveFactory::curveToning(params.colorToning.cl2curve, cl2Toningcurve, 1); + } + + labView = new LabImage (fw, fh); + + if(params.blackwhite.enabled) { + CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 1); + } + + double rrm, ggm, bbm; + float autor, autog, autob; + float satLimit = float(params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; + float satLimitOpacity = 1.f - (float(params.colorToning.saturatedOpacity) / 100.f); + + if(params.colorToning.enabled && params.colorToning.autosat) { //for colortoning evaluation of saturation settings + float moyS = 0.f; + float eqty = 0.f; + ipf.moyeqt (baseImg, moyS, eqty);//return image : mean saturation and standard dev of saturation + float satp = ((moyS + 1.5f * eqty) - 0.3f) / 0.7f; //1.5 sigma ==> 93% pixels with high saturation -0.3 / 0.7 convert to Hombre scale + + if(satp >= 0.92f) { + satp = 0.92f; //avoid values too high (out of gamut) + } + + if(satp <= 0.15f) { + satp = 0.15f; //avoid too low values + } + + satLimit = 100.f * satp; + + satLimitOpacity = 100.f * (moyS - 0.85f * eqty); //-0.85 sigma==>20% pixels with low saturation + } + + autor = -9000.f; // This will ask to compute the "auto" values for the B&W tool (have to be inferior to -5000) + DCPProfile::ApplyState as; + DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB, as); + + LUTu histToneCurve; + + ipf.rgbProc (baseImg, labView, nullptr, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as, histToneCurve); + + if (settings->verbose) { + printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob); + } + + // if clut was used and size of clut cache == 1 we free the memory used by the clutstore (default clut cache size = 1 for 32 bit OS) + if ( params.filmSimulation.enabled && !params.filmSimulation.clutFilename.empty() && options.clutCacheSize == 1) { + CLUTStore::getInstance().clearCache(); + } + + // freeing up some memory + customToneCurve1.Reset(); + customToneCurve2.Reset(); + ctColorCurve.Reset(); + ctOpacityCurve.Reset(); + noiseLCurve.Reset(); + noiseCCurve.Reset(); + customToneCurvebw1.Reset(); + customToneCurvebw2.Reset(); + + // Freeing baseImg because not used anymore + delete baseImg; + baseImg = nullptr; + + if (shmap) { + delete shmap; + } + + shmap = nullptr; + + if (pl) { + pl->setProgress (0.55); + } + } + + void stage_6() + { + ProcessingJobImpl* job = static_cast(pjob); + procparams::ProcParams& params = job->pparams; + ImProcFunctions ipf (¶ms, true); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // start tile processing...??? + + + if(params.labCurve.contrast != 0) { //only use hist16 for contrast + hist16.clear(); + +#ifdef _OPENMP +#pragma omp parallel +#endif + { + LUTu hist16thr (hist16.getSize()); // one temporary lookup table per thread + hist16thr.clear(); +#ifdef _OPENMP +#pragma omp for schedule(static) nowait +#endif + + for (int i = 0; i < fh; i++) + for (int j = 0; j < fw; j++) { + hist16thr[(int)((labView->L[i][j]))]++; + } + +#pragma omp critical + { + hist16 += hist16thr; + } } } - imgsrc->convertColorSpace(calclum, params.icm, currWB); - } + bool utili; + CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, hist16, lumacurve, dummy, 1, utili); - if (denoiseParams.enabled) { - // CurveFactory::denoiseLL(lldenoiseutili, denoiseParams.lcurve, Noisecurve,1); - //denoiseParams.getCurves(noiseLCurve); -// ipf.RGB_denoise(baseImg, baseImg, calclum, imgsrc->isRAW(), denoiseParams, params.defringe, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, lldenoiseutili); - float chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi; - int kall = 2; - ipf.RGB_denoise(kall, baseImg, baseImg, calclum, ch_M, max_r, max_b, imgsrc->isRAW(), denoiseParams, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi); + bool clcutili; + CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, 1); - } + bool ccutili, cclutili; + CurveFactory::complexsgnCurve (autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, + params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, 1); -// delete calclum; - delete [] ch_M; - delete [] max_r; - delete [] max_b; - delete [] min_r; - delete [] min_b; - delete [] lumL; - delete [] chromC; - delete [] ry; - delete [] sk; - delete [] pcsk; + ipf.chromiLuminanceCurve (nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); - imgsrc->convertColorSpace(baseImg, params.icm, currWB); - - // perform first analysis - LUTu hist16 (65536); - - ipf.firstAnalysis (baseImg, params, hist16); - - // perform transform (excepted resizing) - if (ipf.needsTransform()) { - Imagefloat* trImg = new Imagefloat (fw, fh); - ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, fw, fh, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(), - imgsrc->getMetaData()->getFocusDist(), imgsrc->getRotateDegree(), true); - delete baseImg; - baseImg = trImg; - } - - - if (params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) { - const int W = baseImg->getWidth(); - const int H = baseImg->getHeight(); - LabImage labcbdl(W, H); - ipf.rgb2lab(*baseImg, labcbdl, params.icm.working); - ipf.dirpyrequalizer (&labcbdl, 1); - ipf.lab2rgb(labcbdl, *baseImg, params.icm.working); - } - - // update blurmap - SHMap* shmap = nullptr; - - if (params.sh.enabled) { - shmap = new SHMap (fw, fh, true); - double radius = sqrt (double(fw * fw + fh * fh)) / 2.0; - double shradius = params.sh.radius; - - if (!params.sh.hq) { - shradius *= radius / 1800.0; + if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { + ipf.EPDToneMap(labView, 5, 1); } - shmap->update (baseImg, shradius, ipf.lumimul, params.sh.hq, 1); + + ipf.vibrance(labView); + + if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) { + ipf.impulsedenoise (labView); + } + + // for all treatments Defringe, Sharpening, Contrast detail ,Microcontrast they are activated if "CIECAM" function are disabled + + if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) { + ipf.defringe (labView); + } + + if (params.sharpenEdge.enabled) { + ipf.MLsharpen(labView); + } + + if (params.sharpenMicro.enabled) { + if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) { + ipf.MLmicrocontrast (labView); //!params.colorappearance.sharpcie + } + } + + if(((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) { + + float **buffer = new float*[fh]; + + for (int i = 0; i < fh; i++) { + buffer[i] = new float[fw]; + } + + ipf.sharpening (labView, (float**)buffer, params.sharpening); + + for (int i = 0; i < fh; i++) { + delete [] buffer[i]; + } + + delete [] buffer; + } + + WaveletParams WaveParams = params.wavelet; + WavCurve wavCLVCurve; + WavOpacityCurveRG waOpacityCurveRG; + WavOpacityCurveBY waOpacityCurveBY; + WavOpacityCurveW waOpacityCurveW; + WavOpacityCurveWL waOpacityCurveWL; + + params.wavelet.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL ); + + + // directional pyramid wavelet + if(params.dirpyrequalizer.cbdlMethod == "aft") { + if((params.colorappearance.enabled && !settings->autocielab) || !params.colorappearance.enabled) { + ipf.dirpyrequalizer (labView, 1); //TODO: this is the luminance tonecurve, not the RGB one + } + } + + bool wavcontlutili = false; + + CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve,/* hist16C, dummy,*/ 1); + + if(params.wavelet.enabled) { + ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, wavcontlutili, 1); + } + + wavCLVCurve.Reset(); + + //Colorappearance and tone-mapping associated + + int f_w = 1, f_h = 1; + int begh = 0, endh = fh; + + if(params.colorappearance.tonecie || params.colorappearance.enabled) { + f_w = fw; + f_h = fh; + } + + CieImage *cieView = new CieImage (f_w, (f_h)); + begh = 0; + endh = fh; + CurveFactory::curveLightBrightColor ( + params.colorappearance.curve, + params.colorappearance.curve2, + params.colorappearance.curve3, + hist16, dummy, + dummy, dummy, + customColCurve1, + customColCurve2, + customColCurve3, + 1); + + if(params.colorappearance.enabled) { + double adap; + float fnum = imgsrc->getMetaData()->getFNumber ();// F number + float fiso = imgsrc->getMetaData()->getISOSpeed () ;// ISO + float fspeed = imgsrc->getMetaData()->getShutterSpeed () ;//speed + float fcomp = imgsrc->getMetaData()->getExpComp ();//compensation + - + + if(fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { + adap = 2000.; + }//if no exif data or wrong + else { + float E_V = fcomp + log2 ((fnum * fnum) / fspeed / (fiso / 100.f)); + E_V += params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV + E_V += log2(params.raw.expos);// exposure raw white point ; log2 ==> linear to EV + adap = powf(2.f, E_V - 3.f); //cd / m2 + } + + LUTf CAMBrightCurveJ; + LUTf CAMBrightCurveQ; + float CAMMean = NAN; + + if (params.sharpening.enabled) { + if(settings->ciecamfloat) { + float d; + ipf.ciecam_02float (cieView, float(adap), begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, 1, 1); + } else { + double dd; + ipf.ciecam_02 (cieView, adap, begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, dd, 1, 1); + } + } else { + if(settings->ciecamfloat) { + float d; + ipf.ciecam_02float (cieView, float(adap), begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, 1, 1); + } else { + double dd; + ipf.ciecam_02 (cieView, adap, begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, dd, 1, 1); + } + } + } + + delete cieView; + cieView = nullptr; + + + + + // end tile processing...??? + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + if (pl) { + pl->setProgress (0.60); + } } - // RGB processing + Image16 *stage_7() + { + ProcessingJobImpl* job = static_cast(pjob); + procparams::ProcParams& params = job->pparams; + ImProcFunctions ipf (¶ms, true); + + int imw, imh; + double tmpScale = ipf.resizeScale(¶ms, fw, fh, imw, imh); + bool labResize = params.resize.enabled && params.resize.method != "Nearest" && tmpScale != 1.0; + LabImage *tmplab; - LUTf curve1 (65536); - LUTf curve2 (65536); - LUTf curve (65536, 0); - LUTf satcurve (65536, 0); - LUTf lhskcurve (65536, 0); - LUTf lumacurve(32770, 0); // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation - LUTf clcurve (65536, 0); + // crop and convert to rgb16 + int cx = 0, cy = 0, cw = labView->W, ch = labView->H; + + if (params.crop.enabled) { + cx = params.crop.x; + cy = params.crop.y; + cw = params.crop.w; + ch = params.crop.h; + + if(labResize) { // crop lab data + tmplab = new LabImage(cw, ch); + + for(int row = 0; row < ch; row++) { + for(int col = 0; col < cw; col++) { + tmplab->L[row][col] = labView->L[row + cy][col + cx]; + tmplab->a[row][col] = labView->a[row + cy][col + cx]; + tmplab->b[row][col] = labView->b[row + cy][col + cx]; + } + } + + delete labView; + labView = tmplab; + cx = 0; + cy = 0; + } + } + + if (labResize) { // resize lab data + // resize image + tmplab = new LabImage(imw, imh); + ipf.Lanczos (labView, tmplab, tmpScale); + delete labView; + labView = tmplab; + cw = labView->W; + ch = labView->H; + + if(params.prsharpening.enabled) { + for(int i = 0; i < ch; i++) + for(int j = 0; j < cw; j++) { + labView->L[i][j] = labView->L[i][j] < 0.f ? 0.f : labView->L[i][j]; + } + + float **buffer = new float*[ch]; + + for (int i = 0; i < ch; i++) { + buffer[i] = new float[cw]; + } + + ipf.sharpening (labView, (float**)buffer, params.prsharpening); + + for (int i = 0; i < ch; i++) { + delete [] buffer[i]; + } + + delete [] buffer; + } + } + + Image16* readyImg = nullptr; + cmsHPROFILE jprof = nullptr; + bool customGamma = false; + bool useLCMS = false; + bool bwonly = params.blackwhite.enabled && !params.colorToning.enabled && !autili && !butili ; + + if(params.icm.gamma != "default" || params.icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 + + GammaValues ga; + // if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; + readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly, &ga); + customGamma = true; + + //or selected Free gamma + useLCMS = false; + + if ((jprof = iccStore->createCustomGammaOutputProfile (params.icm, ga)) == nullptr) { + useLCMS = true; + } + + } else { + // if Default gamma mode: we use the profile selected in the "Output profile" combobox; + // gamma come from the selected profile, otherwise it comes from "Free gamma" tool + + readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly); + + if (settings->verbose) { + printf("Output profile_: \"%s\"\n", params.icm.output.c_str()); + } + } + + delete labView; + labView = nullptr; + + + + if(bwonly) { //force BW r=g=b + if (settings->verbose) { + printf("Force BW\n"); + } + + for (int ccw = 0; ccw < cw; ccw++) { + for (int cch = 0; cch < ch; cch++) { + readyImg->r(cch, ccw) = readyImg->g(cch, ccw); + readyImg->b(cch, ccw) = readyImg->g(cch, ccw); + } + } + } + + if (pl) { + pl->setProgress (0.70); + } + + if (tmpScale != 1.0 && params.resize.method == "Nearest") { // resize rgb data (gamma applied) + Image16* tempImage = new Image16 (imw, imh); + ipf.resize (readyImg, tempImage, tmpScale); + delete readyImg; + readyImg = tempImage; + } + + if (tunnelMetaData) { + readyImg->setMetadata (ii->getMetaData()->getExifData ()); + } else { + readyImg->setMetadata (ii->getMetaData()->getExifData (), params.exif, params.iptc); + } + + + // Setting the output curve to readyImg + if (customGamma) { + if (!useLCMS) { + // use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16 w/ gamma + ProfileContent pc(jprof); + readyImg->setOutputProfile (pc.data, pc.length); + } + } else { + // use the selected output profile if present, otherwise use LCMS2 profile generate by lab2rgb16 w/ gamma + + if (params.icm.output != "" && params.icm.output != ColorManagementParams::NoICMString) { + + // if iccStore->getProfile send back an object, then iccStore->getContent will do too + cmsHPROFILE jprof = iccStore->getProfile(params.icm.output); //get outProfile + + if (jprof == nullptr) { + if (settings->verbose) { + printf("\"%s\" ICC output profile not found!\n - use LCMS2 substitution\n", params.icm.output.c_str()); + } + } else { + if (settings->verbose) { + printf("Using \"%s\" output profile\n", params.icm.output.c_str()); + } + + ProfileContent pc = iccStore->getContent (params.icm.output); + readyImg->setOutputProfile (pc.data, pc.length); + } + } else { + // No ICM + readyImg->setOutputProfile (nullptr, 0); + } + } + +// t2.set(); +// if( settings->verbose ) +// printf("Total:- %d usec\n", t2.etime(t1)); + + if (!job->initialImage) { + ii->decreaseRef (); + } + + delete job; + + if (pl) { + pl->setProgress (0.75); + } + + /* curve1.reset();curve2.reset(); + curve.reset(); + satcurve.reset(); + lhskcurve.reset(); + + rCurve.reset(); + gCurve.reset(); + bCurve.reset(); + hist16.reset(); + hist16C.reset(); + */ + return readyImg; + } + + void stage_early_resize() + { + ProcessingJobImpl* job = static_cast(pjob); + procparams::ProcParams& params = job->pparams; + ImProcFunctions ipf (¶ms, true); + + int imw, imh; + double tmpScale = ipf.resizeScale(¶ms, fw, fh, imw, imh); + // bool resize = params.resize.enabled; + + LabImage *tmplab = new LabImage(fw, fh); + ipf.rgb2lab(*baseImg, *tmplab, params.icm.working); + + // crop and convert to rgb16 + int cx = 0, cy = 0, cw = fw, ch = fh; + + if (params.crop.enabled) { + cx = params.crop.x; + cy = params.crop.y; + cw = params.crop.w; + ch = params.crop.h; + + LabImage *cropped = new LabImage(cw, ch); + + for(int row = 0; row < ch; row++) { + for(int col = 0; col < cw; col++) { + cropped->L[row][col] = tmplab->L[row + cy][col + cx]; + cropped->a[row][col] = tmplab->a[row + cy][col + cx]; + cropped->b[row][col] = tmplab->b[row + cy][col + cx]; + } + } + + delete tmplab; + tmplab = cropped; + cx = 0; + cy = 0; + + params.crop.enabled = false; + } + + if (params.resize.enabled) { + // resize image + LabImage *resized = new LabImage(imw, imh); + ipf.Lanczos(tmplab, resized, tmpScale); + delete tmplab; + tmplab = resized; + params.resize.enabled = false; + + if (params.prsharpening.enabled) { + params.sharpening = params.prsharpening; + } + + params.wavelet.strength = + int(float(params.wavelet.strength) * tmpScale); + params.dirpyrDenoise.luma *= tmpScale; + // params.dirpyrDenoise.smethod = "shal"; + + fw = imw; + fh = imh; + } + + delete baseImg; + baseImg = new Imagefloat(fw, fh); + ipf.lab2rgb(*tmplab, *baseImg, params.icm.working); + delete tmplab; + } + +private: + ProcessingJob* pjob; + int& errorCode; + ProgressListener* pl; + bool tunnelMetaData; + bool flush; + + // internal state + InitialImage *ii; + ImageSource *imgsrc; + int fw; + int fh; + + int tr; + PreviewProps pp; + + NoiseCurve noiseLCurve; + NoiseCurve noiseCCurve; + Imagefloat *calclum; + float autoNR; + float autoNRmax; + int tilesize; + int overlap; + + float *ch_M; + float *max_r; + float *max_b; + float *min_b; + float *min_r; + float *lumL; + float *chromC; + float *ry; + float *sk; + float *pcsk; + + double expcomp; + int bright; + int contr; + int black; + int hlcompr; + int hlcomprthresh; + + ColorTemp currWB; + Imagefloat *baseImg; + LabImage* labView; + + LUTu hist16; + + LUTf curve1; + LUTf curve2; + LUTf curve; + LUTf satcurve; + LUTf lhskcurve; + LUTf lumacurve; + LUTf clcurve; LUTf clToningcurve; LUTf cl2Toningcurve; - LUTf wavclCurve (65536, 0); + LUTf wavclCurve; LUTf rCurve; LUTf gCurve; LUTf bCurve; LUTu dummy; - + ToneCurve customToneCurve1, customToneCurve2; ColorGradientCurve ctColorCurve; OpacityCurve ctOpacityCurve; ColorAppearance customColCurve1, customColCurve2, customColCurve3 ; ToneCurve customToneCurvebw1; ToneCurve customToneCurvebw2; - //if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; - CurveFactory::complexCurve (expcomp, black / 65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, - params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, - hist16, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2 ); + bool autili, butili; +}; - CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, 1); - CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, 1); - CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, 1); +} // namespace - bool opautili = false; - if(params.colorToning.enabled) { - TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); - double wp[3][3] = { - {wprof[0][0], wprof[0][1], wprof[0][2]}, - {wprof[1][0], wprof[1][1], wprof[1][2]}, - {wprof[2][0], wprof[2][1], wprof[2][2]} - }; - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); - double wip[3][3] = { - {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, - {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, - {wiprof[2][0], wiprof[2][1], wiprof[2][2]} - }; - params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, wip, opautili); - clToningcurve (65536, 0); - CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, 1); - cl2Toningcurve (65536, 0); - CurveFactory::curveToning(params.colorToning.cl2curve, cl2Toningcurve, 1); - } - - LabImage* labView = new LabImage (fw, fh); - - if(params.blackwhite.enabled) { - CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 1); - } - - double rrm, ggm, bbm; - float autor, autog, autob; - float satLimit = float(params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; - float satLimitOpacity = 1.f - (float(params.colorToning.saturatedOpacity) / 100.f); - - if(params.colorToning.enabled && params.colorToning.autosat) { //for colortoning evaluation of saturation settings - float moyS = 0.f; - float eqty = 0.f; - ipf.moyeqt (baseImg, moyS, eqty);//return image : mean saturation and standard dev of saturation - float satp = ((moyS + 1.5f * eqty) - 0.3f) / 0.7f; //1.5 sigma ==> 93% pixels with high saturation -0.3 / 0.7 convert to Hombre scale - - if(satp >= 0.92f) { - satp = 0.92f; //avoid values too high (out of gamut) - } - - if(satp <= 0.15f) { - satp = 0.15f; //avoid too low values - } - - satLimit = 100.f * satp; - - satLimitOpacity = 100.f * (moyS - 0.85f * eqty); //-0.85 sigma==>20% pixels with low saturation - } - - autor = -9000.f; // This will ask to compute the "auto" values for the B&W tool (have to be inferior to -5000) - DCPProfile::ApplyState as; - DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB, as); - - LUTu histToneCurve; - - ipf.rgbProc (baseImg, labView, nullptr, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as, histToneCurve); - - if (settings->verbose) { - printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob); - } - - // if clut was used and size of clut cache == 1 we free the memory used by the clutstore (default clut cache size = 1 for 32 bit OS) - if ( params.filmSimulation.enabled && !params.filmSimulation.clutFilename.empty() && options.clutCacheSize == 1) { - CLUTStore::getInstance().clearCache(); - } - - // freeing up some memory - customToneCurve1.Reset(); - customToneCurve2.Reset(); - ctColorCurve.Reset(); - ctOpacityCurve.Reset(); - noiseLCurve.Reset(); - noiseCCurve.Reset(); - customToneCurvebw1.Reset(); - customToneCurvebw2.Reset(); - - // Freeing baseImg because not used anymore - delete baseImg; - baseImg = nullptr; - - if (shmap) { - delete shmap; - } - - shmap = nullptr; - - if (pl) { - pl->setProgress (0.55); - } - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // start tile processing...??? - - - if(params.labCurve.contrast != 0) { //only use hist16 for contrast - hist16.clear(); - -#ifdef _OPENMP - #pragma omp parallel -#endif - { - LUTu hist16thr (hist16.getSize()); // one temporary lookup table per thread - hist16thr.clear(); -#ifdef _OPENMP - #pragma omp for schedule(static) nowait -#endif - - for (int i = 0; i < fh; i++) - for (int j = 0; j < fw; j++) { - hist16thr[(int)((labView->L[i][j]))]++; - } - - #pragma omp critical - { - hist16 += hist16thr; - } - } - } - - bool utili; - CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, hist16, lumacurve, dummy, 1, utili); - - bool clcutili; - CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, 1); - - bool autili, butili, ccutili, cclutili; - CurveFactory::complexsgnCurve (autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, - params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, 1); - - ipf.chromiLuminanceCurve (nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); - - if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { - ipf.EPDToneMap(labView, 5, 1); - } - - - ipf.vibrance(labView); - - if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) { - ipf.impulsedenoise (labView); - } - - // for all treatments Defringe, Sharpening, Contrast detail ,Microcontrast they are activated if "CIECAM" function are disabled - - if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) { - ipf.defringe (labView); - } - - if (params.sharpenEdge.enabled) { - ipf.MLsharpen(labView); - } - - if (params.sharpenMicro.enabled) { - if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) { - ipf.MLmicrocontrast (labView); //!params.colorappearance.sharpcie - } - } - - if(((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) { - - float **buffer = new float*[fh]; - - for (int i = 0; i < fh; i++) { - buffer[i] = new float[fw]; - } - - ipf.sharpening (labView, (float**)buffer, params.sharpening); - - for (int i = 0; i < fh; i++) { - delete [] buffer[i]; - } - - delete [] buffer; - } - - WaveletParams WaveParams = params.wavelet; - WavCurve wavCLVCurve; - WavOpacityCurveRG waOpacityCurveRG; - WavOpacityCurveBY waOpacityCurveBY; - WavOpacityCurveW waOpacityCurveW; - WavOpacityCurveWL waOpacityCurveWL; - - params.wavelet.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL ); - - - // directional pyramid wavelet - if(params.dirpyrequalizer.cbdlMethod == "aft") { - if((params.colorappearance.enabled && !settings->autocielab) || !params.colorappearance.enabled) { - ipf.dirpyrequalizer (labView, 1); //TODO: this is the luminance tonecurve, not the RGB one - } - } - - bool wavcontlutili = false; - - CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve,/* hist16C, dummy,*/ 1); - - if(params.wavelet.enabled) { - ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, wavcontlutili, 1); - } - - wavCLVCurve.Reset(); - - //Colorappearance and tone-mapping associated - - int f_w = 1, f_h = 1; - int begh = 0, endh = fh; - - if(params.colorappearance.tonecie || params.colorappearance.enabled) { - f_w = fw; - f_h = fh; - } - - CieImage *cieView = new CieImage (f_w, (f_h)); - begh = 0; - endh = fh; - CurveFactory::curveLightBrightColor ( - params.colorappearance.curve, - params.colorappearance.curve2, - params.colorappearance.curve3, - hist16, dummy, - dummy, dummy, - customColCurve1, - customColCurve2, - customColCurve3, - 1); - - if(params.colorappearance.enabled) { - double adap; - float fnum = imgsrc->getMetaData()->getFNumber ();// F number - float fiso = imgsrc->getMetaData()->getISOSpeed () ;// ISO - float fspeed = imgsrc->getMetaData()->getShutterSpeed () ;//speed - float fcomp = imgsrc->getMetaData()->getExpComp ();//compensation + - - - if(fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f) { - adap = 2000.; - }//if no exif data or wrong - else { - float E_V = fcomp + log2 ((fnum * fnum) / fspeed / (fiso / 100.f)); - E_V += params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV - E_V += log2(params.raw.expos);// exposure raw white point ; log2 ==> linear to EV - adap = powf(2.f, E_V - 3.f); //cd / m2 - } - - LUTf CAMBrightCurveJ; - LUTf CAMBrightCurveQ; - float CAMMean = NAN; - - if (params.sharpening.enabled) { - if(settings->ciecamfloat) { - float d; - ipf.ciecam_02float (cieView, float(adap), begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, 1, 1); - } else { - double dd; - ipf.ciecam_02 (cieView, adap, begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, dd, 1, 1); - } - } else { - if(settings->ciecamfloat) { - float d; - ipf.ciecam_02float (cieView, float(adap), begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, 1, 1); - } else { - double dd; - ipf.ciecam_02 (cieView, adap, begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, dd, 1, 1); - } - } - } - - delete cieView; - cieView = nullptr; - - - - - // end tile processing...??? - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - if (pl) { - pl->setProgress (0.60); - } - - int imw, imh; - double tmpScale = ipf.resizeScale(¶ms, fw, fh, imw, imh); - bool labResize = params.resize.enabled && params.resize.method != "Nearest" && tmpScale != 1.0; - LabImage *tmplab; - - // crop and convert to rgb16 - int cx = 0, cy = 0, cw = labView->W, ch = labView->H; - - if (params.crop.enabled) { - cx = params.crop.x; - cy = params.crop.y; - cw = params.crop.w; - ch = params.crop.h; - - if(labResize) { // crop lab data - tmplab = new LabImage(cw, ch); - - for(int row = 0; row < ch; row++) { - for(int col = 0; col < cw; col++) { - tmplab->L[row][col] = labView->L[row + cy][col + cx]; - tmplab->a[row][col] = labView->a[row + cy][col + cx]; - tmplab->b[row][col] = labView->b[row + cy][col + cx]; - } - } - - delete labView; - labView = tmplab; - cx = 0; - cy = 0; - } - } - - if (labResize) { // resize lab data - // resize image - tmplab = new LabImage(imw, imh); - ipf.Lanczos (labView, tmplab, tmpScale); - delete labView; - labView = tmplab; - cw = labView->W; - ch = labView->H; - - if(params.prsharpening.enabled) { - for(int i = 0; i < ch; i++) - for(int j = 0; j < cw; j++) { - labView->L[i][j] = labView->L[i][j] < 0.f ? 0.f : labView->L[i][j]; - } - - float **buffer = new float*[ch]; - - for (int i = 0; i < ch; i++) { - buffer[i] = new float[cw]; - } - - ipf.sharpening (labView, (float**)buffer, params.prsharpening); - - for (int i = 0; i < ch; i++) { - delete [] buffer[i]; - } - - delete [] buffer; - } - } - - Image16* readyImg = nullptr; - cmsHPROFILE jprof = nullptr; - bool customGamma = false; - bool useLCMS = false; - bool bwonly = params.blackwhite.enabled && !params.colorToning.enabled && !autili && !butili ; - - if(params.icm.gamma != "default" || params.icm.freegamma) { // if select gamma output between BT709, sRGB, linear, low, high, 2.2 , 1.8 - - GammaValues ga; - // if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; - readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly, &ga); - customGamma = true; - - //or selected Free gamma - useLCMS = false; - - if ((jprof = iccStore->createCustomGammaOutputProfile (params.icm, ga)) == nullptr) { - useLCMS = true; - } - - } else { - // if Default gamma mode: we use the profile selected in the "Output profile" combobox; - // gamma come from the selected profile, otherwise it comes from "Free gamma" tool - - readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, bwonly); - - if (settings->verbose) { - printf("Output profile_: \"%s\"\n", params.icm.output.c_str()); - } - } - - delete labView; - labView = nullptr; - - - - if(bwonly) { //force BW r=g=b - if (settings->verbose) { - printf("Force BW\n"); - } - - for (int ccw = 0; ccw < cw; ccw++) { - for (int cch = 0; cch < ch; cch++) { - readyImg->r(cch, ccw) = readyImg->g(cch, ccw); - readyImg->b(cch, ccw) = readyImg->g(cch, ccw); - } - } - } - - if (pl) { - pl->setProgress (0.70); - } - - if (tmpScale != 1.0 && params.resize.method == "Nearest") { // resize rgb data (gamma applied) - Image16* tempImage = new Image16 (imw, imh); - ipf.resize (readyImg, tempImage, tmpScale); - delete readyImg; - readyImg = tempImage; - } - - if (tunnelMetaData) { - readyImg->setMetadata (ii->getMetaData()->getExifData ()); - } else { - readyImg->setMetadata (ii->getMetaData()->getExifData (), params.exif, params.iptc); - } - - - // Setting the output curve to readyImg - if (customGamma) { - if (!useLCMS) { - // use corrected sRGB profile in order to apply a good TRC if present, otherwise use LCMS2 profile generated by lab2rgb16 w/ gamma - ProfileContent pc(jprof); - readyImg->setOutputProfile (pc.data, pc.length); - } - } else { - // use the selected output profile if present, otherwise use LCMS2 profile generate by lab2rgb16 w/ gamma - - if (params.icm.output != "" && params.icm.output != ColorManagementParams::NoICMString) { - - // if iccStore->getProfile send back an object, then iccStore->getContent will do too - cmsHPROFILE jprof = iccStore->getProfile(params.icm.output); //get outProfile - - if (jprof == nullptr) { - if (settings->verbose) { - printf("\"%s\" ICC output profile not found!\n - use LCMS2 substitution\n", params.icm.output.c_str()); - } - } else { - if (settings->verbose) { - printf("Using \"%s\" output profile\n", params.icm.output.c_str()); - } - - ProfileContent pc = iccStore->getContent (params.icm.output); - readyImg->setOutputProfile (pc.data, pc.length); - } - } else { - // No ICM - readyImg->setOutputProfile (nullptr, 0); - } - } - -// t2.set(); -// if( settings->verbose ) -// printf("Total:- %d usec\n", t2.etime(t1)); - - if (!job->initialImage) { - ii->decreaseRef (); - } - - delete job; - - if (pl) { - pl->setProgress (0.75); - } - - /* curve1.reset();curve2.reset(); - curve.reset(); - satcurve.reset(); - lhskcurve.reset(); - - rCurve.reset(); - gCurve.reset(); - bCurve.reset(); - hist16.reset(); - hist16C.reset(); - */ - return readyImg; +IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool tunnelMetaData, bool flush) +{ + ImageProcessor proc(pjob, errorCode, pl, tunnelMetaData, flush); + return proc(true); } void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData) From 93296cff17d93b14b033ee63164a68eb72632bbd Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 8 Mar 2017 00:50:50 +0100 Subject: [PATCH 02/18] continuing with my experiments on an alternative "fast export" --- rtengine/processingjob.cc | 8 ++++---- rtengine/processingjob.h | 9 ++++---- rtengine/rtengine.h | 4 ++-- rtengine/simpleprocess.cc | 43 +++++++++++++++++++-------------------- rtgui/batchqueue.cc | 9 ++++++-- rtgui/filebrowser.cc | 6 +++++- rtgui/filecatalog.cc | 4 ++-- rtgui/main.cc | 8 +++++++- 8 files changed, 53 insertions(+), 38 deletions(-) diff --git a/rtengine/processingjob.cc b/rtengine/processingjob.cc index 612edc2a2..a377e3963 100644 --- a/rtengine/processingjob.cc +++ b/rtengine/processingjob.cc @@ -21,16 +21,16 @@ namespace rtengine { -ProcessingJob* ProcessingJob::create (const Glib::ustring& fname, bool isRaw, const procparams::ProcParams& pparams) +ProcessingJob* ProcessingJob::create (const Glib::ustring& fname, bool isRaw, const procparams::ProcParams& pparams, bool fast) { - return new ProcessingJobImpl (fname, isRaw, pparams); + return new ProcessingJobImpl (fname, isRaw, pparams, fast); } -ProcessingJob* ProcessingJob::create (InitialImage* initialImage, const procparams::ProcParams& pparams) +ProcessingJob* ProcessingJob::create (InitialImage* initialImage, const procparams::ProcParams& pparams, bool fast) { - return new ProcessingJobImpl (initialImage, pparams); + return new ProcessingJobImpl (initialImage, pparams, fast); } void ProcessingJob::destroy (ProcessingJob* job) diff --git a/rtengine/processingjob.h b/rtengine/processingjob.h index 2de426a31..fd3fe82a8 100644 --- a/rtengine/processingjob.h +++ b/rtengine/processingjob.h @@ -32,12 +32,13 @@ public: bool isRaw; InitialImage* initialImage; procparams::ProcParams pparams; + bool fast; - ProcessingJobImpl (const Glib::ustring& fn, bool iR, const procparams::ProcParams& pp) - : fname(fn), isRaw(iR), initialImage(nullptr), pparams(pp) {} + ProcessingJobImpl (const Glib::ustring& fn, bool iR, const procparams::ProcParams& pp, bool ff) + : fname(fn), isRaw(iR), initialImage(nullptr), pparams(pp), fast(ff) {} - ProcessingJobImpl (InitialImage* iImage, const procparams::ProcParams& pp) - : fname(""), isRaw(true), initialImage(iImage), pparams(pp) + ProcessingJobImpl (InitialImage* iImage, const procparams::ProcParams& pp, bool ff) + : fname(""), isRaw(true), initialImage(iImage), pparams(pp), fast(ff) { iImage->increaseRef(); } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index fc793dd71..4cb672e15 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -468,7 +468,7 @@ public: * @param isRaw shall be true if it is a raw file * @param pparams is a struct containing the processing parameters * @return an object containing the data above. It can be passed to the functions that do the actual image processing. */ - static ProcessingJob* create (const Glib::ustring& fname, bool isRaw, const procparams::ProcParams& pparams); + static ProcessingJob* create (const Glib::ustring& fname, bool isRaw, const procparams::ProcParams& pparams, bool fast=false); /** Creates a processing job from a file name. This function always succeeds. It only stores the data into the ProcessingJob class, it does not load * the image thus it returns immediately. This function increases the reference count of the initialImage. If you decide not the process the image you @@ -477,7 +477,7 @@ public: * @param initialImage is a loaded and pre-processed initial image * @param pparams is a struct containing the processing parameters * @return an object containing the data above. It can be passed to the functions that do the actual image processing. */ - static ProcessingJob* create (InitialImage* initialImage, const procparams::ProcParams& pparams); + static ProcessingJob* create (InitialImage* initialImage, const procparams::ProcParams& pparams, bool fast=false); /** Cancels and destroys a processing job. The reference count of the corresponding initialImage (if any) is decreased. After the call of this function the ProcessingJob instance * gets invalid, you must not use it any more. Dont call this function while the job is being processed. diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index e027968a5..677f912fc 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -41,7 +41,7 @@ class ImageProcessor { public: ImageProcessor(ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool tunnelMetaData, bool flush): - pjob(pjob), + job(static_cast(pjob)), errorCode(errorCode), pl(pl), tunnelMetaData(tunnelMetaData), @@ -55,9 +55,9 @@ public: { } - Image16 *operator()(bool fast) + Image16 *operator()() { - if (!fast) { + if (!job->fast) { return normal_pipeline(); } else { return fast_pipeline(); @@ -81,21 +81,28 @@ private: Image16 *fast_pipeline() { - ProcessingJobImpl* job = static_cast(pjob); if (!job->pparams.resize.enabled) { return normal_pipeline(); } + + pl = nullptr; if (!stage_1()) { return nullptr; } + stage_calc_denoise(); + printf("after calc denoise\n"); fflush(stdout); stage_2(); stage_4(); + printf("after 4\n"); fflush(stdout); stage_early_resize(); - stage_calc_denoise(); + printf("after early resize\n"); fflush(stdout); stage_3(); + printf("after 3\n"); fflush(stdout); stage_5(); + printf("after 5\n"); fflush(stdout); stage_6(); + printf("after 6\n"); fflush(stdout); return stage_7(); } @@ -103,8 +110,6 @@ private: { errorCode = 0; - ProcessingJobImpl* job = static_cast(pjob); - if (pl) { pl->setProgressStr ("PROGRESSBAR_PROCESSING"); pl->setProgress (0.0); @@ -235,7 +240,6 @@ private: void stage_calc_denoise() { - ProcessingJobImpl* job = static_cast(pjob); procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -714,7 +718,6 @@ private: void stage_2() { - ProcessingJobImpl* job = static_cast(pjob); procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -753,7 +756,6 @@ private: void stage_3() { - ProcessingJobImpl* job = static_cast(pjob); procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -826,7 +828,6 @@ private: void stage_4() { - ProcessingJobImpl* job = static_cast(pjob); procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -849,7 +850,6 @@ private: void stage_5() { - ProcessingJobImpl* job = static_cast(pjob); procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -994,7 +994,6 @@ private: void stage_6() { - ProcessingJobImpl* job = static_cast(pjob); procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -1192,7 +1191,6 @@ private: Image16 *stage_7() { - ProcessingJobImpl* job = static_cast(pjob); procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -1389,7 +1387,6 @@ private: void stage_early_resize() { - ProcessingJobImpl* job = static_cast(pjob); procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -1435,14 +1432,16 @@ private: tmplab = resized; params.resize.enabled = false; - if (params.prsharpening.enabled) { - params.sharpening = params.prsharpening; - } - + params.sharpening = params.prsharpening; params.wavelet.strength = int(float(params.wavelet.strength) * tmpScale); params.dirpyrDenoise.luma *= tmpScale; - // params.dirpyrDenoise.smethod = "shal"; + params.dirpyrDenoise.smethod = "shal"; + + for (int i = 0; i < 6; ++i) { + auto &n = params.dirpyrequalizer.mult[i]; + n = 1.0 + (n - 1.0) * tmpScale; + } fw = imw; fh = imh; @@ -1455,7 +1454,7 @@ private: } private: - ProcessingJob* pjob; + ProcessingJobImpl* job; int& errorCode; ProgressListener* pl; bool tunnelMetaData; @@ -1534,7 +1533,7 @@ private: IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool tunnelMetaData, bool flush) { ImageProcessor proc(pjob, errorCode, pl, tunnelMetaData, flush); - return proc(true); + return proc(); } void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl, bool tunnelMetaData) diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 7bd53c444..1f2dac51d 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -34,6 +34,9 @@ #include "guiutils.h" #include "rtimage.h" #include + +#include "../rtengine/processingjob.h" + using namespace std; using namespace rtengine; @@ -227,7 +230,7 @@ bool BatchQueue::saveBatchQueue () // The column's header is mandatory (the first line will be skipped when loaded) file << "input image full path|param file full path|output image full path|file format|jpeg quality|jpeg subsampling|" - << "png bit depth|png compression|tiff bit depth|uncompressed tiff|save output params|force format options|" + << "png bit depth|png compression|tiff bit depth|uncompressed tiff|save output params|force format options|fast export|" << std::endl; // method is already running with entryLock, so no need to lock again @@ -242,6 +245,7 @@ bool BatchQueue::saveBatchQueue () << saveFormat.pngBits << '|' << saveFormat.pngCompression << '|' << saveFormat.tiffBits << '|' << saveFormat.tiffUncompressed << '|' << saveFormat.saveParams << '|' << entry->forceFormatOpts << '|' + << static_cast(entry->job)->fast << '|' << std::endl; } } @@ -308,6 +312,7 @@ bool BatchQueue::loadBatchQueue () const auto tiffUncompressed = nextIntOr (options.saveFormat.tiffUncompressed); const auto saveParams = nextIntOr (options.saveFormat.saveParams); const auto forceFormatOpts = nextIntOr (options.forceFormatOpts); + const auto fast = nextIntOr(false); rtengine::procparams::ProcParams pparams; @@ -319,7 +324,7 @@ bool BatchQueue::loadBatchQueue () if (!thumb) continue; - auto job = rtengine::ProcessingJob::create (source, thumb->getType () == FT_Raw, pparams); + auto job = rtengine::ProcessingJob::create (source, thumb->getType () == FT_Raw, pparams, fast); auto prevh = getMaxThumbnailHeight (); auto prevw = prevh; diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 5cbb5255b..24d1d8541 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -389,6 +389,7 @@ FileBrowser::FileBrowser () untrash->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_Delete, Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); open->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_Return, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); develop->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_B, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); + developfast->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_B, Gdk::CONTROL_MASK | Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); copyprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_C, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); pasteprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_V, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); partpasteprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_V, Gdk::CONTROL_MASK | Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); @@ -1139,9 +1140,12 @@ bool FileBrowser::keyPressed (GdkEventKey* event) } else if (event->keyval == GDK_KEY_Delete && shift) { menuItemActivated (untrash); return true; - } else if ((event->keyval == GDK_KEY_B || event->keyval == GDK_KEY_b) && ctrl) { + } else if ((event->keyval == GDK_KEY_B || event->keyval == GDK_KEY_b) && ctrl && !shift) { menuItemActivated (develop); return true; + } else if ((event->keyval == GDK_KEY_B || event->keyval == GDK_KEY_b) && ctrl && shift) { + menuItemActivated (developfast); + return true; } else if ((event->keyval == GDK_KEY_A || event->keyval == GDK_KEY_a) && ctrl) { menuItemActivated (selall); return true; diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index a876dd54e..99c190cde 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1094,7 +1094,7 @@ void FileCatalog::developRequested (std::vector tbe, bool fas // controlling time and resource consuming tasks // and also those which effect is not pronounced after reducing the image size // TODO!!! could expose selections below via preferences - if (fastmode) { + if (fastmode && false) { if (options.fastexport_bypass_sharpening ) { params.sharpening.enabled = false; } @@ -1187,7 +1187,7 @@ void FileCatalog::developRequested (std::vector tbe, bool fas params.resize.height = options.fastexport_resize_height ; } - rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params); + rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode); int pw; int ph = BatchQueue::calcMaxThumbnailHeight(); diff --git a/rtgui/main.cc b/rtgui/main.cc index ee3d3210e..7e11825a2 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -83,6 +83,8 @@ Glib::ustring fname_to_utf8 (const char* fname) #endif } +bool fast_export = false; + } // This recursive mutex will be used by gdk_threads_enter/leave instead of a simple mutex @@ -537,6 +539,10 @@ int processLineParams( int argc, char **argv ) compression = -1; break; + case 'f': + fast_export = true; + break; + case 'c': // MUST be last option while (iArg + 1 < argc) { iArg++; @@ -845,7 +851,7 @@ int processLineParams( int argc, char **argv ) continue; } - job = rtengine::ProcessingJob::create (ii, currentParams); + job = rtengine::ProcessingJob::create (ii, currentParams, fast_export); if( !job ) { errors++; From 44505ccb0844a6ef9823cdbd82cca2ca299161fc Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 8 Mar 2017 22:55:08 +0100 Subject: [PATCH 03/18] some enhancements of the Fast Export functionality - remember fast export options across RT sessions - added option to use a dedicated "Fast Export" pipeline, trading speed for quality (resizes early instead of at the end) --- rtdata/languages/default | 2 + rtengine/processingjob.h | 2 + rtengine/rtengine.h | 2 + rtengine/simpleprocess.cc | 86 ++++++++------------------------------- rtgui/batchqueue.cc | 4 +- rtgui/exportpanel.cc | 64 +++++++++++++++++++---------- rtgui/exportpanel.h | 1 + rtgui/filecatalog.cc | 8 ++-- rtgui/options.cc | 5 +++ rtgui/options.h | 1 + 10 files changed, 76 insertions(+), 99 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 31b14aa2f..f47d09e5d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -80,6 +80,8 @@ EXPORT_BYPASS_SHARPENEDGE;Bypass Edge Sharpening EXPORT_BYPASS_SHARPENING;Bypass Sharpening EXPORT_BYPASS_SHARPENMICRO;Bypass Microcontrast EXPORT_BYPASS_SH_HQ;Bypass Sharp Mask Shadows/Highlights +EXPORT_USE_FAST_PIPELINE;Enable Special "Fast-Export" Processing Pipeline +EXPORT_USE_FAST_PIPELINE_TIP;Use a dedicated processing pipeline for images in Fast Export mode, that trades speed for quality. Resizing of the image is done as early as possible, instead of doing it at the end like in the normal pipeline. The speedup can be significant, but be prepared to see artifacts and a general degradation of output quality. EXPORT_FASTEXPORTOPTIONS;Fast Export Options EXPORT_INSTRUCTIONS;Fast Export options provide overrides to bypass time and resource consuming development settings and to run queue processing using the fast export settings instead. This method is recommended for quicker generation of lower resolution images when speed is a priority or when resized output is desired for one or many images without making modifications to their saved development parameters. EXPORT_MAXHEIGHT;Maximum height: diff --git a/rtengine/processingjob.h b/rtengine/processingjob.h index fd3fe82a8..c7f49192e 100644 --- a/rtengine/processingjob.h +++ b/rtengine/processingjob.h @@ -49,6 +49,8 @@ public: initialImage->decreaseRef(); } } + + bool fastPipeline() const { return fast; } }; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 4cb672e15..7449dbd0d 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -483,6 +483,8 @@ public: * gets invalid, you must not use it any more. Dont call this function while the job is being processed. * @param job is the job to destroy */ static void destroy (ProcessingJob* job); + + virtual bool fastPipeline() const = 0; }; /** This function performs all the image processinf steps corresponding to the given ProcessingJob. It returns when it is ready, so it can be slow. diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 677f912fc..3b450c492 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -67,16 +67,12 @@ public: private: Image16 *normal_pipeline() { - if (!stage_1()) { + if (!stage_init()) { return nullptr; } - stage_calc_denoise(); - stage_2(); - stage_3(); - stage_4(); - stage_5(); - stage_6(); - return stage_7(); + stage_denoise(); + stage_transform(); + return stage_finish(); } Image16 *fast_pipeline() @@ -87,26 +83,16 @@ private: pl = nullptr; - if (!stage_1()) { + if (!stage_init()) { return nullptr; } - stage_calc_denoise(); - printf("after calc denoise\n"); fflush(stdout); - stage_2(); - stage_4(); - printf("after 4\n"); fflush(stdout); + stage_transform(); stage_early_resize(); - printf("after early resize\n"); fflush(stdout); - stage_3(); - printf("after 3\n"); fflush(stdout); - stage_5(); - printf("after 5\n"); fflush(stdout); - stage_6(); - printf("after 6\n"); fflush(stdout); - return stage_7(); + stage_denoise(); + return stage_finish(); } - bool stage_1() + bool stage_init() { errorCode = 0; @@ -230,19 +216,6 @@ private: currWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias); } - // // AG begin - // baseImg = new Imagefloat (fw, fh); - // imgsrc->getImage (currWB, tr, baseImg, pp, params.toneCurve, params.icm, params.raw); - // // AG end - - return true; - } - - void stage_calc_denoise() - { - procparams::ProcParams& params = job->pparams; - ImProcFunctions ipf (¶ms, true); - calclum = nullptr ; params.dirpyrDenoise.getCurves(noiseLCurve, noiseCCurve); autoNR = (float) settings->nrauto;// @@ -713,14 +686,6 @@ private: //end evaluate noise } - // return true; - } - - void stage_2() - { - procparams::ProcParams& params = job->pparams; - ImProcFunctions ipf (¶ms, true); - baseImg = new Imagefloat (fw, fh); imgsrc->getImage (currWB, tr, baseImg, pp, params.toneCurve, params.icm, params.raw); @@ -752,9 +717,11 @@ private: imgsrc->flushRawData(); imgsrc->flushRGB(); } + + return true; } - void stage_3() + void stage_denoise() { procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -816,17 +783,9 @@ private: delete [] ry; delete [] sk; delete [] pcsk; - - // imgsrc->convertColorSpace(baseImg, params.icm, currWB); - - // // perform first analysis - // hist16 (65536); - - // ipf.firstAnalysis (baseImg, params, hist16); } - - void stage_4() + void stage_transform() { procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -848,7 +807,7 @@ private: } } - void stage_5() + Image16 *stage_finish() { procparams::ProcParams& params = job->pparams; ImProcFunctions ipf (¶ms, true); @@ -990,13 +949,7 @@ private: if (pl) { pl->setProgress (0.55); } - } - void stage_6() - { - procparams::ProcParams& params = job->pparams; - ImProcFunctions ipf (¶ms, true); - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // start tile processing...??? @@ -1187,13 +1140,7 @@ private: if (pl) { pl->setProgress (0.60); } - } - Image16 *stage_7() - { - procparams::ProcParams& params = job->pparams; - ImProcFunctions ipf (¶ms, true); - int imw, imh; double tmpScale = ipf.resizeScale(¶ms, fw, fh, imw, imh); bool labResize = params.resize.enabled && params.resize.method != "Nearest" && tmpScale != 1.0; @@ -1392,12 +1339,10 @@ private: int imw, imh; double tmpScale = ipf.resizeScale(¶ms, fw, fh, imw, imh); - // bool resize = params.resize.enabled; LabImage *tmplab = new LabImage(fw, fh); ipf.rgb2lab(*baseImg, *tmplab, params.icm.working); - // crop and convert to rgb16 int cx = 0, cy = 0, cw = fw, ch = fh; if (params.crop.enabled) { @@ -1438,9 +1383,10 @@ private: params.dirpyrDenoise.luma *= tmpScale; params.dirpyrDenoise.smethod = "shal"; + const double dirpyreq_scale = min(tmpScale * 1.5, 1.0); for (int i = 0; i < 6; ++i) { auto &n = params.dirpyrequalizer.mult[i]; - n = 1.0 + (n - 1.0) * tmpScale; + n = 1.0 + (n - 1.0) * dirpyreq_scale; } fw = imw; diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 1f2dac51d..a02046e01 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -35,8 +35,6 @@ #include "rtimage.h" #include -#include "../rtengine/processingjob.h" - using namespace std; using namespace rtengine; @@ -245,7 +243,7 @@ bool BatchQueue::saveBatchQueue () << saveFormat.pngBits << '|' << saveFormat.pngCompression << '|' << saveFormat.tiffBits << '|' << saveFormat.tiffUncompressed << '|' << saveFormat.saveParams << '|' << entry->forceFormatOpts << '|' - << static_cast(entry->job)->fast << '|' + << entry->job->fastPipeline() << '|' << std::endl; } } diff --git a/rtgui/exportpanel.cc b/rtgui/exportpanel.cc index 3f7be7ab4..fe18cdef7 100644 --- a/rtgui/exportpanel.cc +++ b/rtgui/exportpanel.cc @@ -39,6 +39,8 @@ ExportPanel::ExportPanel () : listener (nullptr) pack_start(*labExportTitle, Gtk::PACK_SHRINK, 4); bypass_ALL = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_ALL"))); + use_fast_pipeline = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_USE_FAST_PIPELINE"))); + use_fast_pipeline->set_tooltip_text(M("EXPORT_USE_FAST_PIPELINE_TIP")); bypass_sharpening = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENING"))); bypass_sharpenEdge = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENEDGE"))); bypass_sharpenMicro = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENMICRO"))); @@ -96,6 +98,7 @@ ExportPanel::ExportPanel () : listener (nullptr) // ---------------------------------------------------------------- // start global packing + pack_start(*use_fast_pipeline , Gtk::PACK_SHRINK, 4); pack_start(*bypass_ALL , Gtk::PACK_SHRINK, 4); pack_start(*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 4); pack_start(*bypass_sharpening , Gtk::PACK_SHRINK, 4); @@ -224,40 +227,48 @@ void ExportPanel::FastExportPressed () void ExportPanel::SaveSettingsAsDefault() { + bool changed = false; +#define FE_OPT_STORE_(n, v) \ + do { \ + if (n != v) { \ + n = v; \ + changed = true; \ + } \ + } while (false) // Save fast export settings to options - options.fastexport_bypass_sharpening = bypass_sharpening->get_active (); - options.fastexport_bypass_sharpenEdge = bypass_sharpenEdge->get_active (); - options.fastexport_bypass_sharpenMicro = bypass_sharpenMicro->get_active (); + FE_OPT_STORE_(options.fastexport_bypass_sharpening, bypass_sharpening->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_sharpenEdge, bypass_sharpenEdge->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_sharpenMicro, bypass_sharpenMicro->get_active ()); //options.fastexport_bypass_lumaDenoise = bypass_lumaDenoise->get_active (); //options.fastexport_bypass_colorDenoise = bypass_colorDenoise->get_active (); - options.fastexport_bypass_defringe = bypass_defringe->get_active (); - options.fastexport_bypass_dirpyrDenoise = bypass_dirpyrDenoise->get_active (); - options.fastexport_bypass_sh_hq = bypass_sh_hq->get_active (); - options.fastexport_bypass_dirpyrequalizer = bypass_dirpyrequalizer->get_active (); - options.fastexport_bypass_wavelet = bypass_wavelet->get_active (); + FE_OPT_STORE_(options.fastexport_bypass_defringe, bypass_defringe->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_dirpyrDenoise, bypass_dirpyrDenoise->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_sh_hq, bypass_sh_hq->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_dirpyrequalizer, bypass_dirpyrequalizer->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_wavelet, bypass_wavelet->get_active ()); //options.fastexport_bypass_raw_bayer_all_enhance = bypass_raw_all_enhance->get_active (); - options.fastexport_bypass_raw_bayer_dcb_iterations = bypass_raw_bayer_dcb_iterations->get_active (); - options.fastexport_bypass_raw_bayer_dcb_enhance = bypass_raw_bayer_dcb_enhance->get_active (); - options.fastexport_bypass_raw_bayer_lmmse_iterations = bypass_raw_bayer_lmmse_iterations->get_active(); - options.fastexport_bypass_raw_bayer_linenoise = bypass_raw_bayer_linenoise->get_active (); - options.fastexport_bypass_raw_bayer_greenthresh = bypass_raw_bayer_greenthresh->get_active (); - options.fastexport_bypass_raw_ccSteps = bypass_raw_ccSteps->get_active (); - options.fastexport_bypass_raw_ca = bypass_raw_ca->get_active (); - options.fastexport_bypass_raw_df = bypass_raw_df->get_active (); - options.fastexport_bypass_raw_ff = bypass_raw_ff->get_active (); + FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_dcb_iterations, bypass_raw_bayer_dcb_iterations->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_dcb_enhance, bypass_raw_bayer_dcb_enhance->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_lmmse_iterations, bypass_raw_bayer_lmmse_iterations->get_active()); + FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_linenoise, bypass_raw_bayer_linenoise->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_bayer_greenthresh, bypass_raw_bayer_greenthresh->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_ccSteps, bypass_raw_ccSteps->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_ca, bypass_raw_ca->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_df, bypass_raw_df->get_active ()); + FE_OPT_STORE_(options.fastexport_bypass_raw_ff, bypass_raw_ff->get_active ()); //saving Bayer demosaic_method int currentRow = raw_bayer_method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::BayerSensor::numMethods) { - options.fastexport_raw_bayer_method = procparams::RAWParams::BayerSensor::methodstring[currentRow]; + FE_OPT_STORE_(options.fastexport_raw_bayer_method, procparams::RAWParams::BayerSensor::methodstring[currentRow]); } //saving X-Trans demosaic_method currentRow = raw_xtrans_method->get_active_row_number(); if( currentRow >= 0 && currentRow < procparams::RAWParams::XTransSensor::numMethods) { - options.fastexport_raw_xtrans_method = procparams::RAWParams::XTransSensor::methodstring[currentRow]; + FE_OPT_STORE_(options.fastexport_raw_xtrans_method, procparams::RAWParams::XTransSensor::methodstring[currentRow]); } // options.fastexport_icm_input = icm_input ; @@ -269,9 +280,16 @@ void ExportPanel::SaveSettingsAsDefault() // options.fastexport_resize_appliesTo = resize_appliesTo; // options.fastexport_resize_dataspec = resize_dataspec ; - options.fastexport_resize_method = "Lanczos"; - options.fastexport_resize_width = MaxWidth->get_value_as_int (); - options.fastexport_resize_height = MaxHeight->get_value_as_int (); + FE_OPT_STORE_(options.fastexport_resize_method, "Lanczos"); + FE_OPT_STORE_(options.fastexport_resize_width, MaxWidth->get_value_as_int ()); + FE_OPT_STORE_(options.fastexport_resize_height, MaxHeight->get_value_as_int ()); + + FE_OPT_STORE_(options.fastexport_use_fast_pipeline, use_fast_pipeline->get_active()); +#undef FE_OPT_STORE_ + + if (changed) { + Options::save(); + } } void ExportPanel::LoadDefaultSettings() @@ -327,6 +345,8 @@ void ExportPanel::LoadDefaultSettings() MaxWidth->set_value(options.fastexport_resize_width); MaxHeight->set_value(options.fastexport_resize_height); + + use_fast_pipeline->set_active(options.fastexport_use_fast_pipeline); } void ExportPanel::LoadSettings() diff --git a/rtgui/exportpanel.h b/rtgui/exportpanel.h index 840a4638d..ce7639921 100644 --- a/rtgui/exportpanel.h +++ b/rtgui/exportpanel.h @@ -38,6 +38,7 @@ protected: //Gtk::CheckButton* enabled; Gtk::CheckButton* bypass_ALL; + Gtk::CheckButton* use_fast_pipeline; Gtk::CheckButton* bypass_sharpenEdge; Gtk::CheckButton* bypass_sharpenMicro; Gtk::CheckButton* bypass_sharpening; diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 99c190cde..68219d745 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1094,7 +1094,7 @@ void FileCatalog::developRequested (std::vector tbe, bool fas // controlling time and resource consuming tasks // and also those which effect is not pronounced after reducing the image size // TODO!!! could expose selections below via preferences - if (fastmode && false) { + if (fastmode) { if (options.fastexport_bypass_sharpening ) { params.sharpening.enabled = false; } @@ -1183,11 +1183,11 @@ void FileCatalog::developRequested (std::vector tbe, bool fas params.resize.appliesTo = options.fastexport_resize_appliesTo ; params.resize.method = options.fastexport_resize_method ; params.resize.dataspec = options.fastexport_resize_dataspec ; - params.resize.width = options.fastexport_resize_width ; - params.resize.height = options.fastexport_resize_height ; + params.resize.width = rtengine::min(params.resize.width, options.fastexport_resize_width) ; + params.resize.height = rtengine::min(params.resize.height, options.fastexport_resize_height) ; } - rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode); + rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode && options.fastexport_use_fast_pipeline); int pw; int ph = BatchQueue::calcMaxThumbnailHeight(); diff --git a/rtgui/options.cc b/rtgui/options.cc index 2f71a7106..9a8b5e08b 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -480,6 +480,7 @@ void Options::setDefaults () fastexport_resize_dataspec = 3; fastexport_resize_width = 900; fastexport_resize_height = 900; + fastexport_use_fast_pipeline = false; clutsDir = "./cluts"; @@ -1784,6 +1785,9 @@ int Options::readFromFile (Glib::ustring fname) if (keyFile.has_key ("Fast Export", "fastexport_resize_height" )) { fastexport_resize_height = keyFile.get_integer ("Fast Export", "fastexport_resize_height" ); } + if (keyFile.has_key ("Fast Export", "fastexport_use_fast_pipeline" )) { + fastexport_use_fast_pipeline = keyFile.get_integer ("Fast Export", "fastexport_use_fast_pipeline" ); + } } if (keyFile.has_group ("Dialogs")) { @@ -2142,6 +2146,7 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_integer ("Fast Export", "fastexport_resize_dataspec", fastexport_resize_dataspec ); keyFile.set_integer ("Fast Export", "fastexport_resize_width", fastexport_resize_width ); keyFile.set_integer ("Fast Export", "fastexport_resize_height", fastexport_resize_height ); + keyFile.set_integer ("Fast Export", "fastexport_use_fast_pipeline", fastexport_use_fast_pipeline ); keyFile.set_string ("Dialogs", "LastIccDir", lastIccDir); keyFile.set_string ("Dialogs", "LastDarkframeDir", lastDarkframeDir); diff --git a/rtgui/options.h b/rtgui/options.h index efc649417..b853c07f6 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -279,6 +279,7 @@ public: int fastexport_resize_dataspec; int fastexport_resize_width; int fastexport_resize_height; + bool fastexport_use_fast_pipeline; // Dialog settings Glib::ustring lastIccDir; From 64661e1a2711ce38ef7c85baea49d81f2892ada1 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 9 Mar 2017 00:05:27 +0100 Subject: [PATCH 04/18] set dirpyrDenoise.median=false in the fast export pipeline --- rtengine/simpleprocess.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 3b450c492..774ee6c5c 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1382,6 +1382,7 @@ private: int(float(params.wavelet.strength) * tmpScale); params.dirpyrDenoise.luma *= tmpScale; params.dirpyrDenoise.smethod = "shal"; + params.dirpyrDenoise.median = false; const double dirpyreq_scale = min(tmpScale * 1.5, 1.0); for (int i = 0; i < 6; ++i) { From 359b4136b52f90c431665ccd36fdfcb98ef9edcc Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 10 Mar 2017 10:53:10 +0100 Subject: [PATCH 05/18] do not use the hard-coded (i.e. not user-selectable) fast export options if the new fast pipeline is selected --- rtengine/simpleprocess.cc | 2 +- rtgui/filecatalog.cc | 52 ++++++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 774ee6c5c..f10378a07 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1381,8 +1381,8 @@ private: params.wavelet.strength = int(float(params.wavelet.strength) * tmpScale); params.dirpyrDenoise.luma *= tmpScale; + params.dirpyrDenoise.smethod = "shal"; - params.dirpyrDenoise.median = false; const double dirpyreq_scale = min(tmpScale * 1.5, 1.0); for (int i = 0; i < 6; ++i) { diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 68219d745..a5b3cdb85 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1129,25 +1129,27 @@ void FileCatalog::developRequested (std::vector tbe, bool fas params.wavelet.enabled = false; } - //if (options.fastexport_bypass_raw_bayer_all_enhance ) params.raw.bayersensor.all_enhance = false; - if (options.fastexport_bypass_raw_bayer_dcb_iterations ) { - params.raw.bayersensor.dcb_iterations = 0; - } + if (!options.fastexport_use_fast_pipeline) { + //if (options.fastexport_bypass_raw_bayer_all_enhance ) params.raw.bayersensor.all_enhance = false; + if (options.fastexport_bypass_raw_bayer_dcb_iterations ) { + params.raw.bayersensor.dcb_iterations = 0; + } - if (options.fastexport_bypass_raw_bayer_dcb_enhance ) { - params.raw.bayersensor.dcb_enhance = false; - } + if (options.fastexport_bypass_raw_bayer_dcb_enhance ) { + params.raw.bayersensor.dcb_enhance = false; + } - if (options.fastexport_bypass_raw_bayer_lmmse_iterations) { - params.raw.bayersensor.lmmse_iterations = 0; - } + if (options.fastexport_bypass_raw_bayer_lmmse_iterations) { + params.raw.bayersensor.lmmse_iterations = 0; + } - if (options.fastexport_bypass_raw_bayer_linenoise ) { - params.raw.bayersensor.linenoise = 0; - } + if (options.fastexport_bypass_raw_bayer_linenoise ) { + params.raw.bayersensor.linenoise = 0; + } - if (options.fastexport_bypass_raw_bayer_greenthresh ) { - params.raw.bayersensor.greenthresh = 0; + if (options.fastexport_bypass_raw_bayer_greenthresh ) { + params.raw.bayersensor.greenthresh = 0; + } } if (options.fastexport_bypass_raw_ccSteps ) { @@ -1170,14 +1172,18 @@ void FileCatalog::developRequested (std::vector tbe, bool fas params.raw.ff_file = ""; } - params.raw.bayersensor.method = options.fastexport_raw_bayer_method ; - params.raw.xtranssensor.method = options.fastexport_raw_xtrans_method; - params.icm.input = options.fastexport_icm_input ; - params.icm.working = options.fastexport_icm_working ; - params.icm.output = options.fastexport_icm_output ; - params.icm.outputIntent = options.fastexport_icm_outputIntent ; - params.icm.outputBPC = options.fastexport_icm_outputBPC ; - params.icm.gamma = options.fastexport_icm_gamma ; + + if (!options.fastexport_use_fast_pipeline) { + params.raw.bayersensor.method = options.fastexport_raw_bayer_method ; + params.raw.xtranssensor.method = options.fastexport_raw_xtrans_method; + params.icm.input = options.fastexport_icm_input ; + params.icm.working = options.fastexport_icm_working ; + params.icm.output = options.fastexport_icm_output ; + params.icm.outputIntent = options.fastexport_icm_outputIntent ; + params.icm.outputBPC = options.fastexport_icm_outputBPC ; + params.icm.gamma = options.fastexport_icm_gamma ; + } + params.resize.enabled = options.fastexport_resize_enabled ; params.resize.scale = options.fastexport_resize_scale ; params.resize.appliesTo = options.fastexport_resize_appliesTo ; From f42710f594a9cd545865e100e802b98c4be4d7e5 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 12 Mar 2017 20:52:32 +0100 Subject: [PATCH 06/18] properly rescale the impulseDenoise settings in the fast pipeline --- rtengine/simpleprocess.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index f10378a07..c0e0c05bd 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1378,10 +1378,14 @@ private: params.resize.enabled = false; params.sharpening = params.prsharpening; + params.impulseDenoise.thresh = + int(float(params.impulseDenoise.thresh) * tmpScale); + if (tmpScale < 0.5) { + params.impulseDenoise.enabled = false; + } params.wavelet.strength = int(float(params.wavelet.strength) * tmpScale); params.dirpyrDenoise.luma *= tmpScale; - params.dirpyrDenoise.smethod = "shal"; const double dirpyreq_scale = min(tmpScale * 1.5, 1.0); From 5a38d0610d92a24331c7d489e6cf38b15854bd2a Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 12 Mar 2017 21:03:49 +0100 Subject: [PATCH 07/18] fix for resizing bug in fast-export mode --- rtgui/filecatalog.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index a5b3cdb85..b9818a839 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1183,14 +1183,20 @@ void FileCatalog::developRequested (std::vector tbe, bool fas params.icm.outputBPC = options.fastexport_icm_outputBPC ; params.icm.gamma = options.fastexport_icm_gamma ; } + + if (params.resize.enabled) { + params.resize.width = rtengine::min(params.resize.width, options.fastexport_resize_width) ; + params.resize.height = rtengine::min(params.resize.height, options.fastexport_resize_height) ; + } else { + params.resize.width = options.fastexport_resize_width; + params.resize.height = options.fastexport_resize_height; + } params.resize.enabled = options.fastexport_resize_enabled ; params.resize.scale = options.fastexport_resize_scale ; params.resize.appliesTo = options.fastexport_resize_appliesTo ; params.resize.method = options.fastexport_resize_method ; params.resize.dataspec = options.fastexport_resize_dataspec ; - params.resize.width = rtengine::min(params.resize.width, options.fastexport_resize_width) ; - params.resize.height = rtengine::min(params.resize.height, options.fastexport_resize_height) ; } rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode && options.fastexport_use_fast_pipeline); From d18ce59132fb630f267f54aabbb84dca20cc51b8 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 12 Mar 2017 21:13:54 +0100 Subject: [PATCH 08/18] some further tweaks to the fast pipeline --- rtengine/simpleprocess.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index c0e0c05bd..06f25d512 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1386,7 +1386,7 @@ private: params.wavelet.strength = int(float(params.wavelet.strength) * tmpScale); params.dirpyrDenoise.luma *= tmpScale; - params.dirpyrDenoise.smethod = "shal"; + //params.dirpyrDenoise.smethod = "shal"; const double dirpyreq_scale = min(tmpScale * 1.5, 1.0); for (int i = 0; i < 6; ++i) { From 6f08233c6f95ff0d66a9abae4daaa8cd710c9633 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 13 Mar 2017 14:00:37 +0100 Subject: [PATCH 09/18] further adjustments of processing parameters for the fast export pipeline --- rtengine/simpleprocess.cc | 84 +++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 06f25d512..50dbedbd0 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1369,34 +1369,18 @@ private: params.crop.enabled = false; } - if (params.resize.enabled) { - // resize image - LabImage *resized = new LabImage(imw, imh); - ipf.Lanczos(tmplab, resized, tmpScale); - delete tmplab; - tmplab = resized; - params.resize.enabled = false; + assert(params.resize.enabled); - params.sharpening = params.prsharpening; - params.impulseDenoise.thresh = - int(float(params.impulseDenoise.thresh) * tmpScale); - if (tmpScale < 0.5) { - params.impulseDenoise.enabled = false; - } - params.wavelet.strength = - int(float(params.wavelet.strength) * tmpScale); - params.dirpyrDenoise.luma *= tmpScale; - //params.dirpyrDenoise.smethod = "shal"; + // resize image + LabImage *resized = new LabImage(imw, imh); + ipf.Lanczos(tmplab, resized, tmpScale); + delete tmplab; + tmplab = resized; - const double dirpyreq_scale = min(tmpScale * 1.5, 1.0); - for (int i = 0; i < 6; ++i) { - auto &n = params.dirpyrequalizer.mult[i]; - n = 1.0 + (n - 1.0) * dirpyreq_scale; - } + adjust_procparams(tmpScale); - fw = imw; - fh = imh; - } + fw = imw; + fh = imh; delete baseImg; baseImg = new Imagefloat(fw, fh); @@ -1404,6 +1388,56 @@ private: delete tmplab; } + void adjust_procparams(double scale_factor) + { + procparams::ProcParams& params = job->pparams; + procparams::ProcParams defaultparams; + +#define ADJUST_RADIUS_(n, f) \ + do { \ + auto delta = (params. n - defaultparams. n) * f; \ + params. n = defaultparams. n + delta; \ + } while (false) + + params.resize.enabled = false; + + if (params.prsharpening.enabled) { + params.sharpening = params.prsharpening; + } else { + ADJUST_RADIUS_(sharpening.radius, scale_factor); + } + params.impulseDenoise.thresh = + int(float(params.impulseDenoise.thresh) * scale_factor); + if (scale_factor < 0.5) { + params.impulseDenoise.enabled = false; + } + params.wavelet.strength = + int(float(params.wavelet.strength) * scale_factor); + params.dirpyrDenoise.luma *= scale_factor; + //params.dirpyrDenoise.smethod = "shal"; + for (auto &p : params.dirpyrDenoise.lcurve) { + p *= scale_factor; + } + for (auto &p : params.dirpyrDenoise.cccurve) { + p *= scale_factor; + } + + params.epd.scale *= scale_factor; + params.epd.edgeStopping *= scale_factor; + + const double dirpyreq_scale = min(scale_factor * 1.5, 1.0); + for (int i = 0; i < 6; ++i) { + ADJUST_RADIUS_(dirpyrequalizer.mult[i], dirpyreq_scale); + // auto &n = params.dirpyrequalizer.mult[i]; + // n = 1.0 + (n - 1.0) * dirpyreq_scale; + } + + ADJUST_RADIUS_(defringe.radius, scale_factor); + ADJUST_RADIUS_(sh.radius, scale_factor); + +#undef ADJUST_RADIUS_ + } + private: ProcessingJobImpl* job; int& errorCode; From 7a69ff84a476539b533254d3d69b1754cb49f8d0 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 13 Mar 2017 15:12:00 +0100 Subject: [PATCH 10/18] use 1-pass method for X-trans demosaic in the fast pipeline As suggested by @heckflosse --- rtengine/simpleprocess.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 50dbedbd0..fd06df66b 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1435,6 +1435,14 @@ private: ADJUST_RADIUS_(defringe.radius, scale_factor); ADJUST_RADIUS_(sh.radius, scale_factor); + if (params.raw.xtranssensor.method == + procparams::RAWParams::XTransSensor::methodstring[ + procparams::RAWParams::XTransSensor::threePass]) { + params.raw.xtranssensor.method = + procparams::RAWParams::XTransSensor::methodstring[ + procparams::RAWParams::XTransSensor::onePass]; + } + #undef ADJUST_RADIUS_ } From f99da0c1ef5fe45a875402e6bc7c5f09047ec4d0 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Mon, 13 Mar 2017 16:39:10 +0100 Subject: [PATCH 11/18] use radio buttons to select between normal and custom pipeline for Fast Export as suggested by @michaelezra --- rtdata/languages/default | 5 +- rtgui/exportpanel.cc | 51 ++++++++++++++------ rtgui/exportpanel.h | 5 +- rtgui/filecatalog.cc | 102 +++++++++++++++++++-------------------- 4 files changed, 94 insertions(+), 69 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 7ae4d2165..35a10b6d7 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -89,7 +89,10 @@ EXPORT_BYPASS_SHARPENEDGE;Bypass Edge Sharpening EXPORT_BYPASS_SHARPENING;Bypass Sharpening EXPORT_BYPASS_SHARPENMICRO;Bypass Microcontrast EXPORT_BYPASS_SH_HQ;Bypass Sharp Mask Shadows/Highlights -EXPORT_USE_FAST_PIPELINE;Enable Special "Fast-Export" Processing Pipeline +EXPORT_PIPELINE;Processing pipeline +EXPORT_BYPASS;Processing steps to bypass +EXPORT_USE_NORMAL_PIPELINE;Standard (bypass some steps, resize at the end) +EXPORT_USE_FAST_PIPELINE;Dedicated (full processing on resized image) EXPORT_USE_FAST_PIPELINE_TIP;Use a dedicated processing pipeline for images in Fast Export mode, that trades speed for quality. Resizing of the image is done as early as possible, instead of doing it at the end like in the normal pipeline. The speedup can be significant, but be prepared to see artifacts and a general degradation of output quality. EXPORT_FASTEXPORTOPTIONS;Fast Export Options EXPORT_INSTRUCTIONS;Fast Export options provide overrides to bypass time and resource consuming development settings and to run queue processing using the fast export settings instead. This method is recommended for quicker generation of lower resolution images when speed is a priority or when resized output is desired for one or many images without making modifications to their saved development parameters. diff --git a/rtgui/exportpanel.cc b/rtgui/exportpanel.cc index fe18cdef7..53d93f8ba 100644 --- a/rtgui/exportpanel.cc +++ b/rtgui/exportpanel.cc @@ -38,8 +38,11 @@ ExportPanel::ExportPanel () : listener (nullptr) labExportTitle->set_alignment(Gtk::ALIGN_START); pack_start(*labExportTitle, Gtk::PACK_SHRINK, 4); + Gtk::RadioButton::Group pipeline_group; + use_fast_pipeline = Gtk::manage ( new Gtk::RadioButton (pipeline_group, M("EXPORT_USE_FAST_PIPELINE"))); + use_normal_pipeline = Gtk::manage ( new Gtk::RadioButton (pipeline_group, M("EXPORT_USE_NORMAL_PIPELINE"))); + bypass_box = Gtk::manage(new Gtk::VBox()); bypass_ALL = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_ALL"))); - use_fast_pipeline = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_USE_FAST_PIPELINE"))); use_fast_pipeline->set_tooltip_text(M("EXPORT_USE_FAST_PIPELINE_TIP")); bypass_sharpening = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENING"))); bypass_sharpenEdge = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENEDGE"))); @@ -98,19 +101,28 @@ ExportPanel::ExportPanel () : listener (nullptr) // ---------------------------------------------------------------- // start global packing + Gtk::HBox* lblbox = Gtk::manage (new Gtk::HBox ()); + lblbox->pack_start (*Gtk::manage (new Gtk::Label (M("EXPORT_PIPELINE"))), Gtk::PACK_SHRINK, 4); + pack_start (*lblbox, Gtk::PACK_SHRINK, 4); pack_start(*use_fast_pipeline , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_ALL , Gtk::PACK_SHRINK, 4); - pack_start(*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 4); - pack_start(*bypass_sharpening , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_sharpenEdge , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_sharpenMicro , Gtk::PACK_SHRINK, 4); + pack_start(*use_normal_pipeline , Gtk::PACK_SHRINK, 4); + + bypass_box->pack_start(*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 4); + lblbox = Gtk::manage (new Gtk::HBox ()); + lblbox->pack_start (*Gtk::manage (new Gtk::Label (M("EXPORT_BYPASS"))), Gtk::PACK_SHRINK, 4); + bypass_box->pack_start (*lblbox, Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_ALL , Gtk::PACK_SHRINK, 4); + // bypass_box->pack_start(*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_sharpening , Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_sharpenEdge , Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_sharpenMicro , Gtk::PACK_SHRINK, 4); //pack_start(*bypass_lumaDenoise , Gtk::PACK_SHRINK, 4); //pack_start(*bypass_colorDenoise , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_defringe , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_dirpyrDenoise, Gtk::PACK_SHRINK, 4); - pack_start(*bypass_sh_hq , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_dirpyrequalizer , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_wavelet , Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_defringe , Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_dirpyrDenoise, Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_sh_hq , Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_dirpyrequalizer , Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_wavelet , Gtk::PACK_SHRINK, 4); bayerFrameVBox->pack_start(*hb_raw_bayer_method, Gtk::PACK_SHRINK, 4); //bayerFrameVBox->pack_start(*bypass_raw_all_enhance , Gtk::PACK_SHRINK, 4); @@ -124,12 +136,14 @@ ExportPanel::ExportPanel () : listener (nullptr) xtransFrameVBox->pack_start(*hb_raw_xtrans_method, Gtk::PACK_SHRINK, 4); xtransFrame->add(*xtransFrameVBox); - pack_start(*bypass_raw_ccSteps , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_raw_ca , Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_raw_ccSteps , Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_raw_ca , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_raw_df , Gtk::PACK_SHRINK, 4); - pack_start(*bypass_raw_ff , Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_raw_df , Gtk::PACK_SHRINK, 4); + bypass_box->pack_start(*bypass_raw_ff , Gtk::PACK_SHRINK, 4); + pack_start(*bypass_box, Gtk::PACK_SHRINK); + pack_start (*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 2); // Resize options @@ -179,6 +193,7 @@ ExportPanel::ExportPanel () : listener (nullptr) pack_start(*vboxpe, Gtk::PACK_SHRINK, 0); + use_fast_pipeline->signal_toggled().connect(sigc::mem_fun(*this, &ExportPanel::use_fast_pipeline_toggled)); btnFastExport->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::FastExportPressed) ); //btnExportLoadSettings->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::LoadSettings) ); //btnExportSaveSettings->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::SaveSettings) ); @@ -347,6 +362,7 @@ void ExportPanel::LoadDefaultSettings() MaxHeight->set_value(options.fastexport_resize_height); use_fast_pipeline->set_active(options.fastexport_use_fast_pipeline); + bypass_box->set_sensitive(!options.fastexport_use_fast_pipeline); } void ExportPanel::LoadSettings() @@ -428,6 +444,11 @@ void ExportPanel::bypassALL_Toggled() bypass_raw_ffConn.block (false); } +void ExportPanel::use_fast_pipeline_toggled() +{ + bypass_box->set_sensitive(!use_fast_pipeline->get_active()); +} + /* fastexport_bypass_sharpening fastexport_bypass_sharpenEdge diff --git a/rtgui/exportpanel.h b/rtgui/exportpanel.h index ce7639921..db4431ca5 100644 --- a/rtgui/exportpanel.h +++ b/rtgui/exportpanel.h @@ -36,9 +36,11 @@ class ExportPanel : public Gtk::VBox protected: + Gtk::VBox *bypass_box; //Gtk::CheckButton* enabled; + Gtk::RadioButton* use_fast_pipeline; + Gtk::RadioButton* use_normal_pipeline; Gtk::CheckButton* bypass_ALL; - Gtk::CheckButton* use_fast_pipeline; Gtk::CheckButton* bypass_sharpenEdge; Gtk::CheckButton* bypass_sharpenMicro; Gtk::CheckButton* bypass_sharpening; @@ -106,6 +108,7 @@ protected: ExportPanelListener* listener; void bypassALL_Toggled(); + void use_fast_pipeline_toggled(); void SaveSettingsAsDefault(); void LoadDefaultSettings(); void LoadSettings(); diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index b9818a839..cdba10316 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1095,41 +1095,41 @@ void FileCatalog::developRequested (std::vector tbe, bool fas // and also those which effect is not pronounced after reducing the image size // TODO!!! could expose selections below via preferences if (fastmode) { - if (options.fastexport_bypass_sharpening ) { - params.sharpening.enabled = false; - } - - if (options.fastexport_bypass_sharpenEdge ) { - params.sharpenEdge.enabled = false; - } - - if (options.fastexport_bypass_sharpenMicro ) { - params.sharpenMicro.enabled = false; - } - - //if (options.fastexport_bypass_lumaDenoise ) params.lumaDenoise.enabled = false; - //if (options.fastexport_bypass_colorDenoise ) params.colorDenoise.enabled = false; - if (options.fastexport_bypass_defringe ) { - params.defringe.enabled = false; - } - - if (options.fastexport_bypass_dirpyrDenoise ) { - params.dirpyrDenoise.enabled = false; - } - - if (options.fastexport_bypass_sh_hq ) { - params.sh.hq = false; - } - - if (options.fastexport_bypass_dirpyrequalizer ) { - params.dirpyrequalizer.enabled = false; - } - - if (options.fastexport_bypass_wavelet ) { - params.wavelet.enabled = false; - } - if (!options.fastexport_use_fast_pipeline) { + if (options.fastexport_bypass_sharpening ) { + params.sharpening.enabled = false; + } + + if (options.fastexport_bypass_sharpenEdge ) { + params.sharpenEdge.enabled = false; + } + + if (options.fastexport_bypass_sharpenMicro ) { + params.sharpenMicro.enabled = false; + } + + //if (options.fastexport_bypass_lumaDenoise ) params.lumaDenoise.enabled = false; + //if (options.fastexport_bypass_colorDenoise ) params.colorDenoise.enabled = false; + if (options.fastexport_bypass_defringe ) { + params.defringe.enabled = false; + } + + if (options.fastexport_bypass_dirpyrDenoise ) { + params.dirpyrDenoise.enabled = false; + } + + if (options.fastexport_bypass_sh_hq ) { + params.sh.hq = false; + } + + if (options.fastexport_bypass_dirpyrequalizer ) { + params.dirpyrequalizer.enabled = false; + } + + if (options.fastexport_bypass_wavelet ) { + params.wavelet.enabled = false; + } + //if (options.fastexport_bypass_raw_bayer_all_enhance ) params.raw.bayersensor.all_enhance = false; if (options.fastexport_bypass_raw_bayer_dcb_iterations ) { params.raw.bayersensor.dcb_iterations = 0; @@ -1150,30 +1150,28 @@ void FileCatalog::developRequested (std::vector tbe, bool fas if (options.fastexport_bypass_raw_bayer_greenthresh ) { params.raw.bayersensor.greenthresh = 0; } - } - if (options.fastexport_bypass_raw_ccSteps ) { - params.raw.bayersensor.ccSteps = params.raw.xtranssensor.ccSteps = 0; - } + if (options.fastexport_bypass_raw_ccSteps ) { + params.raw.bayersensor.ccSteps = params.raw.xtranssensor.ccSteps = 0; + } - if (options.fastexport_bypass_raw_ca ) { - params.raw.ca_autocorrect = false; - params.raw.cared = 0; - params.raw.cablue = 0; - } + if (options.fastexport_bypass_raw_ca ) { + params.raw.ca_autocorrect = false; + params.raw.cared = 0; + params.raw.cablue = 0; + } - if (options.fastexport_bypass_raw_df ) { - params.raw.df_autoselect = false; - params.raw.dark_frame = ""; - } + if (options.fastexport_bypass_raw_df ) { + params.raw.df_autoselect = false; + params.raw.dark_frame = ""; + } - if (options.fastexport_bypass_raw_ff ) { - params.raw.ff_AutoSelect = false; - params.raw.ff_file = ""; - } + if (options.fastexport_bypass_raw_ff ) { + params.raw.ff_AutoSelect = false; + params.raw.ff_file = ""; + } - if (!options.fastexport_use_fast_pipeline) { params.raw.bayersensor.method = options.fastexport_raw_bayer_method ; params.raw.xtranssensor.method = options.fastexport_raw_xtrans_method; params.icm.input = options.fastexport_icm_input ; From a3adf8fb07fdd2dd46f5e1b4ea65427f9c968a46 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 14 Mar 2017 11:48:51 +0100 Subject: [PATCH 12/18] code cleanup after feedback by @Floessie --- rtengine/rtengine.h | 1 + rtengine/simpleprocess.cc | 71 +++++++++++++--------------- rtgui/filecatalog.cc | 97 +++++++++++++++++++-------------------- 3 files changed, 81 insertions(+), 88 deletions(-) diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 7449dbd0d..4a87414b8 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -461,6 +461,7 @@ class ProcessingJob { public: + virtual ~ProcessingJob() {} /** Creates a processing job from a file name. This function always succeeds. It only stores the data into the ProcessingJob class, it does not load * the image thus it returns immediately. diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index fd06df66b..4a6c7a695 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -37,6 +37,14 @@ extern const Settings* settings; namespace { +template +void adjust_radius(const T &default_param, double scale_factor, T ¶m) +{ + const double delta = (param - default_param) * scale_factor; + param = default_param + delta; +} + + class ImageProcessor { public: ImageProcessor(ProcessingJob* pjob, int& errorCode, @@ -1338,20 +1346,18 @@ private: ImProcFunctions ipf (¶ms, true); int imw, imh; - double tmpScale = ipf.resizeScale(¶ms, fw, fh, imw, imh); + double scale_factor = ipf.resizeScale(¶ms, fw, fh, imw, imh); - LabImage *tmplab = new LabImage(fw, fh); + std::unique_ptr tmplab(new LabImage(fw, fh)); ipf.rgb2lab(*baseImg, *tmplab, params.icm.working); - int cx = 0, cy = 0, cw = fw, ch = fh; - if (params.crop.enabled) { - cx = params.crop.x; - cy = params.crop.y; - cw = params.crop.w; - ch = params.crop.h; + int cx = params.crop.x; + int cy = params.crop.y; + int cw = params.crop.w; + int ch = params.crop.h; - LabImage *cropped = new LabImage(cw, ch); + std::unique_ptr cropped(new LabImage(cw, ch)); for(int row = 0; row < ch; row++) { for(int col = 0; col < cw; col++) { @@ -1361,23 +1367,20 @@ private: } } - delete tmplab; - tmplab = cropped; - cx = 0; - cy = 0; - + tmplab.swap(cropped); params.crop.enabled = false; } assert(params.resize.enabled); // resize image - LabImage *resized = new LabImage(imw, imh); - ipf.Lanczos(tmplab, resized, tmpScale); - delete tmplab; - tmplab = resized; + { + std::unique_ptr resized(new LabImage(imw, imh)); + ipf.Lanczos(tmplab.get(), resized.get(), scale_factor); + tmplab.swap(resized); + } - adjust_procparams(tmpScale); + adjust_procparams(scale_factor); fw = imw; fh = imh; @@ -1385,34 +1388,26 @@ private: delete baseImg; baseImg = new Imagefloat(fw, fh); ipf.lab2rgb(*tmplab, *baseImg, params.icm.working); - delete tmplab; } void adjust_procparams(double scale_factor) { - procparams::ProcParams& params = job->pparams; + procparams::ProcParams ¶ms = job->pparams; procparams::ProcParams defaultparams; -#define ADJUST_RADIUS_(n, f) \ - do { \ - auto delta = (params. n - defaultparams. n) * f; \ - params. n = defaultparams. n + delta; \ - } while (false) - params.resize.enabled = false; if (params.prsharpening.enabled) { params.sharpening = params.prsharpening; } else { - ADJUST_RADIUS_(sharpening.radius, scale_factor); + adjust_radius(defaultparams.sharpening.radius, scale_factor, + params.sharpening.radius); } - params.impulseDenoise.thresh = - int(float(params.impulseDenoise.thresh) * scale_factor); + params.impulseDenoise.thresh *= scale_factor; if (scale_factor < 0.5) { params.impulseDenoise.enabled = false; } - params.wavelet.strength = - int(float(params.wavelet.strength) * scale_factor); + params.wavelet.strength *= scale_factor; params.dirpyrDenoise.luma *= scale_factor; //params.dirpyrDenoise.smethod = "shal"; for (auto &p : params.dirpyrDenoise.lcurve) { @@ -1427,13 +1422,13 @@ private: const double dirpyreq_scale = min(scale_factor * 1.5, 1.0); for (int i = 0; i < 6; ++i) { - ADJUST_RADIUS_(dirpyrequalizer.mult[i], dirpyreq_scale); - // auto &n = params.dirpyrequalizer.mult[i]; - // n = 1.0 + (n - 1.0) * dirpyreq_scale; + adjust_radius(defaultparams.dirpyrequalizer.mult[i], dirpyreq_scale, + params.dirpyrequalizer.mult[i]); } - ADJUST_RADIUS_(defringe.radius, scale_factor); - ADJUST_RADIUS_(sh.radius, scale_factor); + adjust_radius(defaultparams.defringe.radius, scale_factor, + params.defringe.radius); + adjust_radius(defaultparams.sh.radius, scale_factor, params.sh.radius); if (params.raw.xtranssensor.method == procparams::RAWParams::XTransSensor::methodstring[ @@ -1442,8 +1437,6 @@ private: procparams::RAWParams::XTransSensor::methodstring[ procparams::RAWParams::XTransSensor::onePass]; } - -#undef ADJUST_RADIUS_ } private: diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index cdba10316..96a04ba0b 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1096,105 +1096,104 @@ void FileCatalog::developRequested (std::vector tbe, bool fas // TODO!!! could expose selections below via preferences if (fastmode) { if (!options.fastexport_use_fast_pipeline) { - if (options.fastexport_bypass_sharpening ) { - params.sharpening.enabled = false; + if (options.fastexport_bypass_sharpening) { + params.sharpening.enabled = false; } - if (options.fastexport_bypass_sharpenEdge ) { - params.sharpenEdge.enabled = false; + if (options.fastexport_bypass_sharpenEdge) { + params.sharpenEdge.enabled = false; } - if (options.fastexport_bypass_sharpenMicro ) { - params.sharpenMicro.enabled = false; + if (options.fastexport_bypass_sharpenMicro) { + params.sharpenMicro.enabled = false; } - //if (options.fastexport_bypass_lumaDenoise ) params.lumaDenoise.enabled = false; - //if (options.fastexport_bypass_colorDenoise ) params.colorDenoise.enabled = false; - if (options.fastexport_bypass_defringe ) { - params.defringe.enabled = false; + //if (options.fastexport_bypass_lumaDenoise) params.lumaDenoise.enabled = false; + //if (options.fastexport_bypass_colorDenoise) params.colorDenoise.enabled = false; + if (options.fastexport_bypass_defringe) { + params.defringe.enabled = false; } - if (options.fastexport_bypass_dirpyrDenoise ) { - params.dirpyrDenoise.enabled = false; + if (options.fastexport_bypass_dirpyrDenoise) { + params.dirpyrDenoise.enabled = false; } - if (options.fastexport_bypass_sh_hq ) { - params.sh.hq = false; + if (options.fastexport_bypass_sh_hq) { + params.sh.hq = false; } - if (options.fastexport_bypass_dirpyrequalizer ) { - params.dirpyrequalizer.enabled = false; + if (options.fastexport_bypass_dirpyrequalizer) { + params.dirpyrequalizer.enabled = false; } - if (options.fastexport_bypass_wavelet ) { - params.wavelet.enabled = false; + if (options.fastexport_bypass_wavelet) { + params.wavelet.enabled = false; } - //if (options.fastexport_bypass_raw_bayer_all_enhance ) params.raw.bayersensor.all_enhance = false; - if (options.fastexport_bypass_raw_bayer_dcb_iterations ) { - params.raw.bayersensor.dcb_iterations = 0; + //if (options.fastexport_bypass_raw_bayer_all_enhance) params.raw.bayersensor.all_enhance = false; + if (options.fastexport_bypass_raw_bayer_dcb_iterations) { + params.raw.bayersensor.dcb_iterations = 0; } - if (options.fastexport_bypass_raw_bayer_dcb_enhance ) { - params.raw.bayersensor.dcb_enhance = false; + if (options.fastexport_bypass_raw_bayer_dcb_enhance) { + params.raw.bayersensor.dcb_enhance = false; } if (options.fastexport_bypass_raw_bayer_lmmse_iterations) { - params.raw.bayersensor.lmmse_iterations = 0; + params.raw.bayersensor.lmmse_iterations = 0; } - if (options.fastexport_bypass_raw_bayer_linenoise ) { - params.raw.bayersensor.linenoise = 0; + if (options.fastexport_bypass_raw_bayer_linenoise) { + params.raw.bayersensor.linenoise = 0; } - if (options.fastexport_bypass_raw_bayer_greenthresh ) { - params.raw.bayersensor.greenthresh = 0; + if (options.fastexport_bypass_raw_bayer_greenthresh) { + params.raw.bayersensor.greenthresh = 0; } - if (options.fastexport_bypass_raw_ccSteps ) { + if (options.fastexport_bypass_raw_ccSteps) { params.raw.bayersensor.ccSteps = params.raw.xtranssensor.ccSteps = 0; } - if (options.fastexport_bypass_raw_ca ) { + if (options.fastexport_bypass_raw_ca) { params.raw.ca_autocorrect = false; params.raw.cared = 0; params.raw.cablue = 0; } - if (options.fastexport_bypass_raw_df ) { - params.raw.df_autoselect = false; + if (options.fastexport_bypass_raw_df) { + params.raw.df_autoselect = false; params.raw.dark_frame = ""; } - if (options.fastexport_bypass_raw_ff ) { - params.raw.ff_AutoSelect = false; + if (options.fastexport_bypass_raw_ff) { + params.raw.ff_AutoSelect = false; params.raw.ff_file = ""; } - - params.raw.bayersensor.method = options.fastexport_raw_bayer_method ; + params.raw.bayersensor.method = options.fastexport_raw_bayer_method; params.raw.xtranssensor.method = options.fastexport_raw_xtrans_method; - params.icm.input = options.fastexport_icm_input ; - params.icm.working = options.fastexport_icm_working ; - params.icm.output = options.fastexport_icm_output ; - params.icm.outputIntent = options.fastexport_icm_outputIntent ; - params.icm.outputBPC = options.fastexport_icm_outputBPC ; - params.icm.gamma = options.fastexport_icm_gamma ; + params.icm.input = options.fastexport_icm_input; + params.icm.working = options.fastexport_icm_working; + params.icm.output = options.fastexport_icm_output; + params.icm.outputIntent = options.fastexport_icm_outputIntent; + params.icm.outputBPC = options.fastexport_icm_outputBPC; + params.icm.gamma = options.fastexport_icm_gamma; } if (params.resize.enabled) { - params.resize.width = rtengine::min(params.resize.width, options.fastexport_resize_width) ; - params.resize.height = rtengine::min(params.resize.height, options.fastexport_resize_height) ; + params.resize.width = rtengine::min(params.resize.width, options.fastexport_resize_width); + params.resize.height = rtengine::min(params.resize.height, options.fastexport_resize_height); } else { params.resize.width = options.fastexport_resize_width; params.resize.height = options.fastexport_resize_height; } - params.resize.enabled = options.fastexport_resize_enabled ; - params.resize.scale = options.fastexport_resize_scale ; - params.resize.appliesTo = options.fastexport_resize_appliesTo ; - params.resize.method = options.fastexport_resize_method ; - params.resize.dataspec = options.fastexport_resize_dataspec ; + params.resize.enabled = options.fastexport_resize_enabled; + params.resize.scale = options.fastexport_resize_scale; + params.resize.appliesTo = options.fastexport_resize_appliesTo; + params.resize.method = options.fastexport_resize_method; + params.resize.dataspec = options.fastexport_resize_dataspec; } rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode && options.fastexport_use_fast_pipeline); From 656fe0a022700bffacff26991da1f386799617e5 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 14 Mar 2017 15:13:16 +0100 Subject: [PATCH 13/18] use move assignment instead of std::unique_ptr::swap (better readability) --- rtengine/simpleprocess.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 4a6c7a695..1315fb061 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1367,7 +1367,7 @@ private: } } - tmplab.swap(cropped); + tmplab = std::move(cropped); params.crop.enabled = false; } @@ -1377,7 +1377,7 @@ private: { std::unique_ptr resized(new LabImage(imw, imh)); ipf.Lanczos(tmplab.get(), resized.get(), scale_factor); - tmplab.swap(resized); + tmplab = std::move(resized); } adjust_procparams(scale_factor); From 416fc6c92f8fea41fc9f2a12e0805c0b13b0251d Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 15 Mar 2017 09:12:09 +0100 Subject: [PATCH 14/18] move all procparams tweaks to adjust_procparams `params.crop.enabled=false` was still in `stage_early_resize` --- rtengine/simpleprocess.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 1315fb061..9fe4ca731 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1368,7 +1368,6 @@ private: } tmplab = std::move(cropped); - params.crop.enabled = false; } assert(params.resize.enabled); @@ -1396,6 +1395,7 @@ private: procparams::ProcParams defaultparams; params.resize.enabled = false; + params.crop.enabled = false; if (params.prsharpening.enabled) { params.sharpening = params.prsharpening; From 83c6453b4492187ee0aeb1897f52d5c2e556dc4f Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 15 Mar 2017 14:04:03 +0100 Subject: [PATCH 15/18] minor tweaking to the tonemapping procparams in fast export mode --- rtengine/simpleprocess.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 9fe4ca731..bd8dc0e23 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1418,7 +1418,7 @@ private: } params.epd.scale *= scale_factor; - params.epd.edgeStopping *= scale_factor; + //params.epd.edgeStopping *= scale_factor; const double dirpyreq_scale = min(scale_factor * 1.5, 1.0); for (int i = 0; i < 6; ++i) { From c8a6253e432c3f5c8d1a58a51ff628d12c4d82aa Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 16 Mar 2017 09:06:47 +0100 Subject: [PATCH 16/18] save fast export options also when clicking on the "fast export" menu item --- rtgui/filebrowser.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 24d1d8541..70c019942 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -768,6 +768,12 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) else if (m == develop) { tbl->developRequested (mselected, false); } else if (m == developfast) { + if (exportPanel) { + // force saving export panel settings + exportPanel->setExportPanelListener(nullptr); + exportPanel->FastExportPressed(); + exportPanel->setExportPanelListener(this); + } tbl->developRequested (mselected, true); } From f5798946ef708e0f4b35cd8e09882da257e4f1ce Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 16 Mar 2017 11:43:37 +0100 Subject: [PATCH 17/18] fixed bug in disabling the "bypass" checkboxes when fast export is selected --- rtgui/exportpanel.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rtgui/exportpanel.cc b/rtgui/exportpanel.cc index 53d93f8ba..72cf30fdd 100644 --- a/rtgui/exportpanel.cc +++ b/rtgui/exportpanel.cc @@ -361,8 +361,12 @@ void ExportPanel::LoadDefaultSettings() MaxWidth->set_value(options.fastexport_resize_width); MaxHeight->set_value(options.fastexport_resize_height); - use_fast_pipeline->set_active(options.fastexport_use_fast_pipeline); - bypass_box->set_sensitive(!options.fastexport_use_fast_pipeline); + if (options.fastexport_use_fast_pipeline) { + use_fast_pipeline->set_active(true); + bypass_box->set_sensitive(false); + } else { + use_normal_pipeline->set_active(true); + } } void ExportPanel::LoadSettings() From 8bfe14da09b68e83264bdbb75e33e6a952bc7c64 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Tue, 28 Mar 2017 08:35:06 +0200 Subject: [PATCH 18/18] do not touch the chroma denoise curve in the fast export pipeline (no need to) --- rtengine/simpleprocess.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 360b892c4..c49535a3c 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1414,9 +1414,6 @@ private: for (auto &p : params.dirpyrDenoise.lcurve) { p *= scale_factor; } - for (auto &p : params.dirpyrDenoise.cccurve) { - p *= scale_factor; - } params.epd.scale *= scale_factor; //params.epd.edgeStopping *= scale_factor;