From f2cdbd0e4dabc1878f36a6b35c88132b8c561901 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Mon, 16 Sep 2019 15:09:47 +0200 Subject: [PATCH] Capture sharpening: experimental radius offset depending on distance to center --- rtdata/languages/default | 1 + rtengine/capturesharpening.cc | 30 ++++++++++++++++++++++-------- rtengine/procparams.cc | 4 ++++ rtengine/procparams.h | 1 + rtgui/paramsedited.cc | 8 +++++++- rtgui/paramsedited.h | 1 + rtgui/pdsharpening.cc | 22 ++++++++++++++++++++-- rtgui/pdsharpening.h | 2 ++ 8 files changed, 58 insertions(+), 11 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 3749a706a..be1638e8e 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2037,6 +2037,7 @@ TP_SHARPENING_LABEL;Sharpening TP_SHARPENING_METHOD;Method TP_SHARPENING_ONLYEDGES;Sharpen only edges TP_SHARPENING_RADIUS;Radius +TP_SHARPENING_RADIUS_OFFSET;Radius corner offset TP_SHARPENING_RLD;RL Deconvolution TP_SHARPENING_RLD_AMOUNT;Amount TP_SHARPENING_RLD_DAMPING;Damping diff --git a/rtengine/capturesharpening.cc b/rtengine/capturesharpening.cc index df2b1d908..e08243713 100644 --- a/rtengine/capturesharpening.cc +++ b/rtengine/capturesharpening.cc @@ -513,11 +513,11 @@ float calcRadiusXtrans(const float * const *rawData, int W, int H, float lowerLi } return std::sqrt((1.f / (std::log(1.f / maxRatio))) / -2.f); } -void CaptureDeconvSharpening (float** luminance, float** oldLuminance, const float * const * blend, int W, int H, double sigma, int iterations, rtengine::ProgressListener* plistener, double startVal, double endVal) +void CaptureDeconvSharpening (float** luminance, float** oldLuminance, const float * const * blend, int W, int H, double sigma, double sigmaCornerOffset, int iterations, rtengine::ProgressListener* plistener, double startVal, double endVal) { BENCHFUN - const bool is5x5 = (sigma <= 0.84); - const bool is3x3 = (sigma < 0.6); + const bool is5x5 = (sigma <= 0.84 && sigmaCornerOffset == 0.0); + const bool is3x3 = (sigma < 0.6 && sigmaCornerOffset == 0.0); float kernel7[7][7]; float kernel5[5][5]; float kernel3[3][3]; @@ -532,6 +532,9 @@ BENCHFUN constexpr int tileSize = 194; constexpr int border = 5; constexpr int fullTileSize = tileSize + 2 * border; + const float maxRadius = std::min(1.15f, sigma + sigmaCornerOffset); + const float maxDistance = sqrt(rtengine::SQR(W * 0.5f) + rtengine::SQR(H * 0.5f)); + const float distanceFactor = (maxRadius - sigma) / maxDistance; double progress = startVal; const double progressStep = (endVal - startVal) * rtengine::SQR(tileSize) / (W * H); @@ -578,10 +581,21 @@ BENCHFUN gauss5x5mult(tmpThr, tmpIThr, fullTileSize, fullTileSize, kernel5); } } else { - for (int k = 0; k < iterations; ++k) { - // apply 7x7 gaussian blur and divide luminance by result of gaussian blur - gauss7x7div(tmpIThr, tmpThr, lumThr, fullTileSize, fullTileSize, kernel7); - gauss7x7mult(tmpThr, tmpIThr, fullTileSize, fullTileSize, kernel7); + if (sigmaCornerOffset > 0.0) { + float lkernel7[7][7]; + const float distance = sqrt(rtengine::SQR(i + tileSize / 2 - H / 2) + rtengine::SQR(j + tileSize / 2 - W / 2)); + compute7x7kernel(sigma + distanceFactor * distance, lkernel7); + for (int k = 0; k < iterations - 1; ++k) { + // apply 7x7 gaussian blur and divide luminance by result of gaussian blur + gauss7x7div(tmpIThr, tmpThr, lumThr, fullTileSize, fullTileSize, lkernel7); + gauss7x7mult(tmpThr, tmpIThr, fullTileSize, fullTileSize, lkernel7); + } + } else { + for (int k = 0; k < iterations; ++k) { + // apply 7x7 gaussian blur and divide luminance by result of gaussian blur + gauss7x7div(tmpIThr, tmpThr, lumThr, fullTileSize, fullTileSize, kernel7); + gauss7x7mult(tmpThr, tmpIThr, fullTileSize, fullTileSize, kernel7); + } } } if (endOfRow || endOfCol) { @@ -760,7 +774,7 @@ BENCHFUN } conrastThreshold = contrast * 100.f; - CaptureDeconvSharpening(YNew, YOld, blend, W, H, radius, sharpeningParams.deconviter, plistener, 0.2, 0.9); + CaptureDeconvSharpening(YNew, YOld, blend, W, H, radius, sharpeningParams.deconvradiusOffset, sharpeningParams.deconviter, plistener, 0.2, 0.9); if (plistener) { plistener->setProgress(0.9); } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index f88220c4e..639a9e3d3 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -1156,6 +1156,7 @@ CaptureSharpeningParams::CaptureSharpeningParams() : contrast(10.0), gamma(1.00), deconvradius(0.75), + deconvradiusOffset(0.0), deconviter(20) { } @@ -1169,6 +1170,7 @@ bool CaptureSharpeningParams::operator ==(const CaptureSharpeningParams& other) && autoContrast == other.autoContrast && autoRadius == other.autoRadius && deconvradius == other.deconvradius + && deconvradiusOffset == other.deconvradiusOffset && deconviter == other.deconviter; } @@ -3375,6 +3377,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->pdsharpening.autoRadius, "PostDemosaicSharpening", "AutoRadius", pdsharpening.autoRadius, keyFile); saveToKeyfile(!pedited || pedited->pdsharpening.gamma, "PostDemosaicSharpening", "DeconvGamma", pdsharpening.gamma, keyFile); saveToKeyfile(!pedited || pedited->pdsharpening.deconvradius, "PostDemosaicSharpening", "DeconvRadius", pdsharpening.deconvradius, keyFile); + saveToKeyfile(!pedited || pedited->pdsharpening.deconvradiusOffset, "PostDemosaicSharpening", "DeconvRadiusOffset", pdsharpening.deconvradiusOffset, keyFile); saveToKeyfile(!pedited || pedited->pdsharpening.deconviter, "PostDemosaicSharpening", "DeconvIterations", pdsharpening.deconviter, keyFile); // Post resize sharpening @@ -4465,6 +4468,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "PostDemosaicSharpening", "DeconvGamma", pedited, pdsharpening.gamma, pedited->pdsharpening.gamma); assignFromKeyfile(keyFile, "PostDemosaicSharpening", "DeconvRadius", pedited, pdsharpening.deconvradius, pedited->pdsharpening.deconvradius); + assignFromKeyfile(keyFile, "PostDemosaicSharpening", "DeconvRadiusOffset", pedited, pdsharpening.deconvradiusOffset, pedited->pdsharpening.deconvradiusOffset); assignFromKeyfile(keyFile, "PostDemosaicSharpening", "DeconvIterations", pedited, pdsharpening.deconviter, pedited->pdsharpening.deconviter); } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index ce03efc7d..ec529ee06 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -549,6 +549,7 @@ struct CaptureSharpeningParams { double contrast; double gamma; double deconvradius; + double deconvradiusOffset; int deconviter; CaptureSharpeningParams(); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 2ab5702ea..b2b51f38a 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -171,6 +171,7 @@ void ParamsEdited::set(bool v) pdsharpening.autoRadius = v; pdsharpening.gamma = v; pdsharpening.deconvradius = v; + pdsharpening.deconvradiusOffset = v; pdsharpening.deconviter = v; prsharpening.enabled = v; prsharpening.contrast = v; @@ -756,6 +757,7 @@ void ParamsEdited::initFrom(const std::vector& pdsharpening.autoRadius = pdsharpening.autoRadius && p.pdsharpening.autoRadius == other.pdsharpening.autoRadius; pdsharpening.gamma = pdsharpening.gamma && p.pdsharpening.gamma == other.pdsharpening.gamma; pdsharpening.deconvradius = pdsharpening.deconvradius && p.pdsharpening.deconvradius == other.pdsharpening.deconvradius; + pdsharpening.deconvradiusOffset = pdsharpening.deconvradiusOffset && p.pdsharpening.deconvradiusOffset == other.pdsharpening.deconvradiusOffset; pdsharpening.deconviter = pdsharpening.deconviter && p.pdsharpening.deconviter == other.pdsharpening.deconviter; prsharpening.enabled = prsharpening.enabled && p.prsharpening.enabled == other.prsharpening.enabled; prsharpening.contrast = prsharpening.contrast && p.prsharpening.contrast == other.prsharpening.contrast; @@ -1746,6 +1748,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.pdsharpening.deconvradius = dontforceSet && options.baBehav[ADDSET_SHARP_RADIUS] ? toEdit.pdsharpening.deconvradius + mods.pdsharpening.deconvradius : mods.pdsharpening.deconvradius; } + if (pdsharpening.deconvradiusOffset) { + toEdit.pdsharpening.deconvradiusOffset = dontforceSet && options.baBehav[ADDSET_SHARP_RADIUS] ? toEdit.pdsharpening.deconvradiusOffset + mods.pdsharpening.deconvradiusOffset : mods.pdsharpening.deconvradiusOffset; + } + if (pdsharpening.deconviter) { toEdit.pdsharpening.deconviter = dontforceSet && options.baBehav[ADDSET_SHARP_ITER] ? toEdit.pdsharpening.deconviter + mods.pdsharpening.deconviter : mods.pdsharpening.deconviter; } @@ -3295,5 +3301,5 @@ bool FilmNegativeParamsEdited::isUnchanged() const bool CaptureSharpeningParamsEdited::isUnchanged() const { - return enabled && contrast && autoContrast && autoRadius && gamma && deconvradius && deconviter; + return enabled && contrast && autoContrast && autoRadius && gamma && deconvradius && deconvradiusOffset && deconviter; } \ No newline at end of file diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 1bd7170d4..b83fbf568 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -205,6 +205,7 @@ struct CaptureSharpeningParamsEdited { bool autoRadius; bool gamma; bool deconvradius; + bool deconvradiusOffset; bool deconviter; bool isUnchanged() const; }; diff --git a/rtgui/pdsharpening.cc b/rtgui/pdsharpening.cc index ef0ad90c2..f25e44e69 100644 --- a/rtgui/pdsharpening.cc +++ b/rtgui/pdsharpening.cc @@ -33,6 +33,7 @@ PdSharpening::PdSharpening() : FoldableToolPanel(this, "pdsharpening", M("TP_PDS EvPdShrContrast = m->newEvent(CAPTURESHARPEN, "HISTORY_MSG_PDSHARPEN_CONTRAST"); EvPdSharpenGamma = m->newEvent(CAPTURESHARPEN, "HISTORY_MSG_PDSHARPEN_GAMMA"); EvPdShrDRadius = m->newEvent(CAPTURESHARPEN, "HISTORY_MSG_PDSHARPEN_RADIUS"); + EvPdShrDRadiusOffset = m->newEvent(CAPTURESHARPEN, "HISTORY_MSG_PDSHARPEN_RADIUS_OFFSET"); EvPdShrDIterations = m->newEvent(CAPTURESHARPEN, "HISTORY_MSG_PDSHARPEN_ITERATIONS"); EvPdShrAutoContrast = m->newEvent(CAPTURESHARPEN, "HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST"); EvPdShrAutoRadius = m->newEvent(CAPTURESHARPEN, "HISTORY_MSG_PDSHARPEN_AUTO_RADIUS"); @@ -51,25 +52,30 @@ PdSharpening::PdSharpening() : FoldableToolPanel(this, "pdsharpening", M("TP_PDS Gtk::VBox* rld = Gtk::manage(new Gtk::VBox()); gamma = Gtk::manage(new Adjuster(M("TP_SHARPENING_GAMMA"), 0.5, 6.0, 0.05, 1.00)); - dradius = Gtk::manage(new Adjuster(M("TP_SHARPENING_EDRADIUS"), 0.4, 1.15, 0.01, 0.75)); + dradius = Gtk::manage(new Adjuster(M("TP_SHARPENING_RADIUS"), 0.4, 1.15, 0.01, 0.75)); dradius->addAutoButton(M("TP_PDSHARPENING_AUTORADIUS_TOOLTIP")); dradius->setAutoValue(true); + dradiusOffset = Gtk::manage(new Adjuster(M("TP_SHARPENING_RADIUS_OFFSET"), 0.0, 0.5, 0.01, 0.0)); diter = Gtk::manage(new Adjuster(M("TP_SHARPENING_RLD_ITERATIONS"), 1, 100, 1, 20)); rld->pack_start(*gamma); rld->pack_start(*dradius); + rld->pack_start(*dradiusOffset); rld->pack_start(*diter); gamma->show(); dradius->show(); + dradiusOffset->show(); diter->show(); rld->show(); pack_start(*rld); dradius->setAdjusterListener(this); + dradiusOffset->setAdjusterListener(this); gamma->setAdjusterListener(this); diter->setAdjusterListener(this); contrast->delay = std::max(contrast->delay, options.adjusterMaxDelay); dradius->delay = std::max(dradius->delay, options.adjusterMaxDelay); + dradiusOffset->delay = std::max(dradiusOffset->delay, options.adjusterMaxDelay); gamma->delay = std::max(gamma->delay, options.adjusterMaxDelay); diter->delay = std::max(diter->delay, options.adjusterMaxDelay); } @@ -91,6 +97,7 @@ void PdSharpening::read(const ProcParams* pp, const ParamsEdited* pedited) dradius->setAutoInconsistent(multiImage && !pedited->pdsharpening.autoRadius); gamma->setEditedState(pedited->pdsharpening.gamma ? Edited : UnEdited); dradius->setEditedState(pedited->pdsharpening.deconvradius ? Edited : UnEdited); + dradiusOffset->setEditedState(pedited->pdsharpening.deconvradiusOffset ? Edited : UnEdited); diter->setEditedState(pedited->pdsharpening.deconviter ? Edited : UnEdited); set_inconsistent(multiImage && !pedited->pdsharpening.enabled); @@ -103,6 +110,7 @@ void PdSharpening::read(const ProcParams* pp, const ParamsEdited* pedited) gamma->setValue(pp->pdsharpening.gamma); dradius->setValue(pp->pdsharpening.deconvradius); dradius->setAutoValue(pp->pdsharpening.autoRadius); + dradiusOffset->setValue(pp->pdsharpening.deconvradiusOffset); diter->setValue(pp->pdsharpening.deconviter); lastAutoContrast = pp->pdsharpening.autoContrast; lastAutoRadius = pp->pdsharpening.autoRadius; @@ -119,6 +127,7 @@ void PdSharpening::write(ProcParams* pp, ParamsEdited* pedited) pp->pdsharpening.gamma = gamma->getValue(); pp->pdsharpening.deconvradius = dradius->getValue(); pp->pdsharpening.autoRadius = dradius->getAutoValue(); + pp->pdsharpening.deconvradiusOffset = dradiusOffset->getValue(); pp->pdsharpening.deconviter =(int)diter->getValue(); if (pedited) { @@ -127,6 +136,7 @@ void PdSharpening::write(ProcParams* pp, ParamsEdited* pedited) pedited->pdsharpening.gamma = gamma->getEditedState(); pedited->pdsharpening.deconvradius = dradius->getEditedState(); pedited->pdsharpening.autoRadius = !dradius->getAutoInconsistent(); + pedited->pdsharpening.deconvradiusOffset = dradiusOffset->getEditedState(); pedited->pdsharpening.deconviter = diter->getEditedState(); pedited->pdsharpening.enabled = !get_inconsistent(); } @@ -138,17 +148,20 @@ void PdSharpening::setDefaults(const ProcParams* defParams, const ParamsEdited* contrast->setDefault(defParams->pdsharpening.contrast); gamma->setDefault(defParams->pdsharpening.gamma); dradius->setDefault(defParams->pdsharpening.deconvradius); + dradiusOffset->setDefault(defParams->pdsharpening.deconvradiusOffset); diter->setDefault(defParams->pdsharpening.deconviter); if (pedited) { contrast->setDefaultEditedState(pedited->pdsharpening.contrast ? Edited : UnEdited); gamma->setDefaultEditedState(pedited->pdsharpening.gamma ? Edited : UnEdited); dradius->setDefaultEditedState(pedited->pdsharpening.deconvradius ? Edited : UnEdited); + dradiusOffset->setDefaultEditedState(pedited->pdsharpening.deconvradiusOffset ? Edited : UnEdited); diter->setDefaultEditedState(pedited->pdsharpening.deconviter ? Edited : UnEdited); } else { contrast->setDefaultEditedState(Irrelevant); gamma->setDefaultEditedState(Irrelevant); dradius->setDefaultEditedState(Irrelevant); + dradiusOffset->setDefaultEditedState(Irrelevant); diter->setDefaultEditedState(Irrelevant); } } @@ -159,7 +172,7 @@ void PdSharpening::adjusterChanged(Adjuster* a, double newval) Glib::ustring costr; - if (a == gamma || a == dradius) { + if (a == gamma || a == dradius || a == dradiusOffset) { costr = Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), a->getValue()); } else { costr = Glib::ustring::format((int)a->getValue()); @@ -171,6 +184,8 @@ void PdSharpening::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(EvPdSharpenGamma, costr); } else if (a == dradius) { listener->panelChanged(EvPdShrDRadius, costr); + } else if (a == dradiusOffset) { + listener->panelChanged(EvPdShrDRadiusOffset, costr); } else if (a == diter) { listener->panelChanged(EvPdShrDIterations, costr); } @@ -198,6 +213,7 @@ void PdSharpening::setBatchMode(bool batchMode) contrast->showEditedCB(); gamma->showEditedCB(); dradius->showEditedCB(); + dradiusOffset->showEditedCB(); diter->showEditedCB(); } @@ -207,6 +223,7 @@ void PdSharpening::setAdjusterBehavior(bool contrastadd, bool gammaadd, bool rad contrast->setAddMode(contrastadd); gamma->setAddMode(gammaadd); dradius->setAddMode(radiusadd); + dradiusOffset->setAddMode(radiusadd); diter->setAddMode(iteradd); } @@ -216,6 +233,7 @@ void PdSharpening::trimValues(rtengine::procparams::ProcParams* pp) contrast->trimValue(pp->pdsharpening.contrast); gamma->trimValue(pp->pdsharpening.gamma); dradius->trimValue(pp->pdsharpening.deconvradius); + dradiusOffset->trimValue(pp->pdsharpening.deconvradiusOffset); diter->trimValue(pp->pdsharpening.deconviter); } diff --git a/rtgui/pdsharpening.h b/rtgui/pdsharpening.h index e56b4b085..f621fd0a5 100644 --- a/rtgui/pdsharpening.h +++ b/rtgui/pdsharpening.h @@ -28,12 +28,14 @@ protected: Adjuster* contrast; Adjuster* gamma; Adjuster* dradius; + Adjuster* dradiusOffset; Adjuster* diter; bool lastAutoContrast; bool lastAutoRadius; rtengine::ProcEvent EvPdShrContrast; rtengine::ProcEvent EvPdShrDRadius; + rtengine::ProcEvent EvPdShrDRadiusOffset; rtengine::ProcEvent EvPdSharpenGamma; rtengine::ProcEvent EvPdShrDIterations; rtengine::ProcEvent EvPdShrAutoContrast;