diff --git a/rtdata/languages/default b/rtdata/languages/default index d4fb356e0..4a419e736 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -806,6 +806,7 @@ HISTORY_MSG_THRESWAV;Balance threshold HISTORY_MSG_BLUWAV;Maximum blur HISTORY_MSG_WAVOLDSH;Old algorithm HISTORY_MSG_WAVOFFSET;Offset +HISTORY_MSG_WAVLOWTHR;Threshold low contrast HISTORY_MSG_BLSHAPE;Blur by level HISTORY_MSG_WAVBL;Blur levels HISTORY_MSG_BLURWAV;Blur luminance @@ -2242,6 +2243,7 @@ TP_WAVELET_LEVZERO;Level 1 TP_WAVELET_LINKEDG;Link with Edge Sharpness' Strength TP_WAVELET_LIPST;Enhanced algoritm TP_WAVELET_LOWLIGHT;Shadow luminance range +TP_WAVELET_LOWTHR_TOOLTIP;Prevents amplification of fine textures and noise TP_WAVELET_MEDGREINF;First level TP_WAVELET_MEDI;Reduce artifacts in blue sky TP_WAVELET_MEDILEV;Edge detection @@ -2312,6 +2314,7 @@ TP_WAVELET_USH;None TP_WAVELET_USHARP;Clarity method TP_WAVELET_USHARP_TOOLTIP;Origin : the source file is the file before Wavelet.\nWavelet : the source file is the file including wavelet threatment TP_WAVELET_USH_TOOLTIP;If you select Sharp-mask, wavelet settings will be automatically positioned :\nBackground=black, Process=below, level=3...you can change level between 1 and 4.\n\nIf you select Clarity, wavelet settings will be automatically positioned :\nBackground=residual, Process=above, level=7..you can change level between 5 and 10 and wavelet levels. +TP_WAVELET_WAVLOWTHR;Low contrast threshold TP_WAVELET_WAVOFFSET;Offset TP_WAVELET_OFFSET_TOOLTIP;Offset modifies the balance between shadows and highlights.\n High values will amplify the contrast enhancement of the highlights, while low values will amplify the contrast enhancement of the shadows. Along with a low Max. effect value will help you selecting the contrasts that will be enhanced TP_WBALANCE_AUTO;Auto diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index 8c15f51c5..d5b642aaa 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -3002,39 +3002,66 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz const float skinprotneg = -skinprot; const float factorHard = (1.f - skinprotneg / 100.f); const float offs = params->wavelet.offset; + const float lowthr = params->wavelet.lowthr; //to adjust increase contrast with local contrast //for each pixel and each level float beta; - float mea[9]; - float rap = offs * mean[level] - 2.f * cp.sigm * sigma[level]; + float mea[10]; + float rap = 0.f; + float sig = 1.f; + if(cp.sigm < 1.f) { + sig = cp.sigm; + } + if(cp.sigm <= 1.f) { + rap = offs * mean[level] - sig * sigma[level]; + } + if (rap > 0.f) { mea[0] = rap; } else { mea[0] = mean[level] / 6.f; } - rap = offs * mean[level] - cp.sigm * sigma[level]; + rap = 0.f; + if(cp.sigm <= 1.f) { + rap = offs * mean[level] - 0.5f * sig * sigma[level]; + } if (rap > 0.f) { mea[1] = rap; } else { - mea[1] = mean[level] / 2.f; + mea[1] = mean[level] / 4.f; + } + + rap = 0.f; + if(cp.sigm <= 1.f) { + rap = offs * mean[level] - 0.2f * sig * sigma[level]; } - mea[2] = offs * mean[level]; // 50% data - mea[3] = offs * mean[level] + cp.sigm * sigma[level] / 2.f; - mea[4] = offs * mean[level] + cp.sigm * sigma[level]; //66% - mea[5] = offs * mean[level] + cp.sigm * 1.2f * sigma[level]; - mea[6] = offs * mean[level] + cp.sigm * 1.5f * sigma[level]; // - mea[7] = offs * mean[level] + cp.sigm * 2.f * sigma[level]; //95% - mea[8] = offs * mean[level] + cp.sigm * 2.5f * sigma[level]; //99% + if (rap > 0.f) { + mea[2] = rap; + } else { + mea[2] = mean[level] / 2.f; + } + + mea[3] = offs * mean[level]; // 50% data + mea[4] = offs * mean[level] + cp.sigm * sigma[level] / 2.f; + mea[5] = offs * mean[level] + cp.sigm * sigma[level]; //66% + mea[6] = offs * mean[level] + cp.sigm * 1.2f * sigma[level]; + mea[7] = offs * mean[level] + cp.sigm * 1.5f * sigma[level]; // + mea[8] = offs * mean[level] + cp.sigm * 2.f * sigma[level]; //95% + mea[9] = offs * mean[level] + cp.sigm * 2.5f * sigma[level]; //99% bool useChromAndHue = (skinprot != 0.f || cp.HSmet); float modchro; + float red0 = 0.005f * (110.f - lowthr); + float red1 = 0.008f * (110.f - lowthr); + float red2 = 0.011f * (110.f - lowthr); + for (int i = 0; i < W_L * H_L; i++) { float kLlev = 1.f; @@ -3046,22 +3073,24 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz //reduction amplification: max action between mean / 2 and mean + sigma // arbitrary coefficient, we can add a slider !! if (WavCL < mea[0]) { - beta = 0.6f; //preserve very low contrast (sky...) + beta = 0.4f * red0;//preserve very low contrast (sky...) } else if (WavCL < mea[1]) { - beta = 0.8f; + beta = 0.5f * red1; } else if (WavCL < mea[2]) { - beta = 1.f; //standard + beta = 0.7f * red2; } else if (WavCL < mea[3]) { - beta = 1.f; + beta = 1.f; //standard } else if (WavCL < mea[4]) { - beta = 0.8f; //+sigma + beta = 1.f; } else if (WavCL < mea[5]) { - beta = 0.6f; + beta = 0.8f; //+sigma } else if (WavCL < mea[6]) { - beta = 0.4f; + beta = 0.6f; } else if (WavCL < mea[7]) { - beta = 0.2f; // + 2 sigma + beta = 0.4f; } else if (WavCL < mea[8]) { + beta = 0.2f; // + 2 sigma + } else if (WavCL < mea[9]) { beta = 0.1f; } else { beta = 0.0f; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 20ae540f5..66f2a4c19 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2288,6 +2288,7 @@ WaveletParams::WaveletParams() : HSmethod("with"), sigma(1.0), offset(1.0), + lowthr(40.0), rescon(0), resconH(0), reschro(0), @@ -2403,6 +2404,7 @@ bool WaveletParams::operator ==(const WaveletParams& other) const && HSmethod == other.HSmethod && sigma == other.sigma && offset == other.offset + && lowthr == other.lowthr && rescon == other.rescon && resconH == other.resconH && reschro == other.reschro @@ -3599,6 +3601,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->wavelet.tmr, "Wavelet", "TMr", wavelet.tmr, keyFile); saveToKeyfile(!pedited || pedited->wavelet.sigma, "Wavelet", "Sigma", wavelet.sigma, keyFile); saveToKeyfile(!pedited || pedited->wavelet.offset, "Wavelet", "Offset", wavelet.offset, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.lowthr, "Wavelet", "Lowthr", wavelet.lowthr, keyFile); saveToKeyfile(!pedited || pedited->wavelet.rescon, "Wavelet", "ResidualcontShadow", wavelet.rescon, keyFile); saveToKeyfile(!pedited || pedited->wavelet.resconH, "Wavelet", "ResidualcontHighlight", wavelet.resconH, keyFile); saveToKeyfile(!pedited || pedited->wavelet.thr, "Wavelet", "ThresholdResidShadow", wavelet.thr, keyFile); @@ -4722,6 +4725,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Wavelet", "DirMethod", pedited, wavelet.Dirmethod, pedited->wavelet.Dirmethod); assignFromKeyfile(keyFile, "Wavelet", "Sigma", pedited, wavelet.sigma, pedited->wavelet.sigma); assignFromKeyfile(keyFile, "Wavelet", "Offset", pedited, wavelet.offset, pedited->wavelet.offset); + assignFromKeyfile(keyFile, "Wavelet", "Lowthr", pedited, wavelet.lowthr, pedited->wavelet.lowthr); assignFromKeyfile(keyFile, "Wavelet", "ResidualcontShadow", pedited, wavelet.rescon, pedited->wavelet.rescon); assignFromKeyfile(keyFile, "Wavelet", "ResidualcontHighlight", pedited, wavelet.resconH, pedited->wavelet.resconH); assignFromKeyfile(keyFile, "Wavelet", "Residualchroma", pedited, wavelet.reschro, pedited->wavelet.reschro); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 8ca3e5c29..6dd5198ff 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1247,6 +1247,7 @@ struct WaveletParams { Glib::ustring HSmethod; double sigma; double offset; + double lowthr; int rescon; int resconH; int reschro; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index b3c2b64d7..0b06b9d92 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -512,6 +512,7 @@ void ParamsEdited::set(bool v) wavelet.sigma = v; wavelet.sigma = v; wavelet.offset = v; + wavelet.lowthr = v; wavelet.resconH = v; wavelet.reschro = v; wavelet.resblur = v; @@ -1115,6 +1116,7 @@ void ParamsEdited::initFrom(const std::vector& wavelet.Dirmethod = wavelet.Dirmethod && p.wavelet.Dirmethod == other.wavelet.Dirmethod; wavelet.sigma = wavelet.sigma && p.wavelet.sigma == other.wavelet.sigma; wavelet.offset = wavelet.offset && p.wavelet.offset == other.wavelet.offset; + wavelet.lowthr = wavelet.lowthr && p.wavelet.lowthr == other.wavelet.lowthr; wavelet.rescon = wavelet.rescon && p.wavelet.rescon == other.wavelet.rescon; wavelet.resconH = wavelet.resconH && p.wavelet.resconH == other.wavelet.resconH; wavelet.reschro = wavelet.reschro && p.wavelet.reschro == other.wavelet.reschro; @@ -3202,6 +3204,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wavelet.offset = mods.wavelet.offset; } + if (wavelet.lowthr) { + toEdit.wavelet.lowthr = mods.wavelet.lowthr; + } + if (wavelet.resblur) { toEdit.wavelet.resblur = mods.wavelet.resblur; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 43254b015..0b315583d 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -527,6 +527,7 @@ struct WaveletParamsEdited { bool Dirmethod; bool sigma; bool offset; + bool lowthr; bool rescon; bool resconH; bool reschro; diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc index 2e444ff3d..b23143c6c 100644 --- a/rtgui/wavelet.cc +++ b/rtgui/wavelet.cc @@ -84,6 +84,7 @@ Wavelet::Wavelet() : neutralchButton(Gtk::manage(new Gtk::Button(M("TP_WAVELET_NEUTRAL")))), sigma(Gtk::manage(new Adjuster(M("TP_WAVELET_SIGMA"), 0.05, 2.5, 0.01, 1.))), offset(Gtk::manage(new Adjuster(M("TP_WAVELET_WAVOFFSET"), 0.33, 1.66, 0.01, 1., Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))), + lowthr(Gtk::manage(new Adjuster(M("TP_WAVELET_WAVLOWTHR"), 20., 100., 0.5, 40.))), rescon(Gtk::manage(new Adjuster(M("TP_WAVELET_RESCON"), -100, 100, 1, 0))), resconH(Gtk::manage(new Adjuster(M("TP_WAVELET_RESCONH"), -100, 100, 1, 0))), reschro(Gtk::manage(new Adjuster(M("TP_WAVELET_RESCHRO"), -100, 100, 1, 0))), @@ -190,6 +191,7 @@ Wavelet::Wavelet() : EvWavchrwav = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_chrwav"); EvWavoldsh = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVOLDSH"); EvWavoffset = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVOFFSET"); + EvWavlowthr = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_WAVLOWTHR"); EvWavbluwav = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_BLUWAV"); EvWavblshape = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_BLSHAPE"); EvWavresblur = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_BLURWAV"); @@ -359,6 +361,9 @@ Wavelet::Wavelet() : levBox->pack_start(*offset, Gtk::PACK_SHRINK); sigma->set_tooltip_text(M("TP_WAVELET_SIGMA_TOOLTIP")); offset->set_tooltip_text(M("TP_WAVELET_OFFSET_TOOLTIP")); + lowthr->setAdjusterListener(this); + lowthr->set_tooltip_text(M("TP_WAVELET_LOWTHR_TOOLTIP")); + levBox->pack_start(*lowthr, Gtk::PACK_SHRINK); wavLabels->show(); levBox->pack_start(*wavLabels); @@ -1321,6 +1326,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) lasttmr = pp->wavelet.tmr; sigma->setValue(pp->wavelet.sigma); offset->setValue(pp->wavelet.offset); + lowthr->setValue(pp->wavelet.lowthr); rescon->setValue(pp->wavelet.rescon); resconH->setValue(pp->wavelet.resconH); reschro->setValue(pp->wavelet.reschro); @@ -1481,6 +1487,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) rescon->setEditedState(pedited->wavelet.rescon ? Edited : UnEdited); sigma->setEditedState(pedited->wavelet.sigma ? Edited : UnEdited); offset->setEditedState(pedited->wavelet.offset ? Edited : UnEdited); + lowthr->setEditedState(pedited->wavelet.lowthr ? Edited : UnEdited); resconH->setEditedState(pedited->wavelet.resconH ? Edited : UnEdited); reschro->setEditedState(pedited->wavelet.reschro ? Edited : UnEdited); resblur->setEditedState(pedited->wavelet.resblur ? Edited : UnEdited); @@ -1672,6 +1679,7 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pp->wavelet.tmr = tmr->get_active(); pp->wavelet.sigma = sigma->getValue(); pp->wavelet.offset = offset->getValue(); + pp->wavelet.lowthr = lowthr->getValue(); pp->wavelet.rescon = rescon->getValue(); pp->wavelet.resconH = resconH->getValue(); pp->wavelet.reschro = reschro->getValue(); @@ -1791,6 +1799,7 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pedited->wavelet.edgthresh = edgthresh->getEditedState(); pedited->wavelet.sigma = sigma->getEditedState(); pedited->wavelet.offset = offset->getEditedState(); + pedited->wavelet.lowthr = lowthr->getEditedState(); pedited->wavelet.rescon = rescon->getEditedState(); pedited->wavelet.resconH = resconH->getEditedState(); pedited->wavelet.reschro = reschro->getEditedState(); @@ -2035,6 +2044,7 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit iter->setDefault(defParams->wavelet.iter); sigma->setDefault(defParams->wavelet.sigma); offset->setDefault(defParams->wavelet.offset); + lowthr->setDefault(defParams->wavelet.lowthr); rescon->setDefault(defParams->wavelet.rescon); resconH->setDefault(defParams->wavelet.resconH); reschro->setDefault(defParams->wavelet.reschro); @@ -2102,6 +2112,7 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit sigma->setDefault(defParams->wavelet.sigma); offset->setDefault(defParams->wavelet.offset); + lowthr->setDefault(defParams->wavelet.lowthr); rescon->setDefault(defParams->wavelet.rescon); resconH->setDefault(defParams->wavelet.resconH); reschro->setDefault(defParams->wavelet.reschro); @@ -2158,6 +2169,7 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit } else { sigma->setDefaultEditedState(Irrelevant); offset->setDefaultEditedState(Irrelevant); + lowthr->setDefaultEditedState(Irrelevant); rescon->setDefaultEditedState(Irrelevant); resconH->setDefaultEditedState(Irrelevant); reschro->setDefaultEditedState(Irrelevant); @@ -2692,6 +2704,7 @@ void Wavelet::setBatchMode(bool batchMode) curveEditorGAM->setBatchMode(batchMode); sigma->showEditedCB(); offset->showEditedCB(); + lowthr->showEditedCB(); rescon->showEditedCB(); resconH->showEditedCB(); reschro->showEditedCB(); @@ -2781,6 +2794,8 @@ void Wavelet::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(EvWavsigma, sigma->getTextValue()); } else if (a == offset) { listener->panelChanged(EvWavoffset, offset->getTextValue()); + } else if (a == lowthr) { + listener->panelChanged(EvWavlowthr, lowthr->getTextValue()); } else if (a == resconH) { listener->panelChanged(EvWavresconH, resconH->getTextValue()); } else if (a == reschro) { diff --git a/rtgui/wavelet.h b/rtgui/wavelet.h index 67a45b5ac..609d3226c 100644 --- a/rtgui/wavelet.h +++ b/rtgui/wavelet.h @@ -83,6 +83,7 @@ private: rtengine::ProcEvent EvWavchrwav; rtengine::ProcEvent EvWavoldsh; rtengine::ProcEvent EvWavoffset; + rtengine::ProcEvent EvWavlowthr; rtengine::ProcEvent EvWavbluwav; rtengine::ProcEvent EvWavblshape; rtengine::ProcEvent EvWavresblur; @@ -184,6 +185,7 @@ private: Adjuster* correctionch[9]; Adjuster* const sigma; Adjuster* const offset; + Adjuster* const lowthr; Adjuster* const rescon; Adjuster* const resconH; Adjuster* const reschro;