diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais
index e9d891b8e..310dfcfd4 100644
--- a/rtdata/languages/Francais
+++ b/rtdata/languages/Francais
@@ -1878,7 +1878,7 @@ TP_LOCALLAB_DELTAD;Delta balance
TP_LOCALLAB_DELTAEC;Masque ΔE Image
TP_LOCALLAB_DENOIS;Ψ Réduction du bruit
TP_LOCALLAB_DENOI_EXP;Réduction du bruit
-TP_LOCALLAB_DENOIQUA_TOOLTIP;Conservatif préserve les fréquences basses, alors que agressif tend à les effacer
+TP_LOCALLAB_DENOIQUA_TOOLTIP;Conservatif préserve les fréquences basses, alors que agressif tend à les effacer.\nConservatif et agressif utilisent les ondelletes et DCT et peuvent être utilisées en conjonction avec "débruitage par morceaux - luminance"
TP_LOCALLAB_DENOIEQUAL_TOOLTIP;Equilibre l'action de denoise luminance entre les ombres et les lumières
TP_LOCALLAB_DENOI1_EXP;De-bruite basé sur masque luminance
TP_LOCALLAB_DENOI2_EXP;Récupération basée sur masque luminance
@@ -2192,6 +2192,15 @@ TP_LOCALLAB_MRTHR;Image Originale
TP_LOCALLAB_MRTWO;Short Curves 'L' Mask
TP_LOCALLAB_MULTIPL_TOOLTIP;Autorise la retouche des tons sur une large plage : -18EV +4EV. Le remier curseur agit sur -18EV and -6EV. Le dernier curseur agit sur les tons au-dessus de 4EV
TP_LOCALLAB_NEIGH;Rayon
+TP_LOCALLAB_NLDENOISE_TOOLTIP;"Récupération des détails" agit sur un Laplacien pour privilégier l'action de denoise sur les aplats plutôt que sur les structures.
+TP_LOCALLAB_NLDENOISENLPAT_TOOLTIP;Agir sur ce curseur pour adapter le niveau de débruitage à la taille des objets à traiter.
+TP_LOCALLAB_NLDENOISENLRAD_TOOLTIP;Plus la valeur sera importante, plus le débruitage sera intense.\nMais cela a une forte incidence sur les temps de traitement.
+TP_LOCALLAB_NLFRAME_TOOLTIP;"Débruitage par morceaux" réalise une moyenne de la totalité des valeurs des pixels contenus dans l'image, pondérées en fonction de leur similarité avec le résultat attendu (pixel cible).\nL'algoritme permet d’amoindrir la perte de détails au sein de l'image.\nSeul le bruit de luminance est pris en compte, le bruit de chrominance est traité de manière plus performante par le couple ondelettes / Fourier (DCT).\nPeut être utilisé en conjonction avec 'ondelettes' ou isolé.\nLa taille du RT-Spot doit être supérieure à 150x150 pixels (sortie TIF/JPG).
+TP_LOCALLAB_NLFRA;Débruitage par morceaux - Luminance
+TP_LOCALLAB_NLLUM;Force
+TP_LOCALLAB_NLDET;Récupération des détails
+TP_LOCALLAB_NLPAT;Taille maximum du morceau
+TP_LOCALLAB_NLRAD;Taille maximum du rayon
TP_LOCALLAB_NOISE_TOOLTIP;Ajoute du bruit de luminance
TP_LOCALLAB_NOISECHROCOARSE;Chroma gros (Ond)
TP_LOCALLAB_NOISECHROC_TOOLTIP;Si supérieur à zéro, algorithme haute qualité est activé.\nGros est sélectionné si curseur >=0.2
@@ -2211,7 +2220,7 @@ TP_LOCALLAB_OFFSETWAV;Décalage
TP_LOCALLAB_OPACOL;Opacité
TP_LOCALLAB_ORIGLC;Fusion seulement avec image originale
TP_LOCALLAB_ORRETILAP_TOOLTIP;Agit sur un deuxième seuil Laplacien, pour prendre en compte ΔE pour différencier l'action nottament avec l'arrière plan (différent de Etendue)
-TP_LOCALLAB_ORRETISTREN_TOOLTIP;Aagit sur un seuil Laplacien, plus grande est l'action, plus les différences de contraste seront réduites
+TP_LOCALLAB_ORRETISTREN_TOOLTIP;Agit sur un seuil Laplacien, plus grande est l'action, plus les différences de contraste seront réduites
TP_LOCALLAB_PASTELS2;Vibrance
TP_LOCALLAB_PDE;Atténuation de Contraste - Compression dynamique
TP_LOCALLAB_PDEFRA;Contraste atténuation ƒ
@@ -2222,8 +2231,12 @@ TP_LOCALLAB_PREVSHOW;Montrer tous les réglages
TP_LOCALLAB_PROXI;ΔE Affaiblissement
TP_LOCALLAB_QUALCURV_METHOD;Types de Courbes
TP_LOCALLAB_QUAL_METHOD;Qualité globale
+TP_LOCALLAB_QUACONSER;Conservatif
+TP_LOCALLAB_QUAAGRES;Aggressif
+TP_LOCALLAB_QUANONEWAV;Débruitage par morceaux - luminance seulement
+TP_LOCALLAB_QUANONEALL;Rien
TP_LOCALLAB_RADIUS;Rayon
-TP_LOCALLAB_RADIUS_TOOLTIP;Above Radius 30 Use Fast Fourier Transform
+TP_LOCALLAB_RADIUS_TOOLTIP;Au-dessus de Rayon 30 Utilise 'Fast Fourier Transform'
TP_LOCALLAB_RADMASKCOL;Rayon adoucir
TP_LOCALLAB_RECT;Rectangle
TP_LOCALLAB_RECURS;Réferences Récursives
diff --git a/rtdata/languages/default b/rtdata/languages/default
index dd57d7106..6b83c3c81 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -1278,6 +1278,11 @@ HISTORY_MSG_1030;Local - reti recovery threshold
HISTORY_MSG_1031;Local - reti threshold mask low
HISTORY_MSG_1032;Local - reti threshold mask high
HISTORY_MSG_1033;Local - reti decay
+HISTORY_MSG_1034;Local - Nlmeans - strength
+HISTORY_MSG_1035;Local - Nlmeans - detail
+HISTORY_MSG_1036;Local - Nlmeans - patch
+HISTORY_MSG_1037;Local - Nlmeans - radius
+HISTORY_MSG_1038;Local - Nlmeans - gamma
HISTORY_MSG_BLSHAPE;Blur by level
HISTORY_MSG_BLURCWAV;Blur chroma
HISTORY_MSG_BLURWAV;Blur luminance
@@ -2244,7 +2249,7 @@ TP_DIRPYRDENOISE_MAIN_GAMMA_TOOLTIP;Gamma varies noise reduction strength across
TP_DIRPYRDENOISE_MAIN_MODE;Mode
TP_DIRPYRDENOISE_MAIN_MODE_AGGRESSIVE;Aggressive
TP_DIRPYRDENOISE_MAIN_MODE_CONSERVATIVE;Conservative
-TP_DIRPYRDENOISE_MAIN_MODE_TOOLTIP;"Conservative" preserves low frequency chroma patterns, while "aggressive" obliterates them.
+TP_DIRPYRDENOISE_MAIN_MODE_TOOLTIP;Conservative preserves low frequency chroma patterns, while aggressive obliterates them.
TP_DIRPYRDENOISE_MEDIAN_METHOD;Median method
TP_DIRPYRDENOISE_MEDIAN_METHOD_CHROMINANCE;Chroma only
TP_DIRPYRDENOISE_MEDIAN_METHOD_LAB;L*a*b*
@@ -2606,11 +2611,11 @@ TP_LOCALLAB_DENOIEQUAL_TOOLTIP;Allows you to carry out more or less noise reduct
TP_LOCALLAB_DENOI1_EXP;Denoise based on luminance mask
TP_LOCALLAB_DENOI2_EXP;Recovery based on luminance mask
TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP;Allows you to recover luminance detail by progressively applying a Fourier transform (DCT).
-TP_LOCALLAB_DENOIQUA_TOOLTIP;Conservative mode preserves low frequency detail. “Aggressive” mode removes low frequency detail.
+TP_LOCALLAB_DENOIQUA_TOOLTIP;Conservative mode preserves low frequency detail. Aggressive mode removes low frequency detail.\nConservative and Aggressive use wavelets and DCT, can be used in conjunction with "Non-local Means - Luminance".
TP_LOCALLAB_DENOIS;Ψ Denoise
TP_LOCALLAB_DENOITHR_TOOLTIP;Adjusts edge detection to help reduce noise in uniform, low-contrast areas.
TP_LOCALLAB_DENOI_EXP;Denoise
-TP_LOCALLAB_DENOI_TOOLTIP;This module can be used for noise reduction either on its own (at the end of the processing pipeline) or in addition to the Noise Reduction module in the Detail tab (which works at the beginning of the pipeline).\n Scope allows you to differentiate the action based on color (deltaE).\n\n You can refine the result with a "Median filter" or a "Guided Filter" (Soft radius).
+TP_LOCALLAB_DENOI_TOOLTIP;This module can be used for noise reduction either on its own (at the end of the processing pipeline) or in addition to the Noise Reduction module in the Detail tab (which works at the beginning of the pipeline).\n Scope allows you to differentiate the action based on color (deltaE).
TP_LOCALLAB_DEPTH;Depth
TP_LOCALLAB_DETAIL;Local contrast
TP_LOCALLAB_DETAILFRA;Edge detection
@@ -2819,9 +2824,9 @@ TP_LOCALLAB_MASKCURVE_TOOLTIP;The 3 curves are set to 1 (maximum) by default:\nC
TP_LOCALLAB_MASKDDECAY;Decay strength
TP_LOCALLAB_MASKDECAY_TOOLTIP;Manages the rate of decay for the gray levels in the mask.\n Decay = 1 linear, Decay > 1 sharper parabolic transitions, Decay < 1 more gradual transitions
TP_LOCALLAB_MASKH;Hue curve
-TP_LOCALLAB_MASKLC_TOOLTIP;This allows you to target the denoise based on the image luminance information contained in the L(L) or LC(H) mask (Mask and Modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n if the mask is very dark - below the threshold 'dark' - denoise will be increased if reinforce > 1.\n if the mask is clear - above the threshold 'light' - denoise will be progressively cancelled.\n between the two, denoise will be maintained at the settings without mask.
-TP_LOCALLAB_MASKDE_TOOLTIP;Used to direct the Denoise based on the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n If the mask is below the ‘dark’ threshold, then the Denoise will be applied progressively.\n if the mask is above the ‘light’ threshold, then the Denoise will be applied progressively.\n Between the two, the image settings without the Denoise will be maintained, unless you act on the sliders "Gray area luminance denoise" or "Gray area chrominance denoise".
-TP_LOCALLAB_MASKGF_TOOLTIP;Used to direct the Guided Filter based on the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n If the mask is below the ‘dark’ threshold, then the GF will be applied progressively.\n if the mask is above the ‘light’ threshold, then the GF will be applied progressively.\n Between the two, the image settings without the GF will be maintained.
+TP_LOCALLAB_MASKLC_TOOLTIP;This allows you to target the denoise based on the image luminance information contained in the L(L) or LC(H) mask (Mask and Modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n 'Dark area luminance threshold'. If 'Reinforce denoise in dark and light areas' > 1 the denoise is progressively increased from 0% at the threshold settings to 100% at the maximum black value (determined by mask).\n 'Light area luminance threshold' .The denoise is progressively decreased from 100% at the threshold setting to 0% at the maximum white value (determined by mask).\n In the area between the two thresholds, the denoise settings are not affected by the mask.
+TP_LOCALLAB_MASKDE_TOOLTIP;Used to target the denoise as a function of the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n If the mask is below the ‘dark’ threshold, then the Denoise will be applied progressively.\n if the mask is above the ‘light’ threshold, then the Denoise will be applied progressively.\n Between the two, the image settings without the Denoise will be maintained, unless you adjust the sliders "Gray area luminance denoise" or "Gray area chrominance denoise".
+TP_LOCALLAB_MASKGF_TOOLTIP;Used to target the Guided Filter as a function of the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n If the mask is below the ‘dark’ threshold, then the GF will be applied progressively.\n if the mask is above the ‘light’ threshold, then the GF will be applied progressively.\n Between the two, the image settings without the GF will be maintained.
TP_LOCALLAB_MASKRECOL_TOOLTIP;Used to modulate the effect of the Color and Light settings based on the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n The ‘dark’ and ‘light’ areas below the dark threshold and above the light threshold will be restored progressively to their original values prior to being modified by the Color and Light settings \n In between these two areas, the full value of the Color and Light settings will be applied
TP_LOCALLAB_MASKREEXP_TOOLTIP;Used to modulate the effect of the 'Dynamic range and Exposure' settings based on the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n The ‘dark’ and ‘light’ areas below the dark threshold and above the light threshold will be restored progressively to their original values prior to being modified by the 'Dynamic range and Exposure' settings \n In between these two areas, the full value of the 'Dynamic range and Exposure' settings will be applied
TP_LOCALLAB_MASKRESH_TOOLTIP;Used to modulate the effect of the Shadows Highlights settings based on the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n The ‘dark’ and ‘light’ areas below the dark threshold and above the light threshold will be restored progressively to their original values prior to being modified by the Shadows Highlights settings \n In between these two areas, the full value of the Shadows Highlights settings will be applied
@@ -2917,6 +2922,17 @@ TP_LOCALLAB_MRTHR;Original Image
TP_LOCALLAB_MRTWO;Short Curves 'L' Mask
TP_LOCALLAB_MULTIPL_TOOLTIP;Wide-range tone adjustment: -18EV to +4EV. The first slider acts on very dark tones between -18EV and -6EV. The last slider acts on light tones up to 4EV
TP_LOCALLAB_NEIGH;Radius
+TP_LOCALLAB_NLDENOISE_TOOLTIP;“Detail recovery” acts on a Laplacian transform to target uniform areas rather than areas with detail.
+TP_LOCALLAB_NLDENOISENLPAT_TOOLTIP;Use this slider to adapt the amount of denoise to the size of the objects to be processed.
+TP_LOCALLAB_NLDENOISENLRAD_TOOLTIP;Higher values increase denoise at the expense of processing time.
+TP_LOCALLAB_NLDENOISENLGAM_TOOLTIP;Lower values preserve details and texture, higher values increase denoise.
+TP_LOCALLAB_NLFRA;Non-local Means - Luminance
+TP_LOCALLAB_NLFRAME_TOOLTIP;Non-local means denoising takes a mean of all pixels in the image, weighted by how similar they are to the target pixel.\nReduces loss of detail compared with local mean algorithms.\nOnly luminance noise is taken into account. Chrominance noise is best processed using wavelets and Fourier transforms (DCT).\nCan be used in conjunction with 'Luminance denoise by level' or on its own.\nRT-Spot size must be greater than 150x150 pixels (Output).
+TP_LOCALLAB_NLLUM;Strength
+TP_LOCALLAB_NLDET;Detail recovery
+TP_LOCALLAB_NLGAM;Gamma
+TP_LOCALLAB_NLPAT;Maximum patch size
+TP_LOCALLAB_NLRAD;Maximum radius size
TP_LOCALLAB_NOISECHROCOARSE;Coarse chroma (Wav)
TP_LOCALLAB_NOISECHROC_TOOLTIP;If superior to zero, high quality algorithm is enabled.\nCoarse is for slider >=0.02
TP_LOCALLAB_NOISECHRODETAIL;Chroma detail recovery (DCT ƒ)
@@ -2948,6 +2964,10 @@ TP_LOCALLAB_PREVSHOW;Show additional settings
TP_LOCALLAB_PROXI;ΔE decay
TP_LOCALLAB_QUALCURV_METHOD;Curve type
TP_LOCALLAB_QUAL_METHOD;Global quality
+TP_LOCALLAB_QUACONSER;Conservative
+TP_LOCALLAB_QUAAGRES;Aggressive
+TP_LOCALLAB_QUANONEWAV;Non-local means only
+TP_LOCALLAB_QUANONEALL;Off
TP_LOCALLAB_RADIUS;Radius
TP_LOCALLAB_RADIUS_TOOLTIP;Uses a Fast Fourier Transform for radius > 30
TP_LOCALLAB_RADMASKCOL;Smooth radius
@@ -3130,7 +3150,7 @@ TP_LOCALLAB_VIS_TOOLTIP;Click to show/hide selected Control Spot.\nCtr
TP_LOCALLAB_WAMASKCOL;Ψ Mask Wavelet level
TP_LOCALLAB_WARM;Warm/Cool & Color artifacts
TP_LOCALLAB_WARM_TOOLTIP;This slider uses the CIECAM algorithm and acts as a White Balance control to make the color temperature of the selected area warmer or cooler.\nIt can also reduce color artifacts in some cases.
-TP_LOCALLAB_WASDEN_TOOLTIP;Luminance noise reduction: the left-hand side of the curve including the 'separation point' corresponds to the first 3 levels 0, 1, 2 (fine detail). The right hand side of the curve corresponds to the coarser details (level 3, 4, 5, 6).
+TP_LOCALLAB_WASDEN_TOOLTIP;Luminance noise reduction: the left-hand side of the curve including the dark-gray/light-gray boundary corresponds to the first 3 levels 0, 1, 2 (fine detail). The right hand side of the curve corresponds to the coarser details (level 3, 4, 5, 6).
TP_LOCALLAB_WAT_BALTHRES_TOOLTIP;Balances the action within each level.
TP_LOCALLAB_WAT_BLURLC_TOOLTIP;The default blur setting affects all 3 L*a* b* components (luminance and colour).\nWhen checked, only luminance is blurred.
TP_LOCALLAB_WAT_CLARIC_TOOLTIP;“Merge chroma” is used to select the intensity of the desired effect on chrominance.
@@ -3689,7 +3709,7 @@ TP_WAVELET_MIXNOISE;Noise
TP_WAVELET_NEUTRAL;Neutral
TP_WAVELET_NOIS;Denoise
TP_WAVELET_NOISE;Denoise and Refine
-TP_WAVELET_NOISE_TOOLTIP;If level 4 luminance denoise superior to 50, mode Agressive is used.\nIf chrominance coarse superior to 20, mode Agressive is used.
+TP_WAVELET_NOISE_TOOLTIP;If level 4 luminance denoise superior to 50, mode Aggressive is used.\nIf chrominance coarse superior to 20, mode Aggressive is used.
TP_WAVELET_NPHIGH;High
TP_WAVELET_NPLOW;Low
TP_WAVELET_NPNONE;None
@@ -3704,8 +3724,8 @@ TP_WAVELET_OPACITYWL_TOOLTIP;Modify the final local contrast at the end of the w
TP_WAVELET_PASTEL;Pastel chroma
TP_WAVELET_PROC;Process
TP_WAVELET_PROTAB;Protection
-TP_WAVELET_QUAAGRES;Agressive
-TP_WAVELET_QUANONE;None
+TP_WAVELET_QUAAGRES;Aggressive
+TP_WAVELET_QUANONE;Off
TP_WAVELET_QUACONSER;Conservative
TP_WAVELET_RADIUS;Radius shadows - highlight
TP_WAVELET_RANGEAB;Range a and b %
diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc
index 66f12b668..474196843 100644
--- a/rtengine/FTblockDN.cc
+++ b/rtengine/FTblockDN.cc
@@ -436,6 +436,7 @@ void ImProcFunctions::Median_Denoise(float **src, float **dst, float upperBound,
}
+
void ImProcFunctions::Tile_calc(int tilesize, int overlap, int kall, int imwidth, int imheight, int &numtiles_W, int &numtiles_H, int &tilewidth, int &tileheight, int &tileWskip, int &tileHskip)
{
diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h
index 4436c2f1e..4c656fd9f 100644
--- a/rtengine/improcfun.h
+++ b/rtengine/improcfun.h
@@ -136,6 +136,11 @@ public:
TYPE_7X7,
TYPE_9X9
};
+enum class BlurType {
+ OFF,
+ BOX,
+ GAUSS
+};
double lumimul[3];
@@ -252,6 +257,8 @@ public:
float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope, float balance, float balanceh);
void discrete_laplacian_threshold(float * data_out, const float * data_in, size_t nx, size_t ny, float t);
void laplacian(const array2D &src, array2D &dst, int bfw, int bfh, float threshold, float ceiling, float factor, bool multiThread);
+ void detail_mask(const array2D &src, array2D &mask, int bfw, int bfh, float scaling, float threshold, float ceiling, float factor, BlurType blur_type, float blur, bool multithread);
+ void NLMeans(float **img, int strength, int detail_thresh, int patch, int radius, float gam, int bfw, int bfh, float scale, bool multithread);
void rex_poisson_dct(float * data, size_t nx, size_t ny, double m);
void mean_dt(const float * data, size_t size, double& mean_p, double& dt_p);
diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc
index 6e6ab0a1b..01fc1a9f4 100644
--- a/rtengine/iplocallab.cc
+++ b/rtengine/iplocallab.cc
@@ -50,7 +50,7 @@
#include "StopWatch.h"
#include "guidedfilter.h"
#include "boxblur.h"
-
+#include "rescale.h"
#pragma GCC diagnostic warning "-Wall"
#pragma GCC diagnostic warning "-Wextra"
@@ -391,6 +391,29 @@ void SobelCannyLuma(float **sobelL, float **luma, int bfw, int bfh, float radius
}
}
+float igammalog(float x, float p, float s, float g2, float g4)
+{
+ return x <= g2 ? x / s : pow_F((x + g4) / (1.f + g4), p);//continuous
+}
+
+#ifdef __SSE2__
+vfloat igammalog(vfloat x, vfloat p, vfloat s, vfloat g2, vfloat g4)
+{
+ return x <= g2 ? x / s : pow_F((x + g4) / (1.f + g4), p);//continuous
+}
+#endif
+
+float gammalog(float x, float p, float s, float g3, float g4)
+{
+ return x <= g3 ? x * s : (1.f + g4) * xexpf(xlogf(x) / p) - g4;//continuous
+}
+
+#ifdef __SSE2__
+vfloat gammalog(vfloat x, vfloat p, vfloat s, vfloat g3, vfloat g4)
+{
+ return x <= g3 ? x * s : (1.f + g4) * xexpf(xlogf(x) / p) - g4;//continuous
+}
+#endif
}
namespace rtengine
@@ -627,6 +650,11 @@ struct local_params {
int noiselequal;
float noisechrodetail;
float bilat;
+ int nlstr;
+ int nldet;
+ int nlpat;
+ int nlrad;
+ float nlgam;
float noiselc;
float noiselc4;
float noiselc5;
@@ -880,13 +908,19 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall
lp.chromet = 2;
}
+
+
+
if (locallab.spots.at(sp).quamethod == "cons") {
lp.quamet = 0;
} else if (locallab.spots.at(sp).quamethod == "agre") {
lp.quamet = 1;
- } else if (locallab.spots.at(sp).quamethod == "none") {
+ } else if (locallab.spots.at(sp).quamethod == "nlmean") {
lp.quamet = 2;
+ } else if (locallab.spots.at(sp).quamethod == "none") {
+ lp.quamet = 3;
}
+// printf("lpqualmet=%i\n", lp.quamet);
if (locallab.spots.at(sp).shMethod == "std") {
lp.shmeth = 0;
@@ -1543,6 +1577,11 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall
lp.noisecc = local_noisecc;
lp.sensden = local_sensiden;
lp.bilat = locallab.spots.at(sp).bilateral;
+ lp.nldet = locallab.spots.at(sp).nldet;
+ lp.nlstr = locallab.spots.at(sp).nlstr;
+ lp.nlpat = locallab.spots.at(sp).nlpat;
+ lp.nlrad = locallab.spots.at(sp).nlrad;
+ lp.nlgam = locallab.spots.at(sp).nlgam;
lp.adjch = (float) locallab.spots.at(sp).adjblur;
lp.strengt = streng;
lp.gamm = gam;
@@ -3512,6 +3551,8 @@ void ImProcFunctions::InverseReti_Local(const struct local_params & lp, const fl
}
}
+
+
void ImProcFunctions::InverseBlurNoise_Local(LabImage * originalmask, const struct local_params & lp, const float hueref, const float chromaref, const float lumaref, LabImage * original, LabImage * transformed, const LabImage * const tmp1, int cx, int cy, int sk)
{
// BENCHFUN
@@ -8961,7 +9002,7 @@ void ImProcFunctions::fftw_denoise(int sk, int GW, int GH, int max_numblox_W, in
void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * slidb, int aut, bool noiscfactiv, const struct local_params & lp, LabImage * originalmaskbl, LabImage * bufmaskblurbl, int levred, float huerefblur, float lumarefblur, float chromarefblur, LabImage * original, LabImage * transformed, int cx, int cy, int sk, const LocwavCurve& locwavCurvehue, bool locwavhueutili)
{
-
+ BENCHFUN
//local denoise
//all these variables are to prevent use of denoise when non necessary
// but with qualmet = 2 (default for best quality) we must denoise chroma with little values to prevent artifacts due to variations of Hue
@@ -8971,9 +9012,16 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl
bool execdenoi = noiscfactiv && ((lp.colorena && execcolor) || (lp.tonemapena && lp.strengt != 0.f) || (lp.cbdlena && execbdl) || (lp.sfena && lp.strng > 0.f) || (lp.lcena && lp.lcamount > 0.f) || (lp.sharpena && lp.shrad > 0.42) || (lp.retiena && lp.str > 0.f) || (lp.exposena && lp.expcomp != 0.f) || (lp.expvib && lp.past != 0.f));
bool execmaskden = (lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4) && lp.smasktyp != 0;
- if (((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.wavcurvedenoi || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f
+ const int ys = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0);
+ const int ye = rtengine::min(static_cast(lp.yc + lp.ly) - cy, original->H);
+ const int xs = rtengine::max(static_cast(lp.xc - lp.lxL) - cx, 0);
+ const int xe = rtengine::min(static_cast(lp.xc + lp.lx) - cx, original->W);
+ const int hspot = ye - ys;
+ const int wspot = xe - xs;
+
+ if (((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.nlstr > 0 || lp.wavcurvedenoi || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f
// || lp.showmaskblmet == 2 || lp.enablMask || lp.showmaskblmet == 3 || lp.showmaskblmet == 4 || aut == 1 || aut == 2) && lp.denoiena) || execdenoi) { // sk == 1 ??
- || execmaskden || aut == 1 || aut == 2) && lp.denoiena && lp.quamet != 2) || execdenoi) { // sk == 1 ??
+ || execmaskden || aut == 1 || aut == 2) && lp.denoiena && lp.quamet != 3) || execdenoi) { // sk == 1 ??
StopWatch Stop1("locallab Denoise called");
@@ -9221,7 +9269,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl
if ((lp.quamet == 0 && aut == 0) || (mxsl < 1.f && (aut == 1 || aut == 2))) {
WaveletDenoiseAllL(Ldecomp, noisevarlum, madL, vari, edge, numThreads);
- } else {
+ } else if (lp.quamet == 1){
WaveletDenoiseAll_BiShrinkL(Ldecomp, noisevarlum, madL, vari, edge, numThreads);
@@ -9512,7 +9560,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl
if ((lp.quamet == 0 && aut == 0) || (maxccoarse < 0.1f && (aut == 1 || aut == 2))) {
WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads);
WaveletDenoiseAllAB(Ldecomp, bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, numThreads);
- } else {
+ } else if (lp.quamet == 1){
WaveletDenoiseAll_BiShrinkAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads);
WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads);
@@ -9540,7 +9588,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl
}
if (!Ldecomp.memory_allocation_failed() && aut == 0) {
- if ((lp.noiself >= 0.01f || lp.noiself0 >= 0.01f || lp.noiself2 >= 0.01f || lp.wavcurvedenoi || lp.noiselc >= 0.01f) && levred == 7 && lp.noiseldetail != 100.f && lp.quamet != 2) {
+ if ((lp.noiself >= 0.01f || lp.noiself0 >= 0.01f || lp.noiself2 >= 0.01f || lp.wavcurvedenoi || lp.noiselc >= 0.01f) && levred == 7 && lp.noiseldetail != 100.f && lp.quamet < 2) {
fftw_denoise(sk, GW, GH, max_numblox_W, min_numblox_W, tmp1.L, Lin, numThreads, lp, 0);
}
}
@@ -9590,6 +9638,9 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl
}
+ if(lp.nlstr > 0 && (hspot > 150 && wspot > 150)) {
+ NLMeans(tmp1.L, lp.nlstr, lp.nldet, lp.nlpat, lp.nlrad, lp.nlgam, GW, GH, float (sk), multiThread);
+ }
if(lp.smasktyp != 0) {
if(lp.enablMask && lp.recothrd != 1.f && lp.smasktyp != 0) {
LabImage tmp3(GW, GH);
@@ -9915,7 +9966,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl
if ((lp.quamet == 0 && aut == 0) || (mxsl < 1.f && (aut == 1 || aut == 2))) {
WaveletDenoiseAllL(Ldecomp, noisevarlum, madL, vari, edge, numThreads);
- } else {
+ } else if (lp.quamet == 1) {
WaveletDenoiseAll_BiShrinkL(Ldecomp, noisevarlum, madL, vari, edge, numThreads);
WaveletDenoiseAllL(Ldecomp, noisevarlum, madL, vari, edge, numThreads);
}
@@ -10203,7 +10254,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl
if ((lp.quamet == 0 && aut == 0) || (maxccoarse < 0.1f && (aut == 1 || aut == 2))) {
WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads);
WaveletDenoiseAllAB(Ldecomp, bdecomp, noisevarchrom, madL, variCb, edge, noisevarab_r, true, false, false, numThreads);
- } else {
+ } else if (lp.quamet == 1){
WaveletDenoiseAll_BiShrinkAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads);
WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, true, false, false, numThreads);
@@ -10234,7 +10285,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl
if (!Ldecomp.memory_allocation_failed() && aut == 0) {
- if ((lp.noiself >= 0.01f || lp.noiself0 >= 0.01f || lp.noiself2 >= 0.01f || lp.wavcurvedenoi || lp.noiselc >= 0.01f) && levred == 7 && lp.noiseldetail != 100.f && lp.quamet != 2) {
+ if ((lp.noiself >= 0.01f || lp.noiself0 >= 0.01f || lp.noiself2 >= 0.01f || lp.wavcurvedenoi || lp.noiselc >= 0.01f) && levred == 7 && lp.noiseldetail != 100.f && lp.quamet < 2) {
fftw_denoise(sk, bfw, bfh, max_numblox_W, min_numblox_W, bufwv.L, Lin, numThreads, lp, 0);
}
}
@@ -10281,6 +10332,12 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl
}
}
+
+ if(lp.nlstr > 0) {
+ NLMeans(bufwv.L, lp.nlstr, lp.nldet, lp.nlpat, lp.nlrad, lp.nlgam, bfw, bfh, 1.f, multiThread);
+ }
+
+
if (lp.smasktyp != 0) {
if(lp.enablMask && lp.recothrd != 1.f && lp.smasktyp != 0) {
LabImage tmp3(bfw, bfh);
@@ -10776,7 +10833,368 @@ void maskrecov(const LabImage * bufcolfin, LabImage * original, LabImage * bufma
masklum.free();
}
+//thanks to Alberto Griggio
+void ImProcFunctions::detail_mask(const array2D &src, array2D &mask, int bfw, int bfh, float scaling, float threshold, float ceiling, float factor, BlurType blur_type, float blur, bool multithread)
+{
+ const int W = bfw;
+ const int H = bfh;
+ mask(W, H);
+ array2D L2(W/4, H/4);//ARRAY2D_ALIGNED);
+ array2D m2(W/4, H/4);//ARRAY2D_ALIGNED)
+ rescaleBilinear(src, L2, multithread);
+#ifdef _OPENMP
+# pragma omp parallel for if (multithread)
+#endif
+ for (int y = 0; y < H/4; ++y) {
+ for (int x = 0; x < W/4; ++x) {
+ L2[y][x] = xlin2log(L2[y][x]/scaling, 50.f);
+ }
+ }
+
+ laplacian(L2, m2, W / 4, H / 4, threshold/scaling, ceiling/scaling, factor, multithread);
+
+ rescaleBilinear(m2, mask, multithread);
+
+ const auto scurve =
+ [](float x) -> float
+ {
+ constexpr float b = 101.f;
+ constexpr float a = 2.23f;
+ return xlin2log(pow_F(x, a), b);
+ };
+
+ const float thr = 1.f - factor;
+#ifdef _OPENMP
+# pragma omp parallel for if (multithread)
+#endif
+
+ for (int y = 0; y < H; ++y) {
+ for (int x = 0; x < W; ++x) {
+ mask[y][x] = scurve(LIM01(mask[y][x] + thr));
+ }
+ }
+
+ if (blur_type == BlurType::GAUSS) {
+
+#ifdef _OPENMP
+# pragma omp parallel if (multithread)
+#endif
+ {
+ gaussianBlur(mask, mask, W, H, blur);
+ }
+ } else if (blur_type == BlurType::BOX) {
+ if (int(blur) > 0) {
+ for (int i = 0; i < 3; ++i) {
+ boxblur(static_cast(mask), static_cast(mask), blur, W, H, multithread);
+ }
+ }
+ }
+
+}
+
+// basic idea taken from Algorithm 3 in the paper:
+// "Parameter-Free Fast Pixelwise Non-Local Means Denoising" http://www.ipol.im/pub/art/2014/120/
+// by Jacques Froment
+
+// thanks to Alberto Griggio for this wonderful code
+// thanks to Ingo Weyrich for many speedup suggestions!
+// adapted to Rawtherapee Local adjustments J.Desmis january 2021
+//
+
+void ImProcFunctions::NLMeans(float **img, int strength, int detail_thresh, int patch, int radius, float gam, int bfw, int bfh, float scale, bool multithread)
+{
+ if (!strength) {
+ return;
+ }
+ // printf("Scale=%f\n", scale);
+ if(scale > 5.f) {//avoid to small values - leads to crash - but enough to evaluate noise
+ return;
+ }
+ if(bfh < 150 || bfw < 150) {
+ return;
+ }
+
+ BENCHFUN
+ const int W = bfw;
+ const int H = bfh;
+ float gamma = gam;
+ rtengine::GammaValues g_a; //gamma parameters
+ double pwr = 1.0 / gam;//default 3.0 - gamma Lab
+ double ts = 9.03296;//always the same 'slope' in the extrem shadows - slope Lab
+ rtengine::Color::calcGamma(pwr, ts, g_a); // call to calcGamma with selected gamma and slope
+
+ //first change Lab L to pseudo linear with gamma = 3.f slope 9.032...and in range 0...65536, or with gamma slope Lab
+
+#ifdef _OPENMP
+# pragma omp parallel for schedule(dynamic,16) if (multithread)
+#endif
+ for (int y = 0; y < H; ++y) {
+ int x = 0;
+#ifdef __SSE2__
+ for (; x < W - 3; x += 4) {
+ STVFU(img[y][x], F2V(65536.f) * igammalog(LVFU(img[y][x]) / F2V(32768.f), F2V(gamma), F2V(ts), F2V(g_a[2]), F2V(g_a[4])));
+ }
+#endif
+ for (;x < W; ++x) {
+ img[y][x] = 65536.f * igammalog(img[y][x] / 32768.f, gamma, ts, g_a[2], g_a[4]);
+ }
+ }
+
+ // these two can be changed if needed. increasing max_patch_radius doesn't
+ // affect performance, whereas max_search_radius *really* does
+ // (the complexity is O(max_search_radius^2 * W * H))
+// constexpr int max_patch_radius = 2;
+// constexpr int max_search_radius = 5;
+ int max_patch_radius = patch;
+ int max_search_radius = radius;
+
+ const int search_radius = int(std::ceil(float(max_search_radius) / scale));
+ const int patch_radius = int(std::ceil(float(max_patch_radius) / scale));
+
+ // the strength parameter controls the scaling of the weights
+ // (called h^2 in the papers)
+ float eps = 1e-6f;//to avoid too low values and divide near by zero...when scale > 1
+ const float h2 = eps + SQR(std::pow(float(strength) / 100.f, 0.9f) / 30.f / scale);
+// printf("h2=%f\n", h2);
+ // this is the main difference between our version and more conventional
+ // nl-means implementations: instead of varying the patch size, we control
+ // the detail preservation by using a varying weight scaling for the
+ // pixels, depending on our estimate of how much details there are in the
+ // pixel neighborhood. We do this by computing a "detail mask", using a
+ // laplacian filter with additional averaging and smoothing. The
+ // detail_thresh parameter controls the degree of detail preservation: the
+ // (averaged, smoothed) laplacian is first normalized to [0,1], and then
+ // modified by compression and offseting depending on the detail_thresh
+ // parameter, i.e. mask[y][x] = mask[y][x] * (1 - f) + f,
+ // where f = detail_thresh / 100
+ float amount = LIM(float(detail_thresh)/100.f, 0.f, 0.99f);
+ array2D mask(W, H);// ARRAY2D_ALIGNED);
+
+ {
+ array2D LL(W, H, img, ARRAY2D_BYREFERENCE);
+ ImProcFunctions::detail_mask(LL, mask, W, H, 1.f, 1e-3f, 1.f, amount, BlurType::GAUSS, 2.f / scale, multithread);
+
+ }
+
+//allocate dst - same type of datas as img
+ float** dst;
+ int wid = W;
+ int hei = H;
+ dst = new float*[hei];
+ for (int i = 0; i < hei; ++i) {
+ dst[i] = new float[wid];
+ }
+ const int border = search_radius + patch_radius;
+ const int WW = W + border * 2;
+ const int HH = H + border * 2;
+
+ array2D src(WW, HH);//, ARRAY2D_ALIGNED);
+
+#ifdef _OPENMP
+# pragma omp parallel for if (multithread)
+#endif
+ for (int y = 0; y < HH; ++y) {
+ int yy = y <= border ? 0 : y >= H ? H-1 : y - border;
+ for (int x = 0; x < WW; ++x) {
+ int xx = x <= border ? 0 : x >= W ? W-1 : x - border;
+ float Y = img[yy][xx] / 65536.f;
+ src[y][x] = Y;
+ }
+ }
+
+#ifdef _OPENMP
+# pragma omp parallel for if (multithread)
+#endif
+ for (int y = 0; y < H; ++y) {
+ for (int x = 0; x < W; ++x) {
+ dst[y][x] = 0.f;
+ }
+ }
+
+ constexpr int lutsz = 8192;
+ constexpr float lutfactor = 100.f / float(lutsz-1);
+ LUTf explut(lutsz);
+ for (int i = 0; i < lutsz; ++i) {
+ float x = float(i) * lutfactor;
+ explut[i] = xexpf(-x);
+ }
+
+#ifdef _OPENMP
+# pragma omp parallel for if (multithread)
+#endif
+ for (int y = 0; y < H; ++y) {
+ for (int x = 0; x < W; ++x) {
+ mask[y][x] = (1.f / (mask[y][x] * h2)) / lutfactor;
+ }
+ }
+
+ // process by tiles to avoid numerical accuracy errors in the computation
+ // of the integral image
+ const int tile_size = 150;
+ const int ntiles_x = int(std::ceil(float(WW) / (tile_size-2*border)));
+ const int ntiles_y = int(std::ceil(float(HH) / (tile_size-2*border)));
+ const int ntiles = ntiles_x * ntiles_y;
+
+#ifdef __SSE2__
+ const vfloat zerov = F2V(0.0);
+ const vfloat v1e_5f = F2V(1e-5f);
+ const vfloat v65536f = F2V(65536.f);
+#endif
+
+#ifdef _OPENMP
+# pragma omp parallel if (multithread)
+#endif
+ {
+
+#ifdef __SSE2__
+ // flush denormals to zero to avoid performance penalty
+ const auto oldMode = _MM_GET_FLUSH_ZERO_MODE();
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+#endif
+
+#ifdef _OPENMP
+# pragma omp for schedule(dynamic, 2)
+#endif
+ for (int tile = 0; tile < ntiles; ++tile) {
+ const int tile_y = tile / ntiles_x;
+ const int tile_x = tile % ntiles_x;
+
+ const int start_y = tile_y * (tile_size - 2*border);
+ const int end_y = std::min(start_y + tile_size, HH);
+ const int TH = end_y - start_y;
+
+ const int start_x = tile_x * (tile_size - 2*border);
+ const int end_x = std::min(start_x + tile_size, WW);
+ const int TW = end_x - start_x;
+
+ const auto Y = [=](int y) -> int { return LIM(y+start_y, 0, HH-1); };
+ const auto X = [=](int x) -> int { return LIM(x+start_x, 0, WW-1); };
+
+ const auto score =
+ [&](int tx, int ty, int zx, int zy) -> float
+ {
+ return SQR(src[Y(zy)][X(zx)] - src[Y(zy + ty)][X(zx + tx)]);
+ };
+
+ array2D St(TW, TH);//, ARRAY2D_ALIGNED);
+ array2D SW(TW, TH, ARRAY2D_CLEAR_DATA);//, ARRAY2D_ALIGNED|ARRAY2D_CLEAR_DATA);
+
+ for (int ty = -search_radius; ty <= search_radius; ++ty) {
+ for (int tx = -search_radius; tx <= search_radius; ++tx) {
+ // Step 1 — Compute the integral image St
+ St[0][0] = 0.f;
+ for (int xx = 1; xx < TW; ++xx) {
+ St[0][xx] = St[0][xx-1] + score(tx, ty, xx, 0);
+ }
+ for (int yy = 1; yy < TH; ++yy) {
+ St[yy][0] = St[yy-1][0] + score(tx, ty, 0, yy);
+ }
+ for (int yy = 1; yy < TH; ++yy) {
+ for (int xx = 1; xx < TW; ++xx) {
+ // operation grouping tuned for performance (empirically)
+ St[yy][xx] = (St[yy][xx-1] + St[yy-1][xx]) - (St[yy-1][xx-1] - score(tx, ty, xx, yy));
+ }
+ }
+ // Step 2 — Compute weight and estimate for patches
+ // V(x), V(y) with y = x + t
+ for (int yy = start_y+border; yy < end_y-border; ++yy) {
+ int y = yy - border;
+ int xx = start_x+border;
+#ifdef __SSE2__
+ for (; xx < end_x-border-3; xx += 4) {
+ int x = xx - border;
+ int sx = xx + tx;
+ int sy = yy + ty;
+
+ int sty = yy - start_y;
+ int stx = xx - start_x;
+
+ vfloat dist2 = LVFU(St[sty + patch_radius][stx + patch_radius]) + LVFU(St[sty - patch_radius][stx - patch_radius]) - LVFU(St[sty + patch_radius][stx - patch_radius]) - LVFU(St[sty - patch_radius][stx + patch_radius]);
+ dist2 = vmaxf(dist2, zerov);
+ vfloat d = dist2 * LVFU(mask[y][x]);
+ vfloat weight = explut[d];
+ STVFU(SW[y-start_y][x-start_x], LVFU(SW[y-start_y][x-start_x]) + weight);
+ vfloat Y = weight * LVFU(src[sy][sx]);
+ STVFU(dst[y][x], LVFU(dst[y][x]) + Y);
+ }
+#endif
+ for (; xx < end_x-border; ++xx) {
+ int x = xx - border;
+ int sx = xx + tx;
+ int sy = yy + ty;
+
+ int sty = yy - start_y;
+ int stx = xx - start_x;
+
+ float dist2 = St[sty + patch_radius][stx + patch_radius] + St[sty - patch_radius][stx - patch_radius] - St[sty + patch_radius][stx - patch_radius] - St[sty - patch_radius][stx + patch_radius];
+ dist2 = std::max(dist2, 0.f);
+ float d = dist2 * mask[y][x];
+ float weight = explut[d];
+ SW[y-start_y][x-start_x] += weight;
+ float Y = weight * src[sy][sx];
+ dst[y][x] += Y;
+
+ assert(!xisinff(dst[y][x]));
+ assert(!xisnanf(dst[y][x]));
+ }
+ }
+ }
+ }
+// printf("E\n");
+
+ // Compute final estimate at pixel x = (x1, x2)
+ for (int yy = start_y+border; yy < end_y-border; ++yy) {
+ int y = yy - border;
+ int xx = start_x+border;
+#ifdef __SSE2__
+ for (; xx < end_x-border-3; xx += 4) {
+ int x = xx - border;
+
+ const vfloat Y = LVFU(dst[y][x]);
+ const vfloat f = (v1e_5f + LVFU(SW[y-start_y][x-start_x]));
+ STVFU(dst[y][x], (Y / f) * v65536f);
+ }
+#endif
+ for (; xx < end_x-border; ++xx) {
+ int x = xx - border;
+
+ const float Y = dst[y][x];
+ const float f = (1e-5f + SW[y-start_y][x-start_x]);
+ dst[y][x] = (Y / f) * 65536.f;
+
+ assert(!xisnanf(dst[y][x]));
+ }
+ }
+ }
+
+#ifdef __SSE2__
+ _MM_SET_FLUSH_ZERO_MODE(oldMode);
+#endif
+
+ } // omp parallel
+
+#ifdef _OPENMP
+# pragma omp parallel for schedule(dynamic,16) if (multithread)
+#endif
+ for (int y = 0; y < H; ++y) {//apply inverse gamma 3.f and put result in range 32768.f
+ int x = 0;
+#ifdef __SSE2__
+ for (; x < W - 3; x += 4) {
+ STVFU(img[y][x], F2V(32768.f) * gammalog(LVFU(dst[y][x]) / F2V(65536.f), F2V(gamma), F2V(ts), F2V(g_a[3]), F2V(g_a[4])));
+ }
+#endif
+ for (; x < W; ++x) {
+ img[y][x] = 32768.f * gammalog(dst[y][x] / 65536.f, gamma, ts, g_a[3], g_a[4]);
+ }
+ }
+
+ for (int i = 0; i < hei; ++i) {
+ delete[] dst[i];
+ }
+ delete[] dst;
+
+}
void ImProcFunctions::Lab_Local(
int call, int sp, float** shbuffer, LabImage * original, LabImage * transformed, LabImage * reserved, LabImage * lastorig, int cx, int cy, int oW, int oH, int sk,
diff --git a/rtengine/procevents.h b/rtengine/procevents.h
index 00f2d1916..62dff74e3 100644
--- a/rtengine/procevents.h
+++ b/rtengine/procevents.h
@@ -1056,6 +1056,11 @@ enum ProcEventCode {
Evlocallablowthresr = 1030,
Evlocallabhigthresr = 1031,
Evlocallabdecayr = 1032,
+ Evlocallabnlstr = 1033,
+ Evlocallabnldet = 1034,
+ Evlocallabnlpat = 1035,
+ Evlocallabnlrad = 1036,
+ Evlocallabnlgam = 1037,
NUMOFEVENTS
};
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index 09c174462..0bbcaa907 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -3352,6 +3352,11 @@ LocallabParams::LocallabSpot::LocallabSpot() :
noisechrodetail(50.),
adjblur(0),
bilateral(0),
+ nlstr(0),
+ nldet(50),
+ nlpat(2),
+ nlrad(5),
+ nlgam(3.),
sensiden(60),
detailthr(50),
locwavcurveden{
@@ -4443,6 +4448,11 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const
&& noisechrodetail == other.noisechrodetail
&& adjblur == other.adjblur
&& bilateral == other.bilateral
+ && nlstr == other.nlstr
+ && nldet == other.nldet
+ && nlpat == other.nlpat
+ && nlrad == other.nlrad
+ && nlgam == other.nlgam
&& sensiden == other.sensiden
&& detailthr == other.detailthr
&& locwavcurveden == other.locwavcurveden
@@ -6077,6 +6087,11 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
saveToKeyfile(!pedited || spot_edited->noisechrodetail, "Locallab", "noisechrodetail_" + index_str, spot.noisechrodetail, keyFile);
saveToKeyfile(!pedited || spot_edited->adjblur, "Locallab", "Adjblur_" + index_str, spot.adjblur, keyFile);
saveToKeyfile(!pedited || spot_edited->bilateral, "Locallab", "Bilateral_" + index_str, spot.bilateral, keyFile);
+ saveToKeyfile(!pedited || spot_edited->nlstr, "Locallab", "Nlstr_" + index_str, spot.nlstr, keyFile);
+ saveToKeyfile(!pedited || spot_edited->nldet, "Locallab", "Nldet_" + index_str, spot.nldet, keyFile);
+ saveToKeyfile(!pedited || spot_edited->nlpat, "Locallab", "Nlpat_" + index_str, spot.nlpat, keyFile);
+ saveToKeyfile(!pedited || spot_edited->nlrad, "Locallab", "Nlrad_" + index_str, spot.nlrad, keyFile);
+ saveToKeyfile(!pedited || spot_edited->nlgam, "Locallab", "Nlgam_" + index_str, spot.nlgam, keyFile);
saveToKeyfile(!pedited || spot_edited->sensiden, "Locallab", "Sensiden_" + index_str, spot.sensiden, keyFile);
saveToKeyfile(!pedited || spot_edited->detailthr, "Locallab", "Detailthr_" + index_str, spot.detailthr, keyFile);
saveToKeyfile(!pedited || spot_edited->locwavcurveden, "Locallab", "LocwavCurveden_" + index_str, spot.locwavcurveden, keyFile);
@@ -7927,6 +7942,11 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
assignFromKeyfile(keyFile, "Locallab", "noisechrodetail_" + index_str, pedited, spot.noisechrodetail, spotEdited.noisechrodetail);
assignFromKeyfile(keyFile, "Locallab", "Adjblur_" + index_str, pedited, spot.adjblur, spotEdited.adjblur);
assignFromKeyfile(keyFile, "Locallab", "Bilateral_" + index_str, pedited, spot.bilateral, spotEdited.bilateral);
+ assignFromKeyfile(keyFile, "Locallab", "Nlstr_" + index_str, pedited, spot.nlstr, spotEdited.nlstr);
+ assignFromKeyfile(keyFile, "Locallab", "Nldet_" + index_str, pedited, spot.nldet, spotEdited.nldet);
+ assignFromKeyfile(keyFile, "Locallab", "Nlpat_" + index_str, pedited, spot.nlpat, spotEdited.nlpat);
+ assignFromKeyfile(keyFile, "Locallab", "Nlrad_" + index_str, pedited, spot.nlrad, spotEdited.nlrad);
+ assignFromKeyfile(keyFile, "Locallab", "Nlgam_" + index_str, pedited, spot.nlgam, spotEdited.nlgam);
assignFromKeyfile(keyFile, "Locallab", "Sensiden_" + index_str, pedited, spot.sensiden, spotEdited.sensiden);
assignFromKeyfile(keyFile, "Locallab", "Detailthr_" + index_str, pedited, spot.detailthr, spotEdited.detailthr);
assignFromKeyfile(keyFile, "Locallab", "LocwavCurveden_" + index_str, pedited, spot.locwavcurveden, spotEdited.locwavcurveden);
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index 15fb79702..45ce8005d 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -1258,6 +1258,11 @@ struct LocallabParams {
double noisechrodetail;
int adjblur;
int bilateral;
+ int nlstr;
+ int nldet;
+ int nlpat;
+ int nlrad;
+ double nlgam;
int sensiden;
int detailthr;
std::vector locwavcurveden;
diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc
index 742aa3707..ad16b881d 100644
--- a/rtengine/refreshmap.cc
+++ b/rtengine/refreshmap.cc
@@ -1059,7 +1059,12 @@ int refreshmap[rtengine::NUMOFEVENTS] = {
LUMINANCECURVE, // Evlocallabrecothrer
LUMINANCECURVE, // Evlocallablowthresr
LUMINANCECURVE, // Evlocallabhigthresr
- LUMINANCECURVE // Evlocallabdecayr
+ LUMINANCECURVE, // Evlocallabdecayr
+ LUMINANCECURVE, // Evlocallabnlstr
+ LUMINANCECURVE, // Evlocallabnldet
+ LUMINANCECURVE, // Evlocallabnlpat
+ LUMINANCECURVE, // Evlocallabnlrad
+ LUMINANCECURVE // Evlocallabnlgam
};
diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc
index 41b75f17f..ce582b592 100644
--- a/rtgui/locallabtools.cc
+++ b/rtgui/locallabtools.cc
@@ -6258,6 +6258,12 @@ LocallabBlur::LocallabBlur():
decayd(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKDDECAY"), 0.5, 4., 0.1, 2.))),
invmaskd(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVMASK")))),
invmask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVMASK")))),
+ nlFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_NLFRA")))),
+ nlstr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NLLUM"), 0, 100, 1, 0))),
+ nldet(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NLDET"), 0, 100, 1, 50))),
+ nlpat(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NLPAT"), 1, 5, 1, 2))),
+ nlrad(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NLRAD"), 3, 10, 1, 5))),
+ nlgam(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NLGAM"), 2., 5., 0.1, 3.))),
bilateral(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BILATERAL"), 0, 100, 1, 0))),
sensiden(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 60))),
neutral(Gtk::manage (new Gtk::Button (M ("TP_RETINEX_NEUTRAL")))),
@@ -6363,9 +6369,10 @@ LocallabBlur::LocallabBlur():
setExpandAlignProperties(expdenoise, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START);
- quamethod->append(M("TP_WAVELET_QUACONSER"));
- quamethod->append(M("TP_WAVELET_QUAAGRES"));
- quamethod->append(M("TP_WAVELET_QUANONE"));
+ quamethod->append(M("TP_LOCALLAB_QUANONEALL"));
+ quamethod->append(M("TP_LOCALLAB_QUACONSER"));
+ quamethod->append(M("TP_LOCALLAB_QUAAGRES"));
+ quamethod->append(M("TP_LOCALLAB_QUANONEWAV"));
quamethodconn = quamethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabBlur::quamethodChanged));
Gtk::Label* const quaLabel = Gtk::manage(new Gtk::Label(M("TP_WAVELET_DENQUA") + ":"));
quaHBox->pack_start(*quaLabel, Gtk::PACK_SHRINK, 4);
@@ -6429,6 +6436,13 @@ LocallabBlur::LocallabBlur():
decayd->setAdjusterListener(this);
bilateral->setAdjusterListener(this);
+ nlFrame->set_label_align(0.025, 0.5);
+
+ nlstr->setAdjusterListener(this);
+ nldet->setAdjusterListener(this);
+ nlpat->setAdjusterListener(this);
+ nlrad->setAdjusterListener(this);
+ nlgam->setAdjusterListener(this);
sensiden->setAdjusterListener(this);
@@ -6566,17 +6580,28 @@ LocallabBlur::LocallabBlur():
wavBox1->pack_start(*levelthr, Gtk::PACK_SHRINK, 0);
expdenoise1->add(*wavBox1, false);
wavBox->pack_start(*expdenoise1);
- wavBox->pack_start(*noisechrof);
- wavBox->pack_start(*noisechroc);
- wavBox->pack_start(*noisechrodetail);
- wavBox->pack_start(*adjblur);
ToolParamBlock* const detailBox = Gtk::manage(new ToolParamBlock());
detailBox->pack_start(*detailthr);
detailBox->pack_start(*usemask, Gtk::PACK_SHRINK, 0);
detailFrame->add(*detailBox);
wavBox->pack_start(*detailFrame);
+
+ ToolParamBlock* const nlbox = Gtk::manage(new ToolParamBlock());
+ nlbox->pack_start(*nlstr);
+ nlbox->pack_start(*nldet);
+ nlbox->pack_start(*nlgam);
+ nlbox->pack_start(*nlpat);
+ nlbox->pack_start(*nlrad);
+ nlFrame->add(*nlbox);
+ wavBox->pack_start(*nlFrame);
+
+ wavBox->pack_start(*noisechrof);
+ wavBox->pack_start(*noisechroc);
+ wavBox->pack_start(*noisechrodetail);
+ wavBox->pack_start(*adjblur);
wavFrame->add(*wavBox);
denoisebox->pack_start(*wavFrame);
+
ToolParamBlock* const wavBox3 = Gtk::manage(new ToolParamBlock());
wavBox3->pack_start(*maskusable3, Gtk::PACK_SHRINK, 0);
wavBox3->pack_start(*maskunusable3, Gtk::PACK_SHRINK, 0);
@@ -6683,6 +6708,12 @@ void LocallabBlur::updateAdviceTooltips(const bool showTooltips)
detailthr->set_tooltip_text(M("TP_LOCALLAB_DENOITHR_TOOLTIP"));
adjblur->set_tooltip_text(M("TP_LOCALLAB_DENOIEQUALCHRO_TOOLTIP"));
bilateral->set_tooltip_text(M("TP_LOCALLAB_DENOIBILAT_TOOLTIP"));
+ nlFrame->set_tooltip_text(M("TP_LOCALLAB_NLFRAME_TOOLTIP"));
+ nlstr->set_tooltip_text(M("TP_LOCALLAB_NLDENOISE_TOOLTIP"));
+ nldet->set_tooltip_text(M("TP_LOCALLAB_NLDENOISE_TOOLTIP"));
+ nlpat->set_tooltip_text(M("TP_LOCALLAB_NLDENOISENLPAT_TOOLTIP"));
+ nlrad->set_tooltip_text(M("TP_LOCALLAB_NLDENOISENLRAD_TOOLTIP"));
+ nlgam->set_tooltip_text(M("TP_LOCALLAB_NLDENOISENLGAM_TOOLTIP"));
noiselumc->set_tooltip_text(M("TP_LOCALLAB_NOISECHROC_TOOLTIP"));
expmaskbl->set_tooltip_markup(M("TP_LOCALLAB_MASK_TOOLTIP"));
showmaskblMethodtyp->set_tooltip_markup(M("TP_LOCALLAB_SHOWMASKTYP_TOOLTIP"));
@@ -6742,6 +6773,12 @@ void LocallabBlur::updateAdviceTooltips(const bool showTooltips)
detailthr->set_tooltip_text("");
adjblur->set_tooltip_text("");
bilateral->set_tooltip_text("");
+ nlFrame->set_tooltip_text("");
+ nlstr->set_tooltip_text("");
+ nldet->set_tooltip_text("");
+ nlpat->set_tooltip_text("");
+ nlrad->set_tooltip_text("");
+ nlgam->set_tooltip_text("");
sensibn->set_tooltip_text("");
blurMethod->set_tooltip_markup("");
expdenoise->set_tooltip_markup("");
@@ -6793,8 +6830,13 @@ void LocallabBlur::neutral_pressed ()
detailthr->setValue(defSpot.detailthr);;
adjblur->setValue(defSpot.adjblur);
bilateral->setValue(defSpot.bilateral);
+ nlstr->setValue(defSpot.nlstr);
+ nldet->setValue(defSpot.nldet);
+ nlpat->setValue(defSpot.nlpat);
+ nlrad->setValue(defSpot.nlrad);
+ nlgam->setValue(defSpot.nlgam);
sensiden->setValue(defSpot.sensiden);
- quamethod->set_active (2);
+ quamethod->set_active (0);
wavshapeden->setCurve(defSpot.locwavcurveden);
wavhue->setCurve(defSpot.locwavcurvehue);
usemask->set_active(defSpot.usemask);
@@ -6942,12 +6984,14 @@ void LocallabBlur::read(const rtengine::procparams::ProcParams* pp, const Params
chroMethod->set_active(2);
}
- if (spot.quamethod == "cons") {
+ if (spot.quamethod == "none") {
quamethod->set_active(0);
- } else if (spot.quamethod == "agre") {
+ } else if (spot.quamethod == "cons") {
quamethod->set_active(1);
- } else if (spot.quamethod == "none") {
+ } else if (spot.quamethod == "agre") {
quamethod->set_active(2);
+ } else if (spot.quamethod == "nlmean") {
+ quamethod->set_active(3);
}
activlum->set_active(spot.activlum);
@@ -6968,6 +7012,11 @@ void LocallabBlur::read(const rtengine::procparams::ProcParams* pp, const Params
detailthr->setValue((double)spot.detailthr);
adjblur->setValue((double)spot.adjblur);
bilateral->setValue((double)spot.bilateral);
+ nlstr->setValue((double)spot.nlstr);
+ nldet->setValue((double)spot.nldet);
+ nlpat->setValue((double)spot.nlpat);
+ nlrad->setValue((double)spot.nlrad);
+ nlgam->setValue((double)spot.nlgam);
sensiden->setValue((double)spot.sensiden);
if (spot.showmaskblMethodtyp == "blur") {
@@ -7081,11 +7130,13 @@ void LocallabBlur::write(rtengine::procparams::ProcParams* pp, ParamsEdited* ped
}
if (quamethod->get_active_row_number() == 0) {
- spot.quamethod = "cons";
- } else if (quamethod->get_active_row_number() == 1) {
- spot.quamethod = "agre";
- } else if (quamethod->get_active_row_number() == 2) {
spot.quamethod = "none";
+ } else if (quamethod->get_active_row_number() == 1) {
+ spot.quamethod = "cons";
+ } else if (quamethod->get_active_row_number() == 2) {
+ spot.quamethod = "agre";
+ } else if (quamethod->get_active_row_number() == 3) {
+ spot.quamethod = "nlmean";
}
spot.activlum = activlum->get_active();
@@ -7107,6 +7158,11 @@ void LocallabBlur::write(rtengine::procparams::ProcParams* pp, ParamsEdited* ped
spot.adjblur = adjblur->getIntValue();
spot.bilateral = bilateral->getIntValue();
spot.sensiden = sensiden->getIntValue();
+ spot.nlstr = nlstr->getIntValue();
+ spot.nldet = nldet->getIntValue();
+ spot.nlpat = nlpat->getIntValue();
+ spot.nlrad = nlrad->getIntValue();
+ spot.nlgam = nlgam->getValue();
if (showmaskblMethodtyp->get_active_row_number() == 0) {
spot.showmaskblMethodtyp = "blur";
@@ -7181,6 +7237,11 @@ void LocallabBlur::setDefaults(const rtengine::procparams::ProcParams* defParams
detailthr->setDefault((double)defSpot.detailthr);
adjblur->setDefault((double)defSpot.adjblur);
bilateral->setDefault((double)defSpot.bilateral);
+ nlstr->setDefault((double)defSpot.nlstr);
+ nldet->setDefault((double)defSpot.nldet);
+ nlpat->setDefault((double)defSpot.nlpat);
+ nlrad->setDefault((double)defSpot.nlrad);
+ nlgam->setDefault(defSpot.nlgam);
sensiden->setDefault((double)defSpot.sensiden);
strumaskbl->setDefault(defSpot.strumaskbl);
blendmaskbl->setDefault((double)defSpot.blendmaskbl);
@@ -7455,6 +7516,41 @@ void LocallabBlur::adjusterChanged(Adjuster* a, double newval)
}
}
+ if (a == nlstr) {
+ if (listener) {
+ listener->panelChanged(Evlocallabnlstr,
+ nlstr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")");
+ }
+ }
+
+ if (a == nldet) {
+ if (listener) {
+ listener->panelChanged(Evlocallabnldet,
+ nldet->getTextValue() + " (" + escapeHtmlChars(spotName) + ")");
+ }
+ }
+
+ if (a == nlpat) {
+ if (listener) {
+ listener->panelChanged(Evlocallabnlpat,
+ nlpat->getTextValue() + " (" + escapeHtmlChars(spotName) + ")");
+ }
+ }
+
+ if (a == nlrad) {
+ if (listener) {
+ listener->panelChanged(Evlocallabnlrad,
+ nlrad->getTextValue() + " (" + escapeHtmlChars(spotName) + ")");
+ }
+ }
+
+ if (a == nlgam) {
+ if (listener) {
+ listener->panelChanged(Evlocallabnlgam,
+ nlgam->getTextValue() + " (" + escapeHtmlChars(spotName) + ")");
+ }
+ }
+
if (a == sensiden) {
if (listener) {
listener->panelChanged(Evlocallabsensiden,
@@ -7628,7 +7724,8 @@ void LocallabBlur::convertParamToNormal()
LLmaskblshapewav->setCurve(defSpot.LLmaskblcurvewav);
csThresholdblur->setValue(defSpot.csthresholdblur);
lnoiselow->setValue(defSpot.lnoiselow);
-
+ nlrad->setValue(defSpot.nlrad);
+
// Enable all listeners
enableListener();
}
@@ -7680,6 +7777,10 @@ void LocallabBlur::convertParamToSimple()
higthres->setValue(defSpot.higthres);
adjblur->setValue(defSpot.adjblur);
noisechrodetail->setValue(defSpot.noisechrodetail);
+ nlpat->setValue(defSpot.nlpat);
+ nlrad->setValue(defSpot.nlrad);
+ nlgam->setValue(defSpot.nlgam);
+
// Enable all listeners
enableListener();
}
@@ -7706,6 +7807,9 @@ void LocallabBlur::updateGUIToMode(const modeType new_type)
adjblur->hide();
noisechrodetail->hide();
usemask->hide();
+ nlpat->hide();
+ nlrad->hide();
+ nlgam->hide();
break;
case Normal:
@@ -7726,6 +7830,10 @@ void LocallabBlur::updateGUIToMode(const modeType new_type)
adjblur->show();
noisechrodetail->show();
usemask->show();
+ nlpat->show();
+ nlrad->hide();
+ nlgam->show();
+
if (blMethod->get_active_row_number() == 2) {
expdenoise2->show();
}
@@ -7799,6 +7907,10 @@ void LocallabBlur::updateGUIToMode(const modeType new_type)
shadmaskblsha->show();
mask2blCurveEditorGwav->show();
csThresholdblur->show();
+ nlpat->show();
+ nlrad->show();
+ nlgam->show();
+
if(lnoiselow->getValue()!= 1.) {
if (showmaskblMethodtyp->get_active_row_number() == 0) {
showmaskblMethodtyp->set_active(2);
diff --git a/rtgui/locallabtools.h b/rtgui/locallabtools.h
index d8fb1ab29..6319cf1af 100644
--- a/rtgui/locallabtools.h
+++ b/rtgui/locallabtools.h
@@ -732,7 +732,12 @@ private:
Gtk::CheckButton* const invmaskd;
Gtk::CheckButton* const invmask;
-
+ Gtk::Frame* const nlFrame;
+ Adjuster* const nlstr;
+ Adjuster* const nldet;
+ Adjuster* const nlpat;
+ Adjuster* const nlrad;
+ Adjuster* const nlgam;
Adjuster* const bilateral;
Adjuster* const sensiden;
Gtk::Button* neutral;
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index f1da3fca6..d202577cf 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -1330,6 +1330,11 @@ void ParamsEdited::initFrom(const std::vector&
locallab.spots.at(j).noisechrodetail = locallab.spots.at(j).noisechrodetail && pSpot.noisechrodetail == otherSpot.noisechrodetail;
locallab.spots.at(j).adjblur = locallab.spots.at(j).adjblur && pSpot.adjblur == otherSpot.adjblur;
locallab.spots.at(j).bilateral = locallab.spots.at(j).bilateral && pSpot.bilateral == otherSpot.bilateral;
+ locallab.spots.at(j).nlstr = locallab.spots.at(j).nlstr && pSpot.nlstr == otherSpot.nlstr;
+ locallab.spots.at(j).nldet = locallab.spots.at(j).nldet && pSpot.nldet == otherSpot.nldet;
+ locallab.spots.at(j).nlpat = locallab.spots.at(j).nlpat && pSpot.nlpat == otherSpot.nlpat;
+ locallab.spots.at(j).nlrad = locallab.spots.at(j).nlrad && pSpot.nlrad == otherSpot.nlrad;
+ locallab.spots.at(j).nlgam = locallab.spots.at(j).nlgam && pSpot.nlgam == otherSpot.nlgam;
locallab.spots.at(j).sensiden = locallab.spots.at(j).sensiden && pSpot.sensiden == otherSpot.sensiden;
locallab.spots.at(j).detailthr = locallab.spots.at(j).detailthr && pSpot.detailthr == otherSpot.detailthr;
locallab.spots.at(j).locwavcurveden = locallab.spots.at(j).locwavcurveden && pSpot.locwavcurveden == otherSpot.locwavcurveden;
@@ -4285,6 +4290,26 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
toEdit.locallab.spots.at(i).bilateral = mods.locallab.spots.at(i).bilateral;
}
+ if (locallab.spots.at(i).nlstr) {
+ toEdit.locallab.spots.at(i).nlstr = mods.locallab.spots.at(i).nlstr;
+ }
+
+ if (locallab.spots.at(i).nldet) {
+ toEdit.locallab.spots.at(i).nldet = mods.locallab.spots.at(i).nldet;
+ }
+
+ if (locallab.spots.at(i).nlpat) {
+ toEdit.locallab.spots.at(i).nlpat = mods.locallab.spots.at(i).nlpat;
+ }
+
+ if (locallab.spots.at(i).nlrad) {
+ toEdit.locallab.spots.at(i).nlrad = mods.locallab.spots.at(i).nlrad;
+ }
+
+ if (locallab.spots.at(i).nlgam) {
+ toEdit.locallab.spots.at(i).nlgam = mods.locallab.spots.at(i).nlgam;
+ }
+
if (locallab.spots.at(i).sensiden) {
toEdit.locallab.spots.at(i).sensiden = mods.locallab.spots.at(i).sensiden;
}
@@ -6873,6 +6898,11 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) :
noisechrodetail(v),
adjblur(v),
bilateral(v),
+ nlstr(v),
+ nldet(v),
+ nlpat(v),
+ nlrad(v),
+ nlgam(v),
sensiden(v),
detailthr(v),
locwavcurveden(v),
@@ -7439,6 +7469,11 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v)
noisechrodetail = v;
adjblur = v;
bilateral = v;
+ nlstr = v;
+ nldet = v;
+ nlpat = v;
+ nlrad = v;
+ nlgam = v;
sensiden = v;
detailthr = v;
locwavcurveden = v;
diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h
index f5e547fa5..3b524c23f 100644
--- a/rtgui/paramsedited.h
+++ b/rtgui/paramsedited.h
@@ -666,6 +666,11 @@ public:
bool noisechrodetail;
bool adjblur;
bool bilateral;
+ bool nlstr;
+ bool nldet;
+ bool nlpat;
+ bool nlrad;
+ bool nlgam;
bool sensiden;
bool detailthr;
bool locwavcurveden;