diff --git a/rtdata/languages/default b/rtdata/languages/default index 9aa743ab0..ba96a43cb 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -726,6 +726,7 @@ HISTORY_MSG_490;DRC - Amount HISTORY_MSG_491;White Balance HISTORY_MSG_492;RGB Curves HISTORY_MSG_493;L*a*b* Adjustments +HISTORY_MSG_494;Capture Sharpening HISTORY_MSG_CLAMPOOG;Clip out-of-gamut colors HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction HISTORY_MSG_COLORTONING_LABREGION_AB;CT - Color correction @@ -764,7 +765,6 @@ HISTORY_MSG_LOCALCONTRAST_RADIUS;Local Contrast - Radius HISTORY_MSG_METADATA_MODE;Metadata copy mode HISTORY_MSG_MICROCONTRAST_CONTRAST;Microcontrast - Contrast threshold HISTORY_MSG_PDSHARPEN_CONTRAST;CAS - Contrast threshold -HISTORY_MSG_PDSHARPEN_ENABLED;Capture Sharpening HISTORY_MSG_PDSHARPEN_GAMMA;CAS - Gamma HISTORY_MSG_PDSHARPEN_ITERATIONS;CAS - Iterations HISTORY_MSG_PDSHARPEN_RADIUS;CAS - Radius diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 6e57bd532..006fe59a6 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -182,7 +182,7 @@ public: return this; } virtual void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) = 0; - virtual void captureSharpening(const procparams::SharpeningParams &sharpeningParams) = 0; + virtual void captureSharpening(const procparams::SharpeningParams &sharpeningParams, bool showMask) = 0; }; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 2e2ae9084..29d56e79e 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -53,6 +53,7 @@ ImProcCoordinator::ImProcCoordinator() : softProof(false), gamutCheck(false), sharpMask(false), + sharpMaskChanged(false), scale(10), highDetailPreprocessComputed(false), highDetailRawComputed(false), @@ -333,7 +334,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) imgsrc->demosaic(rp, autoContrast, contrastThreshold); //enabled demosaic if (params->pdsharpening.enabled) { - imgsrc->captureSharpening(params->pdsharpening); + imgsrc->captureSharpening(params->pdsharpening, sharpMask); } if (imgsrc->getSensorType() == ST_BAYER && bayerAutoContrastListener && autoContrast) { bayerAutoContrastListener->autoContrastChanged(autoContrast ? contrastThreshold : -1.0); @@ -1347,9 +1348,16 @@ void ImProcCoordinator::getSoftProofing(bool &softProof, bool &gamutCheck) gamutCheck = this->gamutCheck; } -void ImProcCoordinator::setSharpMask (bool sharpMask) +ProcEvent ImProcCoordinator::setSharpMask (bool sharpMask) { - this->sharpMask = sharpMask; + if (this->sharpMask != sharpMask) { + sharpMaskChanged = true; + this->sharpMask = sharpMask; + return params->pdsharpening.enabled ? rtengine::EvPdShrEnabled : rtengine::EvShrEnabled; + } else { + sharpMaskChanged = false; + return rtengine::EvShrEnabled; + } } void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool apply_wb) @@ -1550,8 +1558,10 @@ void ImProcCoordinator::process() || params->wavelet != nextParams->wavelet || params->dirpyrequalizer != nextParams->dirpyrequalizer || params->dehaze != nextParams->dehaze - || params->pdsharpening != nextParams->pdsharpening; + || params->pdsharpening != nextParams->pdsharpening + || sharpMaskChanged; + sharpMaskChanged = false; *params = *nextParams; int change = changeSinceLast; changeSinceLast = 0; diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index fdf74d297..0315bc180 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -77,7 +77,7 @@ protected: bool softProof; bool gamutCheck; bool sharpMask; - + bool sharpMaskChanged; int scale; bool highDetailPreprocessComputed; bool highDetailRawComputed; @@ -277,7 +277,7 @@ public: void getMonitorProfile (Glib::ustring& profile, RenderingIntent& intent) const override; void setSoftProofing (bool softProof, bool gamutCheck) override; void getSoftProofing (bool &softProof, bool &gamutCheck) override; - void setSharpMask (bool sharpMask) override; + ProcEvent setSharpMask (bool sharpMask) override; bool updateTryLock () override { return updaterThreadStart.trylock(); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 65f0f5a96..6fe8a785d 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -248,7 +248,7 @@ public: void Lanczos(const LabImage* src, LabImage* dst, float scale); void Lanczos(const Imagefloat* src, Imagefloat* dst, float scale); - void deconvsharpening(float** luminance, float** buffer, int W, int H, const procparams::SharpeningParams &sharpenParam, double Scale); + void deconvsharpening(float** luminance, float** buffer, float** blend, int W, int H, const procparams::SharpeningParams &sharpenParam, double Scale); void MLsharpen(LabImage* lab); // Manuel's clarity / sharpening void MLmicrocontrast(float** luminance, int W, int H); //Manuel's microcontrast void MLmicrocontrast(LabImage* lab); //Manuel's microcontrast diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index eeda786a5..897aaf7b5 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -158,7 +158,7 @@ namespace rtengine extern const Settings* settings; -void ImProcFunctions::deconvsharpening (float** luminance, float** tmp, int W, int H, const SharpeningParams &sharpenParam, double Scale) +void ImProcFunctions::deconvsharpening (float** luminance, float** tmp, float ** blend, int W, int H, const SharpeningParams &sharpenParam, double Scale) { if (sharpenParam.deconvamount == 0 && sharpenParam.blurradius < 0.25f) { return; @@ -175,10 +175,6 @@ BENCHFUN } } - // calculate contrast based blend factors to reduce sharpening in regions with low contrast - JaggedArray blend(W, H); - float contrast = sharpenParam.contrast / 100.f; - buildBlendMask(luminance, blend, W, H, contrast, 1.f); JaggedArray* blurbuffer = nullptr; if (sharpenParam.blurradius >= 0.25f) { @@ -254,11 +250,12 @@ void ImProcFunctions::sharpening (LabImage* lab, const SharpeningParams &sharpen int W = lab->W, H = lab->H; + // calculate contrast based blend factors to reduce sharpening in regions with low contrast + JaggedArray blend(W, H); + float contrast = sharpenParam.contrast / 100.f; + buildBlendMask(lab->L, blend, W, H, contrast, 1.f); + if(showMask) { - // calculate contrast based blend factors to reduce sharpening in regions with low contrast - JaggedArray blend(W, H); - float contrast = sharpenParam.contrast / 100.f; - buildBlendMask(lab->L, blend, W, H, contrast, 1.f); #ifdef _OPENMP #pragma omp parallel for #endif @@ -274,7 +271,7 @@ void ImProcFunctions::sharpening (LabImage* lab, const SharpeningParams &sharpen JaggedArray b2(W, H); if (sharpenParam.method == "rld") { - deconvsharpening (lab->L, b2, lab->W, lab->H, sharpenParam, scale); + deconvsharpening (lab->L, b2, blend, lab->W, lab->H, sharpenParam, scale); return; } BENCHFUN @@ -290,11 +287,6 @@ BENCHFUN } } - // calculate contrast based blend factors to reduce sharpening in regions with low contrast - JaggedArray blend(W, H); - float contrast = sharpenParam.contrast / 100.f; - buildBlendMask(lab->L, blend, W, H, contrast); - JaggedArray blur(W, H); if (sharpenParam.blurradius >= 0.25f) { @@ -886,11 +878,11 @@ void ImProcFunctions::sharpeningcam (CieImage* ncie, float** b2, bool showMask) int W = ncie->W, H = ncie->H; + // calculate contrast based blend factors to reduce sharpening in regions with low contrast + JaggedArray blend(W, H); + float contrast = params->sharpening.contrast / 100.f; + buildBlendMask(ncie->sh_p, blend, W, H, contrast); if(showMask) { - // calculate contrast based blend factors to reduce sharpening in regions with low contrast - JaggedArray blend(W, H); - float contrast = params->sharpening.contrast / 100.f; - buildBlendMask(ncie->sh_p, blend, W, H, contrast); #ifdef _OPENMP #pragma omp parallel for #endif @@ -903,9 +895,8 @@ void ImProcFunctions::sharpeningcam (CieImage* ncie, float** b2, bool showMask) return; } - if (params->sharpening.method == "rld") { - deconvsharpening (ncie->sh_p, b2, ncie->W, ncie->H, params->sharpening, scale); + deconvsharpening (ncie->sh_p, b2, blend, ncie->W, ncie->H, params->sharpening, scale); return; } @@ -921,11 +912,6 @@ void ImProcFunctions::sharpeningcam (CieImage* ncie, float** b2, bool showMask) } } - // calculate contrast based blend factors to reduce sharpening in regions with low contrast - JaggedArray blend(W, H); - float contrast = params->sharpening.contrast / 100.f; - buildBlendMask(ncie->sh_p, blend, W, H, contrast); - #ifdef _OPENMP #pragma omp parallel #endif diff --git a/rtengine/procevents.h b/rtengine/procevents.h index bb6a30038..670c0c102 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -520,7 +520,7 @@ enum ProcEventCode { EvWBEnabled = 490, EvRGBEnabled = 491, EvLEnabled = 492, -// EvPixelShiftOneGreen = 493, can be reused + EvPdShrEnabled = 493, NUMOFEVENTS diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 4f2cdce2e..e1e66d99c 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2790,9 +2790,9 @@ void ProcParams::setDefaults() prsharpening.deconvdamping = 0; pdsharpening = {}; - pdsharpening.contrast = 0.0; + pdsharpening.contrast = 10.0; prsharpening.method = "rld"; - pdsharpening.gamma = 1.0; + pdsharpening.gamma = 1.35; pdsharpening.deconvradius = 0.75; pdsharpening.deconviter = 30; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 5d8dd8448..96f161d9f 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -38,6 +38,7 @@ #include "camconst.h" #include "procparams.h" #include "color.h" +#include "rt_algo.h" #define BENCHMARK #include "StopWatch.h" #ifdef _OPENMP @@ -4952,26 +4953,65 @@ void RawImageSource::getRawValues(int x, int y, int rotate, int &R, int &G, int } } -void RawImageSource::captureSharpening(const procparams::SharpeningParams &sharpeningParams) { +void RawImageSource::captureSharpening(const procparams::SharpeningParams &sharpeningParams, bool showMask) { BENCHFUN - array2D Y(W,H); - array2D Cb(W,H); - array2D Cr(W,H); + const float xyz_rgb[3][3] = { // XYZ from RGB + { 0.412453, 0.357580, 0.180423 }, + { 0.212671, 0.715160, 0.072169 }, + { 0.019334, 0.119193, 0.950227 } + }; + + float contrast = sharpeningParams.contrast / 100.f; + + if (showMask) { + StopWatch Stop1("Show mask"); + array2D& L = blue; // blue will be overridden anyway => we can use its buffer to store L +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = 0; i < H; ++i) { + Color::RGB2L(red[i], green[i], blue[i], L[i], xyz_rgb, W); + } + array2D& blend = red; // red will be overridden anyway => we can use its buffer to store the blend mask + buildBlendMask(L, blend, W, H, contrast, 1.f); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < H; ++i) { + for (int j = 0; j < W; ++j) { + red[i][j] = green[i][j] = blue[i][j] = blend[i][j] * 16384.f; + } + } + return; + } + + array2D L(W,H); + array2D& Y = red; // red will be overridden anyway => we can use its buffer to store Y + array2D& Cb = green; // green will be overridden anyway => we can use its buffer to store Cb + array2D& Cr = blue; // blue will be overridden anyway => we can use its buffer to store Cr const float gamma = sharpeningParams.gamma; + StopWatch Stop1("rgb2Y"); #pragma omp parallel for for (int i = 0; i < H; ++i) { - for (int j = 0; j < W ; ++j) { + Color::RGB2L(red[i], green[i], blue[i], L[i], xyz_rgb, W); + for (int j = 0; j < W; ++j) { Color::RGB2YCbCr(std::max(red[i][j], 0.f), std::max(green[i][j], 0.f), std::max(blue[i][j], 0.f), Y[i][j], Cb[i][j], Cr[i][j]); Y[i][j] = pow_F(Y[i][j], 1.f / gamma); } } + // calculate contrast based blend factors to reduce sharpening in regions with low contrast + JaggedArray blend(W, H); + buildBlendMask(L, blend, W, H, contrast, 1.f); + Stop1.stop(); - array2D tmp(W, H); + array2D& tmp = L; // L is not used anymore now => we can use its buffer as the needed temporary buffer ProcParams dummy; ImProcFunctions ipf(&dummy); - ipf.deconvsharpening(Y, tmp, W, H, sharpeningParams, 1.0); + ipf.deconvsharpening(Y, tmp, blend, W, H, sharpeningParams, 1.0); StopWatch Stop2("Y2RGB"); #pragma omp parallel for for (int i = 0; i < H; ++i) { @@ -4982,6 +5022,7 @@ BENCHFUN } Stop2.stop(); } + void RawImageSource::cleanup () { delete phaseOneIccCurve; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 7b86111af..a7aee0843 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -305,7 +305,7 @@ protected: void hflip (Imagefloat* im); void vflip (Imagefloat* im); void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override; - void captureSharpening(const procparams::SharpeningParams &sharpeningParams) override; + void captureSharpening(const procparams::SharpeningParams &sharpeningParams, bool showMask) override; }; } diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index d741b1744..8282f5b4b 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -519,7 +519,9 @@ int refreshmap[rtengine::NUMOFEVENTS] = { HDR, // EvTMFattalAmount ALLNORAW, // EvWBEnabled RGBCURVE, // EvRGBEnabled - LUMINANCECURVE // EvLEnabled + LUMINANCECURVE, // EvLEnabled + DEMOSAIC // EvPdShrEnabled + }; diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index f772975b0..ca4cebe2e 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -535,7 +535,7 @@ public: virtual void getMonitorProfile (Glib::ustring& monitorProfile, RenderingIntent& intent) const = 0; virtual void setSoftProofing (bool softProof, bool gamutCheck) = 0; virtual void getSoftProofing (bool &softProof, bool &gamutCheck) = 0; - virtual void setSharpMask (bool sharpMask) = 0; + virtual ProcEvent setSharpMask (bool sharpMask) = 0; virtual ~StagedImageProcessor () {} diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index a9d32dbac..24a3f3263 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -222,7 +222,7 @@ private: imgsrc->demosaic (params.raw, autoContrast, contrastThreshold); if (params.pdsharpening.enabled) { - imgsrc->captureSharpening(params.pdsharpening); + imgsrc->captureSharpening(params.pdsharpening, false); } diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index a8251ade0..5acb8d113 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -102,7 +102,7 @@ public: void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override { R = G = B = 0;} void flushRGB () override; - void captureSharpening(const procparams::SharpeningParams &sharpeningParams) override {}; + void captureSharpening(const procparams::SharpeningParams &sharpeningParams, bool showMask) override {}; }; } #endif diff --git a/rtgui/pdsharpening.cc b/rtgui/pdsharpening.cc index a33da813d..896d416b5 100644 --- a/rtgui/pdsharpening.cc +++ b/rtgui/pdsharpening.cc @@ -19,6 +19,7 @@ #include #include "eventmapper.h" #include "pdsharpening.h" +#include "options.h" using namespace rtengine; using namespace rtengine::procparams; @@ -27,7 +28,6 @@ PdSharpening::PdSharpening () : FoldableToolPanel(this, "pdsharpening", M("TP_PD { auto m = ProcEventMapper::getInstance(); - EvPdShrEnabled = m->newEvent(DEMOSAIC, "HISTORY_MSG_PDSHARPEN_ENABLED"); EvPdShrContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_PDSHARPEN_CONTRAST"); EvPdSharpenGamma = m->newEvent(DEMOSAIC, "HISTORY_MSG_PDSHARPEN_GAMMA"); EvPdShrDRadius = m->newEvent(DEMOSAIC, "HISTORY_MSG_PDSHARPEN_RADIUS"); @@ -35,7 +35,7 @@ PdSharpening::PdSharpening () : FoldableToolPanel(this, "pdsharpening", M("TP_PD Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ()); hb->show (); - contrast = Gtk::manage(new Adjuster (M("TP_SHARPENING_CONTRAST"), 0, 200, 1, 15)); + contrast = Gtk::manage(new Adjuster (M("TP_SHARPENING_CONTRAST"), 0, 200, 1, 10)); contrast->setAdjusterListener (this); pack_start(*contrast); contrast->show(); @@ -43,7 +43,7 @@ PdSharpening::PdSharpening () : FoldableToolPanel(this, "pdsharpening", M("TP_PD pack_start (*hb); rld = new Gtk::VBox (); - gamma = Gtk::manage (new Adjuster (M("TP_SHARPENING_GAMMA"), 0.5, 3.0, 0.05, 1.0)); + gamma = Gtk::manage (new Adjuster (M("TP_SHARPENING_GAMMA"), 0.5, 3.0, 0.05, 1.35)); dradius = Gtk::manage (new Adjuster (M("TP_SHARPENING_EDRADIUS"), 0.4, 2.5, 0.01, 0.75)); diter = Gtk::manage (new Adjuster (M("TP_SHARPENING_RLD_ITERATIONS"), 5, 100, 1, 30)); rld->pack_start (*gamma); @@ -59,6 +59,19 @@ PdSharpening::PdSharpening () : FoldableToolPanel(this, "pdsharpening", M("TP_PD gamma->setAdjusterListener (this); diter->setAdjusterListener (this); + if (contrast->delay < options.adjusterMaxDelay) { + contrast->delay = options.adjusterMaxDelay; + } + if (dradius->delay < options.adjusterMaxDelay) { + dradius->delay = options.adjusterMaxDelay; + } + if (gamma->delay < options.adjusterMaxDelay) { + gamma->delay = options.adjusterMaxDelay; + } + if (diter->delay < options.adjusterMaxDelay) { + diter->delay = options.adjusterMaxDelay; + } + rld->reference(); } diff --git a/rtgui/pdsharpening.h b/rtgui/pdsharpening.h index 998322fe4..fe9359349 100644 --- a/rtgui/pdsharpening.h +++ b/rtgui/pdsharpening.h @@ -33,7 +33,6 @@ protected: Adjuster* diter; Gtk::VBox* rld; - rtengine::ProcEvent EvPdShrEnabled; rtengine::ProcEvent EvPdShrContrast; rtengine::ProcEvent EvPdShrDRadius; rtengine::ProcEvent EvPdSharpenGamma; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 64e44b3fb..93f45aefe 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -695,8 +695,7 @@ void ToolPanelCoordinator::sharpMaskSelected(bool sharpMask) return; } ipc->beginUpdateParams (); - ipc->setSharpMask(sharpMask); - ipc->endUpdateParams (rtengine::EvShrEnabled); + ipc->endUpdateParams (ipc->setSharpMask(sharpMask)); } int ToolPanelCoordinator::getSpotWBRectSize() const