diff --git a/rtdata/languages/default b/rtdata/languages/default index 404c78be0..f32300899 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1222,13 +1222,15 @@ HISTORY_MSG_WAVSOFTRAD;Soft radius clarity HISTORY_MSG_WAVSOFTRADEND;Soft radius final HISTORY_MSG_WAVUSHAMET;Clarity method HISTORY_MSG_THRESWAV;Balance threshold -HISTORY_MSG_BLUWAV;Maximum blur +HISTORY_MSG_BLUWAV;Effects 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 HISTORY_MSG_BLURCWAV;Blur chroma +HISTORY_MSG_EDGEFFECT;Edge Effect HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -3042,7 +3044,7 @@ TP_WAVELET_BASLI;Slider TP_WAVELET_BATYPE;Contrast balance method TP_WAVELET_BLCURVE;Blur by levels TP_WAVELET_BLURFRAME;Blur -TP_WAVELET_BLUWAV;Maximum Blur +TP_WAVELET_BLUWAV;Effects TP_WAVELET_CBENAB;Toning and Color Balance TP_WAVELET_CB_TOOLTIP;For strong values product color-toning by combining it or not with levels decomposition 'toning'\nFor low values you can change the white balance of the background (sky, ...) without changing that of the front plane, generally more contrasted TP_WAVELET_CCURVE;Local contrast @@ -3102,6 +3104,8 @@ TP_WAVELET_EDGEDETECTTHR;Threshold low (noise) TP_WAVELET_EDGEDETECTTHR2;Threshold high (detection) TP_WAVELET_EDGEDETECTTHR_TOOLTIP;This adjuster lets you target edge detection for example to avoid applying edge sharpness to fine details, such as noise in the sky. TP_WAVELET_EDGEDETECT_TOOLTIP;Moving the slider to the right increases edge sensitivity. This affects local contrast, edge settings and noise. +TP_WAVELET_EDEFFECT;Effect +TP_WAVELET_EDEFFECT_TOOLTIP;This slider controls how wide the range of contrast values are that receive the maximum effect from the tool.\nMaximum value (2.5) disabled the tool TP_WAVELET_EDGESENSI;Edge sensitivity TP_WAVELET_EDGREINF_TOOLTIP;Reinforce or reduce the action of the first level, do the opposite to the second level, and leave the rest unchanged. TP_WAVELET_EDGTHRESH;Detail @@ -3140,6 +3144,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 @@ -3210,6 +3215,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/improcfun.h b/rtengine/improcfun.h index fe4db782e..f0086b2e0 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -375,7 +375,7 @@ public: struct cont_params &cp, int skip, float *mean, float *sigma, float *MaxP, float *MaxN, const WavCurve & wavCLVCcurve, const WavOpacityCurveW & waOpacityCurveW, FlatCurve* ChCurve, bool Chutili); void WaveletcontAllLfinal(const wavelet_decomposition &WaveletCoeffs_L, const cont_params &cp, float *mean, float *sigma, float *MaxP, const WavOpacityCurveWL & waOpacityCurveWL); void WaveletcontAllAB(LabImage * lab, float **varhue, float **varchrom, const wavelet_decomposition &WaveletCoeffs_a, const Wavblcurve & wavblcurve, const WavOpacityCurveW & waOpacityCurveW, - struct cont_params &cp, const bool useChannelA, int skip); + struct cont_params &cp, const bool useChannelA, int skip, float *meanab, float *sigmaab); void WaveletAandBAllAB(const wavelet_decomposition &WaveletCoeffs_a, const wavelet_decomposition &WaveletCoeffs_b, const cont_params &cp, FlatCurve* hhcurve, bool hhutili); void ContAllL(float **koeLi, float *maxkoeLi, bool lipschitz, int maxlvl, LabImage * lab, float **varhue, float **varchrom, float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params &cp, @@ -389,6 +389,8 @@ public: void Eval2(float ** WavCoeffs_L, int level, int W_L, int H_L, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN); + void calceffect(int level, float *mean, float *sigma, float *mea, float effect, float offs); + void Aver(float * HH_Coeffs, int datalen, float &averagePlus, float &averageNeg, float &max, float &min); void Sigma(float * HH_Coeffs, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg); // void calckoe(float ** WavCoeffs_LL, const cont_params& cp, float ** koeLi, int level, int dir, int W_L, int H_L, float edd, float *maxkoeLi, float **tmC = nullptr); diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index 5f985c617..9034768b5 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -82,6 +82,7 @@ struct cont_params { float b_lpast, t_lpast, b_rpast, t_rpast; float b_lsat, t_lsat, b_rsat, t_rsat; int rad; + float eff; int val; int til; int numlevH, numlevS; @@ -392,6 +393,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.rad = waparams.edgrad; cp.val = waparams.edgval; cp.til = waparams.edgthresh; + cp.eff = waparams.edgeffect; cp.conres = waparams.rescon; cp.conresH = waparams.resconH; @@ -400,7 +402,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.oldsh = waparams.oldsh; cp.blurres = waparams.resblur; cp.blurcres = waparams.resblurc; - cp.bluwav = 0.01f * waparams.bluwav; + cp.bluwav = waparams.bluwav; //cp.hueres=waparams.reshue; cp.hueres = 2.f; cp.th = float(waparams.thr); @@ -643,6 +645,13 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const float MaxP[10]; float MaxN[10]; + float meanab[10]; + float meanNab[10]; + float sigmaab[10]; + float sigmaNab[10]; + float MaxPab[10]; + float MaxNab[10]; + array2D varchro(tilewidth, tileheight); float** varhue = new float*[tileheight]; @@ -925,7 +934,8 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const const std::unique_ptr adecomp(new wavelet_decomposition(labco->data + datalen, labco->W, labco->H, levwava, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); if (!adecomp->memoryAllocationFailed) { - WaveletcontAllAB(labco, varhue, varchro, *adecomp, wavblcurve, waOpacityCurveW, cp, true, skip); + Evaluate2(*adecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab); + WaveletcontAllAB(labco, varhue, varchro, *adecomp, wavblcurve, waOpacityCurveW, cp, true, skip, meanab, sigmaab); adecomp->reconstruct(labco->data + datalen, cp.strength); } } @@ -942,7 +952,8 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const const std::unique_ptr bdecomp(new wavelet_decomposition(labco->data + 2 * datalen, labco->W, labco->H, levwavb, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); if (!bdecomp->memoryAllocationFailed) { - WaveletcontAllAB(labco, varhue, varchro, *bdecomp, wavblcurve, waOpacityCurveW, cp, false, skip); + Evaluate2(*bdecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab); + WaveletcontAllAB(labco, varhue, varchro, *bdecomp, wavblcurve, waOpacityCurveW, cp, false, skip, meanab, sigmaab); bdecomp->reconstruct(labco->data + 2 * datalen, cp.strength); } } @@ -960,8 +971,10 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const const std::unique_ptr bdecomp(new wavelet_decomposition(labco->data + 2 * datalen, labco->W, labco->H, levwavab, 1, skip, rtengine::max(1, wavNestedLevels), DaubLen)); if (!adecomp->memoryAllocationFailed && !bdecomp->memoryAllocationFailed) { - WaveletcontAllAB(labco, varhue, varchro, *adecomp,wavblcurve, waOpacityCurveW, cp, true, skip); - WaveletcontAllAB(labco, varhue, varchro, *bdecomp, wavblcurve, waOpacityCurveW, cp, false, skip); + Evaluate2(*adecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab); + WaveletcontAllAB(labco, varhue, varchro, *adecomp,wavblcurve, waOpacityCurveW, cp, true, skip, meanab, sigmaab); + Evaluate2(*bdecomp, meanab, meanNab, sigmaab, sigmaNab, MaxPab, MaxNab); + WaveletcontAllAB(labco, varhue, varchro, *bdecomp, wavblcurve, waOpacityCurveW, cp, false, skip, meanab, sigmaab); WaveletAandBAllAB(*adecomp, *bdecomp, cp, hhCurve, hhutili); adecomp->reconstruct(labco->data + datalen, cp.strength); @@ -1228,6 +1241,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } + void ImProcFunctions::Aver(float * RESTRICT DataList, int datalen, float &averagePlus, float &averageNeg, float &max, float &min) { @@ -1334,6 +1348,56 @@ void ImProcFunctions::Evaluate2(const wavelet_decomposition &WaveletCoeffs_L, } } + +void ImProcFunctions::calceffect(int level, float *mean, float *sigma, float *mea, float effect, float offs) +{ + float rap = 0.f; + float sig = 1.f; + if(effect < 1.f) { + sig = effect; + } + + if(effect <= 1.f) { + rap = offs * mean[level] - sig * sigma[level]; + } + + if (rap > 0.f) { + mea[0] = rap; + } else { + mea[0] = mean[level] / 6.f; + } + + rap = 0.f; + if(effect <= 1.f) { + rap = offs * mean[level] - 0.5f * sig * sigma[level]; + } + + if (rap > 0.f) { + mea[1] = rap; + } else { + mea[1] = mean[level] / 4.f; + } + + rap = 0.f; + if(effect <= 1.f) { + rap = offs * mean[level] - 0.2f * sig * sigma[level]; + } + + 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] + effect * sigma[level] / 2.f; + mea[5] = offs * mean[level] + effect * sigma[level]; //66% + mea[6] = offs * mean[level] + effect * 1.2f * sigma[level]; + mea[7] = offs * mean[level] + effect * 1.5f * sigma[level]; // + mea[8] = offs * mean[level] + effect * 2.f * sigma[level]; //95% + mea[9] = offs * mean[level] + effect * 2.5f * sigma[level]; //99% +} + void ImProcFunctions::Eval2(float ** WavCoeffs_L, int level, int W_L, int H_L, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN) { @@ -1957,20 +2021,53 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float * ContAllL(koeLi, maxkoeLi, true, maxlvl, labco, varhue, varchrom, WavCoeffs_L, WavCoeffs_L0, lvl, dir, cp, Wlvl_L, Hlvl_L, skip, mean, sigma, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, ChCurve, Chutili); //blur level float klev = 1.f; - if(wavblcurve && wavcurvecomp && cp.blena && cp.bluwav > 0.f) { + if(wavblcurve && wavcurvecomp && cp.blena) { + float mea[10]; + float effect = cp.bluwav; + float beta = 0.f; + float offs = 1.f; + + calceffect(lvl, mean, sigma, mea, effect, offs); float * bef = new float[Wlvl_L * Hlvl_L]; float * aft = new float[Wlvl_L * Hlvl_L]; for (int co = 0; co < Hlvl_L * Wlvl_L; co++) { - bef[co] = WavCoeffs_L[dir][co]; + bef[co] = WavCoeffs_L[dir][co]; + float WavCL = std::fabs(WavCoeffs_L[dir][co]); + + if (WavCL < mea[0]) { + beta = 0.05f; + } else if (WavCL < mea[1]) { + beta = 0.2f; + } else if (WavCL < mea[2]) { + beta = 0.7f; + } else if (WavCL < mea[3]) { + beta = 1.f; //standard + } else if (WavCL < mea[4]) { + beta = 1.f; + } else if (WavCL < mea[5]) { + beta = 0.8f; //+sigma + } else if (WavCL < mea[6]) { + beta = 0.6f; + } else if (WavCL < mea[7]) { + 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; + } + + } klev = (wavblcurve[lvl * 55.5f]); float lvr = lvl; if(lvr == 0) { lvr = 1; } - klev *= cp.bluwav * lvr * 10.f / skip; + klev *= beta * lvr * 100.f / skip; boxblur(bef, aft, klev, Wlvl_L, Hlvl_L, false); for (int co = 0; co < Hlvl_L * Wlvl_L; co++) { @@ -2057,7 +2154,7 @@ void ImProcFunctions::WaveletAandBAllAB(const wavelet_decomposition &WaveletCoef } void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float **varchrom, const wavelet_decomposition &WaveletCoeffs_ab, const Wavblcurve & wavblcurve, const WavOpacityCurveW & waOpacityCurveW, - struct cont_params &cp, const bool useChannelA, int skip) + struct cont_params &cp, const bool useChannelA, int skip, float *meanab, float *sigmaab) { int maxlvl = WaveletCoeffs_ab.maxlevel(); @@ -2223,20 +2320,54 @@ void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float float ** WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl); ContAllAB(labco, maxlvl, varhue, varchrom, WavCoeffs_ab, WavCoeffs_ab0, lvl, dir, waOpacityCurveW, cp, Wlvl_ab, Hlvl_ab, useChannelA); - if(wavblcurve && wavcurvecomp && cp.blena && cp.chrwav > 0.f && cp.bluwav > 0.f) { + if(wavblcurve && wavcurvecomp && cp.blena && cp.chrwav > 0.f) { + float mea[10]; + float effect = cp.bluwav; + float beta = 0.f; + float offs = 1.f; + + calceffect(lvl, meanab, sigmaab, mea, effect, offs); + float * bef = new float[Wlvl_ab * Hlvl_ab]; float * aft = new float[Wlvl_ab * Hlvl_ab]; float klev; for (int co = 0; co < Hlvl_ab * Wlvl_ab; co++) { bef[co] = WavCoeffs_ab[dir][co]; + float WavCab = std::fabs(WavCoeffs_ab[dir][co]); + + if (WavCab < mea[0]) { + beta = 0.05f; + } else if (WavCab < mea[1]) { + beta = 0.2f; + } else if (WavCab < mea[2]) { + beta = 0.7f; + } else if (WavCab < mea[3]) { + beta = 1.f; //standard + } else if (WavCab < mea[4]) { + beta = 1.f; + } else if (WavCab < mea[5]) { + beta = 0.8f; //+sigma + } else if (WavCab < mea[6]) { + beta = 0.6f; + } else if (WavCab < mea[7]) { + beta = 0.4f; + } else if (WavCab < mea[8]) { + beta = 0.2f; // + 2 sigma + } else if (WavCab < mea[9]) { + beta = 0.1f; + } else { + beta = 0.0f; + } + + } klev = (wavblcurve[lvl * 55.5f]); float lvr = lvl; if(lvr == 0) { lvr = 1; } - - klev *= cp.bluwav * cp.chrwav * lvr * 20.f / skip; + + klev *= beta * cp.chrwav * lvr * 200.f / skip; boxblur(bef, aft, klev, Wlvl_ab, Hlvl_ab, false); @@ -2597,7 +2728,47 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz constexpr float aedstr = (eddstrength - 1.f) / 90.f; constexpr float bedstr = 1.f - 10.f * aedstr; + float mea[10]; + float beta = 1.f; + if(cp.eff < 2.5f) { + float effect = cp.eff; + float offs = 1.f; + + calceffect(level, mean, sigma, mea, effect, offs); + for (int co = 0; co < H_L * W_L; co++) { + float WavCL = std::fabs(WavCoeffs_L[dir][co]); + + if (WavCL < mea[0]) { + beta = 0.05f; + } else if (WavCL < mea[1]) { + beta = 0.2f; + } else if (WavCL < mea[2]) { + beta = 0.7f; + } else if (WavCL < mea[3]) { + beta = 1.f; //standard + } else if (WavCL < mea[4]) { + beta = 1.f; + } else if (WavCL < mea[5]) { + beta = 0.8f; //+sigma + } else if (WavCL < mea[6]) { + beta = 0.6f; + } else if (WavCL < mea[7]) { + 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; + } + + } + } + + if (cp.val > 0 && cp.edgeena) { + + float * koe = nullptr; float maxkoe = 0.f; @@ -2686,7 +2857,7 @@ void ImProcFunctions::ContAllL(float *koeLi[12], float *maxkoeLi, bool lipschitz float atten01234 = 0.80f; value *= (atten01234 * scaleskip[1]); //for zoom < 100% reduce strength...I choose level 1...but!! } - + value *= beta; float edge = 1.f; float lim0 = 20.f; //arbitrary limit for low radius and level between 2 or 3 to 30 maxi float lev = float (level); @@ -3007,39 +3178,20 @@ 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; - - //to adjust increase contrast with local contrast - - //for each pixel and each level + const float lowthr = params->wavelet.lowthr; + float mea[10]; + float effect = cp.sigm; float beta; - float mea[9]; - float rap = offs * mean[level] - 2.f * cp.sigm * sigma[level]; - if (rap > 0.f) { - mea[0] = rap; - } else { - mea[0] = mean[level] / 6.f; - } - - rap = offs * mean[level] - cp.sigm * sigma[level]; - - if (rap > 0.f) { - mea[1] = rap; - } else { - mea[1] = mean[level] / 2.f; - } - - 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% + calceffect(level, mean, sigma, mea, effect, offs); 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; @@ -3051,22 +3203,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 bf5f2a4da..7521332ba 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), @@ -2311,6 +2312,7 @@ WaveletParams::WaveletParams() : edgeampli(10), contrast(0), edgrad(15), + edgeffect(1.0), edgval(0), edgthresh(10), thr(30), @@ -2404,6 +2406,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 @@ -2427,6 +2430,7 @@ bool WaveletParams::operator ==(const WaveletParams& other) const && edgeampli == other.edgeampli && contrast == other.contrast && edgrad == other.edgrad + && edgeffect == other.edgeffect && edgval == other.edgval && edgthresh == other.edgthresh && thr == other.thr @@ -4948,6 +4952,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->wavelet.bluwav, "Wavelet", "bluwav", wavelet.bluwav, keyFile); saveToKeyfile(!pedited || pedited->wavelet.hueskin, "Wavelet", "Hueskin", wavelet.hueskin.toVector(), keyFile); saveToKeyfile(!pedited || pedited->wavelet.edgrad, "Wavelet", "Edgrad", wavelet.edgrad, keyFile); + saveToKeyfile(!pedited || pedited->wavelet.edgeffect, "Wavelet", "Edgeffect", wavelet.edgeffect, keyFile); saveToKeyfile(!pedited || pedited->wavelet.edgval, "Wavelet", "Edgval", wavelet.edgval, keyFile); saveToKeyfile(!pedited || pedited->wavelet.edgthresh, "Wavelet", "ThrEdg", wavelet.edgthresh, keyFile); saveToKeyfile(!pedited || pedited->wavelet.avoid, "Wavelet", "AvoidColorShift", wavelet.avoid, keyFile); @@ -4956,6 +4961,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); @@ -6587,6 +6593,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); @@ -6610,6 +6617,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Wavelet", "ChromaLink", pedited, wavelet.chro, pedited->wavelet.chro); assignFromKeyfile(keyFile, "Wavelet", "Contrast", pedited, wavelet.contrast, pedited->wavelet.contrast); assignFromKeyfile(keyFile, "Wavelet", "Edgrad", pedited, wavelet.edgrad, pedited->wavelet.edgrad); + assignFromKeyfile(keyFile, "Wavelet", "Edgeffect", pedited, wavelet.edgeffect, pedited->wavelet.edgeffect); assignFromKeyfile(keyFile, "Wavelet", "Edgval", pedited, wavelet.edgval, pedited->wavelet.edgval); assignFromKeyfile(keyFile, "Wavelet", "ThrEdg", pedited, wavelet.edgthresh, pedited->wavelet.edgthresh); assignFromKeyfile(keyFile, "Wavelet", "ThresholdResidShadow", pedited, wavelet.thr, pedited->wavelet.thr); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 4aaefca26..66c37edf4 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1715,6 +1715,7 @@ struct WaveletParams { Glib::ustring HSmethod; double sigma; double offset; + double lowthr; int rescon; int resconH; int reschro; @@ -1738,6 +1739,7 @@ struct WaveletParams { int edgeampli; int contrast; int edgrad; + double edgeffect; int edgval; int edgthresh; int thr; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 2debe14ac..483539afd 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -522,6 +522,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; @@ -544,6 +545,7 @@ void ParamsEdited::set(bool v) wavelet.chro = v; wavelet.contrast = v; wavelet.edgrad = v; + wavelet.edgeffect = v; wavelet.edgval = v; wavelet.edgthresh = v; wavelet.thr = v; @@ -1577,6 +1579,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; @@ -1600,6 +1603,7 @@ void ParamsEdited::initFrom(const std::vector& wavelet.chro = wavelet.chro && p.wavelet.chro == other.wavelet.chro; wavelet.contrast = wavelet.contrast && p.wavelet.contrast == other.wavelet.contrast; wavelet.edgrad = wavelet.edgrad && p.wavelet.edgrad == other.wavelet.edgrad; + wavelet.edgeffect = wavelet.edgeffect && p.wavelet.edgeffect == other.wavelet.edgeffect; wavelet.edgval = wavelet.edgval && p.wavelet.edgval == other.wavelet.edgval; wavelet.edgthresh = wavelet.edgthresh && p.wavelet.edgthresh == other.wavelet.edgthresh; wavelet.thr = wavelet.thr && p.wavelet.thr == other.wavelet.thr; @@ -5341,10 +5345,18 @@ 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; } + if (wavelet.edgeffect) { + toEdit.wavelet.edgeffect = mods.wavelet.edgeffect; + } + if (wavelet.resblurc) { toEdit.wavelet.resblurc = mods.wavelet.resblurc; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index af55896d6..f3594cb4e 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -968,6 +968,7 @@ struct WaveletParamsEdited { bool Dirmethod; bool sigma; bool offset; + bool lowthr; bool rescon; bool resconH; bool reschro; @@ -991,6 +992,7 @@ struct WaveletParamsEdited { bool chroma; bool contrast; bool edgrad; + bool edgeffect; bool edgval; bool edgthresh; bool thr; diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc index 2e444ff3d..89e05346a 100644 --- a/rtgui/wavelet.cc +++ b/rtgui/wavelet.cc @@ -84,12 +84,13 @@ 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))), resblur(Gtk::manage(new Adjuster(M("TP_WAVELET_RESBLUR"), 0, 100, 1, 0))), resblurc(Gtk::manage(new Adjuster(M("TP_WAVELET_RESBLURC"), 0, 100, 1, 0))), - bluwav(Gtk::manage(new Adjuster(M("TP_WAVELET_BLUWAV"), 0.0, 100.0, 0.5, 50.))), + bluwav(Gtk::manage(new Adjuster(M("TP_WAVELET_BLUWAV"), 0.05, 2.5, 0.5, 50.))), tmrs(Gtk::manage(new Adjuster(M("TP_WAVELET_TMSTRENGTH"), -1.0, 2.0, 0.01, 0.0))), edgs(Gtk::manage(new Adjuster(M("TP_WAVELET_TMEDGS"), 0.1, 4.0, 0.01, 1.4))), scale(Gtk::manage(new Adjuster(M("TP_WAVELET_TMSCALE"), 0.1, 10.0, 0.01, 1.0))), @@ -105,6 +106,7 @@ Wavelet::Wavelet() : radius(Gtk::manage(new Adjuster(M("TP_WAVELET_RADIUS"), 0, 100, 1, 40))), skinprotect(Gtk::manage(new Adjuster(M("TP_WAVELET_SKIN"), -100, 100, 1, 0.))), edgrad(Gtk::manage(new Adjuster(M("TP_WAVELET_EDRAD"), 0, 100, 1, 15))), + edgeffect(Gtk::manage(new Adjuster(M("TP_WAVELET_EDEFFECT"), 0.05, 2.5, 0.01, 1.))), edgval(Gtk::manage(new Adjuster(M("TP_WAVELET_EDVAL"), 0, 100, 1, 0))), edgthresh(Gtk::manage(new Adjuster(M("TP_WAVELET_EDGTHRESH"), -50, 100, 1, 10))), strength(Gtk::manage(new Adjuster(M("TP_WAVELET_STRENGTH"), 0, 100, 1, 100))), @@ -190,11 +192,12 @@ 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"); EvWavresblurc = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_BLURCWAV"); - + EvWavedgeffect = m->newEvent(DIRPYREQUALIZER, "HISTORY_MSG_EDGEFFECT"); expsettings->signal_button_release_event().connect_notify(sigc::bind(sigc::mem_fun(this, &Wavelet::foldAllButMe), expsettings)); expcontrast->signal_button_release_event().connect_notify(sigc::bind(sigc::mem_fun(this, &Wavelet::foldAllButMe), expcontrast)); @@ -359,6 +362,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); @@ -541,10 +547,14 @@ Wavelet::Wavelet() : // Edge Sharpness ToolParamBlock* const edgBox = Gtk::manage(new ToolParamBlock()); + edgeffect->setAdjusterListener(this); + edgBox->pack_start(*edgeffect); + edgeffect->set_tooltip_markup(M("TP_WAVELET_EDEFFECT_TOOLTIP")); edgval->setAdjusterListener(this); edgBox->pack_start(*edgval); + edgrad->setAdjusterListener(this); edgBox->pack_start(*edgrad); edgrad->set_tooltip_markup(M("TP_WAVELET_EDRAD_TOOLTIP")); @@ -1321,6 +1331,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); @@ -1337,6 +1348,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) chro->setValue(pp->wavelet.chro); contrast->setValue(pp->wavelet.contrast); edgrad->setValue(pp->wavelet.edgrad); + edgeffect->setValue(pp->wavelet.edgeffect); edgval->setValue(pp->wavelet.edgval); edgthresh->setValue(pp->wavelet.edgthresh); thr->setValue(pp->wavelet.thr); @@ -1481,6 +1493,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); @@ -1523,6 +1536,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) lipst->set_inconsistent(!pedited->wavelet.lipst); contrast->setEditedState(pedited->wavelet.contrast ? Edited : UnEdited); edgrad->setEditedState(pedited->wavelet.edgrad ? Edited : UnEdited); + edgeffect->setEditedState(pedited->wavelet.edgeffect ? Edited : UnEdited); edgval->setEditedState(pedited->wavelet.edgval ? Edited : UnEdited); thr->setEditedState(pedited->wavelet.thr ? Edited : UnEdited); thrH->setEditedState(pedited->wavelet.thrH ? Edited : UnEdited); @@ -1672,6 +1686,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(); @@ -1694,6 +1709,7 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pp->wavelet.lipst = lipst->get_active(); pp->wavelet.contrast = contrast->getValue(); pp->wavelet.edgrad = edgrad->getValue(); + pp->wavelet.edgeffect = edgeffect->getValue(); pp->wavelet.edgval = edgval->getValue(); pp->wavelet.edgthresh = edgthresh->getValue(); pp->wavelet.thr = thr->getValue(); @@ -1791,6 +1807,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(); @@ -1814,6 +1831,7 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pedited->wavelet.chro = chro->getEditedState(); pedited->wavelet.contrast = contrast->getEditedState(); pedited->wavelet.edgrad = edgrad->getEditedState(); + pedited->wavelet.edgeffect = edgeffect->getEditedState(); pedited->wavelet.edgval = edgval->getEditedState(); pedited->wavelet.thr = thr->getEditedState(); pedited->wavelet.thrH = thrH->getEditedState(); @@ -2035,6 +2053,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); @@ -2058,6 +2077,7 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit chro->setDefault(defParams->wavelet.chro); contrast->setDefault(defParams->wavelet.contrast); edgrad->setDefault(defParams->wavelet.edgrad); + edgeffect->setDefault(defParams->wavelet.edgeffect); edgval->setDefault(defParams->wavelet.edgval); edgthresh->setDefault(defParams->wavelet.edgthresh); thr->setDefault(defParams->wavelet.thr); @@ -2102,6 +2122,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); @@ -2125,6 +2146,7 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit chro->setDefaultEditedState(pedited->wavelet.chro ? Edited : UnEdited); contrast->setDefaultEditedState(pedited->wavelet.contrast ? Edited : UnEdited); edgrad->setDefaultEditedState(pedited->wavelet.edgrad ? Edited : UnEdited); + edgeffect->setDefaultEditedState(pedited->wavelet.edgeffect ? Edited : UnEdited); edgval->setDefaultEditedState(pedited->wavelet.edgval ? Edited : UnEdited); edgthresh->setDefault(defParams->wavelet.edgthresh); thr->setDefaultEditedState(pedited->wavelet.thr ? Edited : UnEdited); @@ -2158,6 +2180,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); @@ -2181,6 +2204,7 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit chro->setDefaultEditedState(Irrelevant); contrast->setDefaultEditedState(Irrelevant); edgrad->setDefaultEditedState(Irrelevant); + edgeffect->setDefaultEditedState(Irrelevant); edgval->setDefaultEditedState(Irrelevant); edgthresh->setDefaultEditedState(Irrelevant); thr->setDefaultEditedState(Irrelevant); @@ -2692,6 +2716,7 @@ void Wavelet::setBatchMode(bool batchMode) curveEditorGAM->setBatchMode(batchMode); sigma->showEditedCB(); offset->showEditedCB(); + lowthr->showEditedCB(); rescon->showEditedCB(); resconH->showEditedCB(); reschro->showEditedCB(); @@ -2715,6 +2740,7 @@ void Wavelet::setBatchMode(bool batchMode) chro->showEditedCB(); contrast->showEditedCB(); edgrad->showEditedCB(); + edgeffect->showEditedCB(); edgval->showEditedCB(); edgthresh->showEditedCB(); thr->showEditedCB(); @@ -2781,6 +2807,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) { @@ -2841,6 +2869,8 @@ void Wavelet::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(EvWavedgeampli, edgeampli->getTextValue()); } else if (a == edgrad) { listener->panelChanged(EvWavedgrad, edgrad->getTextValue()); + } else if (a == edgeffect) { + listener->panelChanged(EvWavedgeffect, edgeffect->getTextValue()); } else if (a == edgval) { listener->panelChanged(EvWavedgval, edgval->getTextValue()); } else if (a == thres) { diff --git a/rtgui/wavelet.h b/rtgui/wavelet.h index 67a45b5ac..b73339973 100644 --- a/rtgui/wavelet.h +++ b/rtgui/wavelet.h @@ -83,10 +83,12 @@ private: rtengine::ProcEvent EvWavchrwav; rtengine::ProcEvent EvWavoldsh; rtengine::ProcEvent EvWavoffset; + rtengine::ProcEvent EvWavlowthr; rtengine::ProcEvent EvWavbluwav; rtengine::ProcEvent EvWavblshape; rtengine::ProcEvent EvWavresblur; rtengine::ProcEvent EvWavresblurc; + rtengine::ProcEvent EvWavedgeffect; void foldAllButMe(GdkEventButton* event, MyExpander *expander); @@ -184,6 +186,7 @@ private: Adjuster* correctionch[9]; Adjuster* const sigma; Adjuster* const offset; + Adjuster* const lowthr; Adjuster* const rescon; Adjuster* const resconH; Adjuster* const reschro; @@ -205,6 +208,7 @@ private: Adjuster* const radius; Adjuster* const skinprotect; Adjuster* const edgrad; + Adjuster* const edgeffect; Adjuster* const edgval; Adjuster* const edgthresh; Adjuster* const strength;