diff --git a/rtdata/languages/default b/rtdata/languages/default
index ecaff0909..6e201e2f6 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -839,6 +839,7 @@ HISTORY_MSG_589;Local - Spot method
HISTORY_MSG_590;Local - Spot Excluding scope
HISTORY_MSG_591;Local - Spot Excluding struc
HISTORY_MSG_592;Local - Warm Cool
+HISTORY_MSG_593;Local - Noise lum detail
HISTORY_NEWSNAPSHOT;Add
HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s
HISTORY_SNAPSHOT;Snapshot
@@ -1850,10 +1851,11 @@ TP_LOCALLAB_EXCLUTYPE_TOOLTIP;Normal spot use recursive data.\nExcluding spot re
TP_LOCALLAB_EXNORM;Normal spot
TP_LOCALLAB_EXECLU;Excluding spot
TP_LOCALLAB_EXPOSE;Exposure
-TP_LOCALLAB_NOISELUMFINE;Luminance fine
-TP_LOCALLAB_NOISELUMCOARSE;Luminance coarse
-TP_LOCALLAB_NOISECHROFINE;Chroma fine
-TP_LOCALLAB_NOISECHROCOARSE;Chroma coarse
+TP_LOCALLAB_NOISELUMFINE;Luminance fine (Wav)
+TP_LOCALLAB_NOISELUMCOARSE;Luminance coarse (Wav)
+TP_LOCALLAB_NOISELUMDETAIL;Luminance detail (DCT)
+TP_LOCALLAB_NOISECHROFINE;Chroma fine (Wav)
+TP_LOCALLAB_NOISECHROCOARSE;Chroma coarse (Wav)
TP_LOCALLAB_QUAL_METHOD;Global quality
TP_LOCALLAB_QUALCURV_METHOD;Curves type
TP_LOCALLAB_GAM;Gamma
diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc
index e746aeb50..988706c19 100644
--- a/rtengine/dcrop.cc
+++ b/rtengine/dcrop.cc
@@ -1147,6 +1147,7 @@ void Crop::update(int todo)
params.locallab.sensiexclu = parent->sensiexclus[sp];
params.locallab.struc = parent->strucs[sp];
params.locallab.warm = parent->warms[sp];
+ params.locallab.noiselumdetail = parent->noiselumdetails[sp];
std::vector cretie;
@@ -1526,6 +1527,7 @@ void Crop::update(int todo)
parent->sensiexclus[sp] = params.locallab.sensiexclu = parent->sensiexclus[0];
parent->strucs[sp] = params.locallab.struc = parent->strucs[0];
parent->warms[sp] = params.locallab.warm = parent->warms[0];
+ parent->noiselumdetails[sp] = params.locallab.noiselumdetail = parent->noiselumdetails[0];
std::vector ccret;
diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc
index 819f78935..6b666c35d 100644
--- a/rtengine/improccoordinator.cc
+++ b/rtengine/improccoordinator.cc
@@ -155,6 +155,7 @@ ImProcCoordinator::ImProcCoordinator()
proxis(500, -10000),
noiselumfs(500, -10000),
noiselumcs(500, -10000),
+ noiselumdetails(500, -10000),
noisechrofs(500, -10000),
noisechrocs(500, -10000),
mult0s(500, -10000),
@@ -413,34 +414,34 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
}
if (todo & (M_INIT | M_LINDENOISE | M_HDR)) {
- MyMutex::MyLock initLock (minit); // Also used in crop window
+ MyMutex::MyLock initLock(minit); // Also used in crop window
- imgsrc->HLRecovery_Global ( params.toneCurve); // this handles Color HLRecovery
+ imgsrc->HLRecovery_Global(params.toneCurve); // this handles Color HLRecovery
if (settings->verbose) {
- printf ("Applying white balance, color correction & sRBG conversion...\n");
+ printf("Applying white balance, color correction & sRBG conversion...\n");
}
- currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method);
+ currWB = ColorTemp(params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method);
if (!params.wb.enabled) {
currWB = ColorTemp();
} else if (params.wb.method == "Camera") {
- currWB = imgsrc->getWB ();
+ currWB = imgsrc->getWB();
} else if (params.wb.method == "Auto") {
if (lastAwbEqual != params.wb.equal || lastAwbTempBias != params.wb.tempBias) {
double rm, gm, bm;
- imgsrc->getAutoWBMultipliers (rm, gm, bm);
+ imgsrc->getAutoWBMultipliers(rm, gm, bm);
if (rm != -1.) {
- autoWB.update (rm, gm, bm, params.wb.equal, params.wb.tempBias);
+ autoWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias);
lastAwbEqual = params.wb.equal;
lastAwbTempBias = params.wb.tempBias;
} else {
lastAwbEqual = -1.;
lastAwbTempBias = 0.0;
- autoWB.useDefaults (params.wb.equal);
+ autoWB.useDefaults(params.wb.equal);
}
//double rr,gg,bb;
@@ -451,25 +452,25 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
}
if (params.wb.enabled) {
- params.wb.temperature = currWB.getTemp ();
- params.wb.green = currWB.getGreen ();
+ params.wb.temperature = currWB.getTemp();
+ params.wb.green = currWB.getGreen();
}
if (params.wb.method == "Auto" && awbListener && params.wb.enabled) {
- awbListener->WBChanged (params.wb.temperature, params.wb.green);
+ awbListener->WBChanged(params.wb.temperature, params.wb.green);
}
- int tr = getCoarseBitMask (params.coarse);
+ int tr = getCoarseBitMask(params.coarse);
- imgsrc->getFullSize (fw, fh, tr);
+ imgsrc->getFullSize(fw, fh, tr);
// Will (re)allocate the preview's buffers
- setScale (scale);
- PreviewProps pp (0, 0, fw, fh, scale);
+ setScale(scale);
+ PreviewProps pp(0, 0, fw, fh, scale);
// Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications
- ipf.setScale (scale);
+ ipf.setScale(scale);
- imgsrc->getImage (currWB, tr, orig_prev, pp, params.toneCurve, params.raw);
+ imgsrc->getImage(currWB, tr, orig_prev, pp, params.toneCurve, params.raw);
denoiseInfoStore.valid = false;
//ColorTemp::CAT02 (orig_prev, ¶ms) ;
// printf("orig_prevW=%d\n scale=%d",orig_prev->width, scale);
@@ -514,9 +515,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
}
}
*/
- imgsrc->convertColorSpace (orig_prev, params.icm, currWB);
+ imgsrc->convertColorSpace(orig_prev, params.icm, currWB);
- ipf.firstAnalysis (orig_prev, params, vhist16);
+ ipf.firstAnalysis(orig_prev, params, vhist16);
}
readyphase++;
@@ -857,7 +858,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
};
- int maxdata = 86;//85 10016;// 82 10015//78;//73 for 10011
+ int maxdata = 87;//86 10017 //85 10016;// 82 10015//78;//73 for 10011
if (fic0) {
//find current version mip
@@ -901,7 +902,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
//initilize newues when first utilisation of Locallab. Prepare creation of Mip files
for (int sp = 1; sp < maxspot; sp++) { // spots default
int t_sp = sp;
- int t_mipversion = 10017;//new value for each change
+ int t_mipversion = 10018;//new value for each change
int t_circrad = 18;
int t_locX = 250;
int t_locY = 250;
@@ -1022,6 +1023,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
//10017
int t_warm = 0;
+ //10018
+ int t_noiselumdetail = 0;
//all variables except locRETgainCurve 'coomon for all)
fic << "Mipversion=" << t_mipversion << '@' << endl;
@@ -1115,6 +1118,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
fic << "Sensiexclu=" << t_sensiexclu << '@' << endl;
fic << "Struc=" << t_struc << '@' << endl;
fic << "Warm=" << t_warm << '@' << endl;
+ fic << "Noiselumdetail=" << t_noiselumdetail << '@' << endl;
fic << "curveReti=" << t_curvret << '@' << endl;
fic << "curveLL=" << t_curvll << '@' << endl;
@@ -1367,6 +1371,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
dataspot[79][0] = sensiexclus[0] = params.locallab.sensiexclu;
dataspot[80][0] = strucs[0] = params.locallab.struc;
dataspot[81][0] = warms[0] = params.locallab.warm;
+ dataspot[82][0] = noiselumdetails[0] = params.locallab.noiselumdetail;
// for all curves work around - I do not know how to do with params curves...
//curve Reti local
@@ -1653,6 +1658,10 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
maxind = 80;
}
+ if (versionmip == 10017) {
+ maxind = 81;
+ }
+
while (getline(fich, line)) {
spotline = line;
std::size_t pos = spotline.find("=");
@@ -1874,6 +1883,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
}
}
+ if (versionmip <= 10017) {//
+ for (int sp = 1; sp < maxspot; sp++) { // spots default
+ dataspot[82][sp] = 0;
+ }
+ }
//here we change the number of spot
@@ -1883,7 +1897,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
for (int sp = ns + 1 ; sp < maxspot; sp++) { // spots default
int t_sp = sp;
- int t_mipversion = 10017;
+ int t_mipversion = 10018;
int t_circrad = 18;
int t_locX = 250;
int t_locY = 250;
@@ -1996,6 +2010,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
//10017
int t_warm = 0;
+ //10018
+ int t_noiselumdetail = 0;
fic << "Mipversion=" << t_mipversion << '@' << endl;
fic << "Spot=" << t_sp << '@' << endl;
@@ -2085,6 +2101,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
fic << "Sensiexclu=" << t_sensiexclu << '@' << endl;
fic << "Struc=" << t_struc << '@' << endl;
fic << "Warm=" << t_warm << '@' << endl;
+ fic << "Noiselumdetail=" << t_noiselumdetail << '@' << endl;
fic << "curveReti=" << t_curvret << '@' << endl;
fic << "curveLL=" << t_curvll << '@' << endl;
@@ -2434,6 +2451,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
params.locallab.sensiexclu = sensiexclus[sp] = dataspot[79][sp];
params.locallab.struc = strucs[sp] = dataspot[80][sp];
params.locallab.warm = warms[sp] = dataspot[81][sp];
+ params.locallab.noiselumdetail = noiselumdetails[sp] = dataspot[82][sp];
int *s_datc;
@@ -2975,6 +2993,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
dataspot[79][sp] = sensiexclus[sp] = params.locallab.sensiexclu = dataspot[79][0];
dataspot[80][sp] = strucs[sp] = params.locallab.struc = dataspot[80][0];
dataspot[81][sp] = warms[sp] = params.locallab.warm = dataspot[81][0];
+ dataspot[82][sp] = noiselumdetails[sp] = params.locallab.noiselumdetail = dataspot[82][0];
int *s_datc;
@@ -3006,7 +3025,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
sizellcs[sp] = sizl;
std::vector cllend;
- llstr[sp] = llstr[0];
+ llstr[sp] = llstr[0];
for (int j = 0; j < sizl; j++) {
llcurvs[sp * 500 + j] = s_datcl[j];
@@ -3216,7 +3235,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
for (int spe = 1; spe < maxspot; spe++) {
int t_sp = spe;
- int t_mipversion = 10017;
+ int t_mipversion = 10018;
int t_circrad = dataspot[2][spe];
int t_locX = dataspot[3][spe];
int t_locY = dataspot[4][spe];
@@ -3304,6 +3323,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
int t_sensiexclu = dataspot[79][spe];
int t_struc = dataspot[80][spe];
int t_warm = dataspot[81][spe];
+ int t_noiselumdetail = dataspot[82][spe];
int t_hueref = dataspot[maxdata - 4][spe];
int t_chromaref = dataspot[maxdata - 3][spe];
@@ -3410,6 +3430,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
fou << "Sensiexclu=" << t_sensiexclu << '@' << endl;
fou << "Struc=" << t_struc << '@' << endl;
fou << "Warm=" << t_warm << '@' << endl;
+ fou << "Noiselumdetail=" << t_noiselumdetail << '@' << endl;
fou << "hueref=" << t_hueref << '@' << endl;
fou << "chromaref=" << t_chromaref << '@' << endl;
diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h
index 28ab288ea..7667a3b70 100644
--- a/rtengine/improccoordinator.h
+++ b/rtengine/improccoordinator.h
@@ -306,6 +306,7 @@ protected:
LUTi proxis;
LUTi noiselumfs;
LUTi noiselumcs;
+ LUTi noiselumdetails;
LUTi noisechrofs;
LUTi noisechrocs;
LUTi mult0s;
diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc
index 2224af8e5..3760a0117 100644
--- a/rtengine/iplocallab.cc
+++ b/rtengine/iplocallab.cc
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include "rtengine.h"
#include "improcfun.h"
@@ -49,6 +50,14 @@
#define cliploc( val, minv, maxv ) (( val = (val < minv ? minv : val ) ) > maxv ? maxv : val )
+#define TSD 64 // Tile size
+#define offset 25 // shift between tiles
+#define fTS ((TS/2+1)) // second dimension of Fourier tiles
+#define blkrad 1 // radius of block averaging
+
+#define epsilon 0.001f/(TS*TS) //tolerance
+
+
#define CLIPC(a) ((a)>-42000?((a)<42000?(a):42000):-42000) // limit a and b to 130 probably enough ?
#define CLIPL(x) LIM(x,0.f,40000.f) // limit L to about L=120 probably enough ?
#define CLIPLOC(x) LIM(x,0.f,32767.f)
@@ -134,6 +143,7 @@ struct local_params {
int qualcurvemet;
int blurmet;
float noiself;
+ float noiseldetail;
float noiselc;
float noisecf;
float noisecc;
@@ -368,6 +378,7 @@ static void calcLocalParams(int oW, int oH, const LocallabParams& locallab, stru
float local_noiself = locallab.noiselumf;
float local_noiselc = locallab.noiselumc;
+ float local_noiseldetail = locallab.noiselumdetail;
float local_noisecf = locallab.noisechrof;
float local_noisecc = locallab.noisechroc;
float multi[5];
@@ -450,7 +461,7 @@ static void calcLocalParams(int oW, int oH, const LocallabParams& locallab, stru
lp.dyy = h * local_dyy;
lp.thr = thre;
lp.noiself = local_noiself;
- lp.noiself = local_noiself;
+ lp.noiseldetail = local_noiseldetail;
lp.noiselc = local_noiselc;
lp.noisecf = local_noisecf;
lp.noisecc = local_noisecc;
@@ -7235,6 +7246,10 @@ void ImProcFunctions::calc_ref(LabImage * original, LabImage * transformed, int
hueref = xatan2f(avB, avA); //mean hue
chromaref = aveChro;
lumaref = avL;
+
+ if (lumaref > 95.f) {//to avoid crash
+ lumaref = 95.f;
+ }
}
}
@@ -8487,8 +8502,58 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
if (call == 1) {
LabImage tmp1(transformed->W, transformed->H);
+ array2D *Lin = nullptr;
+
+
int GW = transformed->W;
int GH = transformed->H;
+ int max_numblox_W = ceil((static_cast(GW)) / (offset)) + 2 * blkrad;
+ // calculate min size of numblox_W.
+ int min_numblox_W = ceil((static_cast(GW)) / (offset)) + 2 * blkrad;
+
+ // these are needed only for creation of the plans and will be freed before entering the parallel loop
+ fftwf_plan plan_forward_blox[2];
+ fftwf_plan plan_backward_blox[2];
+ array2D tilemask_in(TS, TS);
+ array2D tilemask_out(TS, TS);
+
+ if ((lp.noiself > 0.1f || lp.noiselc > 0.1f)) {
+ float *Lbloxtmp = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float)));
+ float *fLbloxtmp = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float)));
+
+ int nfwd[2] = {TS, TS};
+
+ //for DCT:
+ fftw_r2r_kind fwdkind[2] = {FFTW_REDFT10, FFTW_REDFT10};
+ fftw_r2r_kind bwdkind[2] = {FFTW_REDFT01, FFTW_REDFT01};
+
+ // Creating the plans with FFTW_MEASURE instead of FFTW_ESTIMATE speeds up the execute a bit
+ plan_forward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, Lbloxtmp, nullptr, 1, TS * TS, fLbloxtmp, nullptr, 1, TS * TS, fwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT);
+ plan_backward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, fLbloxtmp, nullptr, 1, TS * TS, Lbloxtmp, nullptr, 1, TS * TS, bwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT);
+ plan_forward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, Lbloxtmp, nullptr, 1, TS * TS, fLbloxtmp, nullptr, 1, TS * TS, fwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT);
+ plan_backward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, fLbloxtmp, nullptr, 1, TS * TS, Lbloxtmp, nullptr, 1, TS * TS, bwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT);
+ fftwf_free(Lbloxtmp);
+ fftwf_free(fLbloxtmp);
+
+ const int border = MAX(2, TS / 16);
+
+ for (int i = 0; i < TS; ++i) {
+ float i1 = abs((i > TS / 2 ? i - TS + 1 : i));
+ float vmask = (i1 < border ? SQR(sin((rtengine::RT_PI * i1) / (2 * border))) : 1.0f);
+ float vmask2 = (i1 < 2 * border ? SQR(sin((rtengine::RT_PI * i1) / (2 * border))) : 1.0f);
+
+ for (int j = 0; j < TS; ++j) {
+ float j1 = abs((j > TS / 2 ? j - TS + 1 : j));
+ tilemask_in[i][j] = (vmask * (j1 < border ? SQR(sin((rtengine::RT_PI * j1) / (2 * border))) : 1.0f)) + epsilon;
+ tilemask_out[i][j] = (vmask2 * (j1 < 2 * border ? SQR(sin((rtengine::RT_PI * j1) / (2 * border))) : 1.0f)) + epsilon;
+
+ }
+ }
+
+ }
+
+ float *LbloxArray[numThreads];
+ float *fLbloxArray[numThreads];
for (int ir = 0; ir < GH; ir++)
for (int jr = 0; jr < GW; jr++) {
@@ -8507,6 +8572,7 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
wavelet_decomposition bdecomp(tmp1.b[0], tmp1.W, tmp1.H, levwavL, 1, skip, numThreads, DaubLen);
float madL[8][3];
+ float madC[8][3];
int edge = 2;
if (!Ldecomp.memoryAllocationFailed) {
@@ -8529,7 +8595,7 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
edge = 2;
vari[0] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
vari[1] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
- vari[2] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
+ vari[2] = 8.f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0));
vari[3] = 8.f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0));
vari[4] = 8.f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0));
@@ -8539,21 +8605,43 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
edge = 3;
vari[0] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
vari[1] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
- vari[2] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
- vari[3] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiselc / 25.0));
+ vari[2] = 8.f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0));
+ vari[3] = 8.f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0));
}
if ((lp.noiself > 0.1f || lp.noiselc > 0.1f)) {
+ float kr3 = 0.f;
+ float kr4 = 0.f;
+ float kr5 = 0.f;
+
+ if (lp.noiselc < 30.f) {
+ kr3 = 0.f;
+ kr4 = 0.f;
+ kr5 = 0.f;
+ } else if (lp.noiselc < 50.f) {
+ kr3 = 0.5f;
+ kr4 = 0.3f;
+ kr5 = 0.2f;
+ } else if (lp.noiselc < 70.f) {
+ kr3 = 0.7f;
+ kr4 = 0.5f;
+ kr5 = 0.3f;
+ } else {
+ kr3 = 1.f;
+ kr4 = 1.f;
+ kr5 = 1.f;
+ }
+
vari[0] = max(0.0001f, vari[0]);
vari[1] = max(0.0001f, vari[1]);
vari[2] = max(0.0001f, vari[2]);
- vari[3] = max(0.0001f, vari[3]);
+ vari[3] = max(0.0001f, kr3 * vari[3]);
if (levred == 7) {
- vari[4] = max(0.0001f, vari[4]);
- vari[5] = max(0.0001f, vari[5]);
- vari[6] = max(0.0001f, vari[6]);
+ vari[4] = max(0.0001f, kr4 * vari[4]);
+ vari[5] = max(0.0001f, kr5 * vari[5]);
+ vari[6] = max(0.0001f, kr5 * vari[6]);
}
float* noisevarlum = nullptr; // we need a dummy to pass it to WaveletDenoiseAllL
@@ -8565,6 +8653,23 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
float variC[levred];
if (!adecomp.memoryAllocationFailed && !bdecomp.memoryAllocationFailed) {
+ #pragma omp parallel for collapse(2) schedule(dynamic,1)
+
+ for (int lvl = 0; lvl < levred; ++lvl) {
+ // compute median absolute deviation (MAD) of detail coefficients as robust noise estimator
+ for (int dir = 1; dir < 4; ++dir) {
+
+ int Wlvl_ab = adecomp.level_W(lvl);//approximation with only "a" (better than L
+ int Hlvl_ab = adecomp.level_H(lvl);
+
+ float ** WavCoeffs_ab = adecomp.level_coeffs(lvl);
+ madC[lvl][dir - 1] = SQR(Mad(WavCoeffs_ab[dir], Wlvl_ab * Hlvl_ab));
+ }
+
+ }
+
+
+
if (levred == 7) {
edge = 2;
variC[0] = SQR(lp.noisecf / 10.0);
@@ -8610,18 +8715,191 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
}
float noisevarab_r = 100.f; //SQR(lp.noisecc / 10.0);
- WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, false, false, false, numThreads);
- WaveletDenoiseAllAB(Ldecomp, bdecomp, noisevarchrom, madL, variC, edge, noisevarab_r, false, false, false, numThreads);
+ WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madC, variC, edge, noisevarab_r, false, false, false, numThreads);
+ WaveletDenoiseAllAB(Ldecomp, bdecomp, noisevarchrom, madC, variC, edge, noisevarab_r, false, false, false, numThreads);
delete[] noisevarchrom;
}
}
if (!Ldecomp.memoryAllocationFailed) {
+ Lin = new array2D(GW, GH);
+
+ for (int i = 0; i < GH; ++i) {
+ for (int j = 0; j < GW; ++j) {
+ (*Lin)[i][j] = tmp1.L[i][j];
+ }
+ }
Ldecomp.reconstruct(tmp1.L[0]);
}
+ if (!Ldecomp.memoryAllocationFailed) {
+
+ const int numblox_W = ceil((static_cast(GW)) / (offset)) + 2 * blkrad;
+ const int numblox_H = ceil((static_cast(GH)) / (offset)) + 2 * blkrad;
+
+ if ((lp.noiself > 0.1f || lp.noiselc > 0.1f)) {
+ //residual between input and denoised L channel
+ array2D Ldetail(GW, GH, ARRAY2D_CLEAR_DATA);
+ array2D totwt(GW, GH, ARRAY2D_CLEAR_DATA); //weight for combining DCT blocks
+
+ for (int i = 0; i < numThreads; ++i) {
+ LbloxArray[i] = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float)));
+ fLbloxArray[i] = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float)));
+ }
+
+#ifdef _OPENMP
+ int masterThread = omp_get_thread_num();
+#endif
+#ifdef _OPENMP
+ #pragma omp parallel //num_threads(denoiseNestedLevels) if (denoiseNestedLevels>1)
+#endif
+ {
+#ifdef _OPENMP
+ int subThread = masterThread * 1 + omp_get_thread_num();
+#else
+ int subThread = 0;
+#endif
+ float blurbuffer[TS * TS] ALIGNED64;
+ float *Lblox = LbloxArray[subThread];
+ float *fLblox = fLbloxArray[subThread];
+ float pBuf[GW + TS + 2 * blkrad * offset] ALIGNED16;
+ float nbrwt[TS * TS] ALIGNED64;
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int vblk = 0; vblk < numblox_H; ++vblk) {
+
+ int top = (vblk - blkrad) * offset;
+ float * datarow = pBuf + blkrad * offset;
+
+ for (int i = 0; i < TS; ++i) {
+ int row = top + i;
+ int rr = row;
+
+ if (row < 0) {
+ rr = MIN(-row, GH - 1);
+ } else if (row >= GH) {
+ rr = MAX(0, 2 * GH - 2 - row);
+ }
+
+ for (int j = 0; j < tmp1.W; ++j) {
+ datarow[j] = ((*Lin)[rr][j] - tmp1.L[rr][j]);
+ }
+
+ for (int j = -blkrad * offset; j < 0; ++j) {
+ datarow[j] = datarow[MIN(-j, GW - 1)];
+ }
+
+ for (int j = GW; j < GW + TS + blkrad * offset; ++j) {
+ datarow[j] = datarow[MAX(0, 2 * GW - 2 - j)];
+ }//now we have a padded data row
+
+ //now fill this row of the blocks with Lab high pass data
+ for (int hblk = 0; hblk < numblox_W; ++hblk) {
+ int left = (hblk - blkrad) * offset;
+ int indx = (hblk) * TS; //index of block in malloc
+
+ if (top + i >= 0 && top + i < GH) {
+ int j;
+
+ for (j = 0; j < min((-left), TS); ++j) {
+ Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data
+ }
+
+ for (; j < min(TS, GW - left); ++j) {
+ Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data
+ totwt[top + i][left + j] += tilemask_in[i][j] * tilemask_out[i][j];
+ }
+
+ for (; j < TS; ++j) {
+ Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data
+ }
+ } else {
+ for (int j = 0; j < TS; ++j) {
+ Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data
+ }
+ }
+
+ }
+
+ }//end of filling block row
+
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ //fftwf_print_plan (plan_forward_blox);
+ if (numblox_W == max_numblox_W) {
+ fftwf_execute_r2r(plan_forward_blox[0], Lblox, fLblox); // DCT an entire row of tiles
+ } else {
+ fftwf_execute_r2r(plan_forward_blox[1], Lblox, fLblox); // DCT an entire row of tiles
+ }
+
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ // now process the vblk row of blocks for noise reduction
+ float params_Ldetail = min(float(lp.noiseldetail), 99.9f); // max out to avoid div by zero when using noisevar_Ldetail as divisor
+ float noisevar_Ldetail = SQR(static_cast(SQR(100. - params_Ldetail) + 50.*(100. - params_Ldetail)) * TS * 0.5f);
+
+
+
+ for (int hblk = 0; hblk < numblox_W; ++hblk) {
+ ImProcFunctions::RGBtile_denoise(fLblox, hblk, noisevar_Ldetail, nbrwt, blurbuffer);
+ }//end of horizontal block loop
+
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ //now perform inverse FT of an entire row of blocks
+ if (numblox_W == max_numblox_W) {
+ fftwf_execute_r2r(plan_backward_blox[0], fLblox, Lblox); //for DCT
+ } else {
+ fftwf_execute_r2r(plan_backward_blox[1], fLblox, Lblox); //for DCT
+ }
+
+ int topproc = (vblk - blkrad) * offset;
+
+ //add row of blocks to output image tile
+ ImProcFunctions::RGBoutput_tile_row(Lblox, Ldetail, tilemask_out, GH, GW, topproc);
+
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ }//end of vertical block loop
+
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ }
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#ifdef _OPENMP
+
+ #pragma omp parallel for //num_threads(denoiseNestedLevels) if (denoiseNestedLevels>1)
+#endif
+
+ for (int i = 0; i < GH; ++i) {
+ for (int j = 0; j < GW; ++j) {
+ //may want to include masking threshold for large hipass data to preserve edges/detail
+ tmp1.L[i][j] += Ldetail[i][j] / totwt[i][j]; //note that labdn initially stores the denoised hipass data
+ }
+ }
+
+ }
+
+ delete Lin;
+ }
+
+ if ((lp.noiself > 0.1f || lp.noiselc > 0.1f)) {
+
+ for (int i = 0; i < numThreads; ++i) {
+ fftwf_free(LbloxArray[i]);
+ fftwf_free(fLbloxArray[i]);
+ }
+
+ fftwf_destroy_plan(plan_forward_blox[0]);
+ fftwf_destroy_plan(plan_backward_blox[0]);
+ fftwf_destroy_plan(plan_forward_blox[1]);
+ fftwf_destroy_plan(plan_backward_blox[1]);
+ fftwf_cleanup();
+
+ }
+
if (!adecomp.memoryAllocationFailed) {
adecomp.reconstruct(tmp1.a[0]);
@@ -8640,6 +8918,54 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
int bfw = int (lp.lx + lp.lxL) + del;
LabImage bufwv(bfw, bfh);
bufwv.clear(true);
+ array2D *Lin = nullptr;
+ int max_numblox_W = ceil((static_cast(bfw)) / (offset)) + 2 * blkrad;
+ // calculate min size of numblox_W.
+ int min_numblox_W = ceil((static_cast(bfw)) / (offset)) + 2 * blkrad;
+ // these are needed only for creation of the plans and will be freed before entering the parallel loop
+ fftwf_plan plan_forward_blox[2];
+ fftwf_plan plan_backward_blox[2];
+ array2D tilemask_in(TS, TS);
+ array2D tilemask_out(TS, TS);
+
+ if ((lp.noiself > 0.1f || lp.noiselc > 0.1f)) {
+ float *Lbloxtmp = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float)));
+ float *fLbloxtmp = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float)));
+
+ int nfwd[2] = {TS, TS};
+
+ //for DCT:
+ fftw_r2r_kind fwdkind[2] = {FFTW_REDFT10, FFTW_REDFT10};
+ fftw_r2r_kind bwdkind[2] = {FFTW_REDFT01, FFTW_REDFT01};
+
+ // Creating the plans with FFTW_MEASURE instead of FFTW_ESTIMATE speeds up the execute a bit
+ plan_forward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, Lbloxtmp, nullptr, 1, TS * TS, fLbloxtmp, nullptr, 1, TS * TS, fwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT);
+ plan_backward_blox[0] = fftwf_plan_many_r2r(2, nfwd, max_numblox_W, fLbloxtmp, nullptr, 1, TS * TS, Lbloxtmp, nullptr, 1, TS * TS, bwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT);
+ plan_forward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, Lbloxtmp, nullptr, 1, TS * TS, fLbloxtmp, nullptr, 1, TS * TS, fwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT);
+ plan_backward_blox[1] = fftwf_plan_many_r2r(2, nfwd, min_numblox_W, fLbloxtmp, nullptr, 1, TS * TS, Lbloxtmp, nullptr, 1, TS * TS, bwdkind, FFTW_MEASURE || FFTW_DESTROY_INPUT);
+ fftwf_free(Lbloxtmp);
+ fftwf_free(fLbloxtmp);
+
+ const int border = MAX(2, TS / 16);
+
+ for (int i = 0; i < TS; ++i) {
+ float i1 = abs((i > TS / 2 ? i - TS + 1 : i));
+ float vmask = (i1 < border ? SQR(sin((rtengine::RT_PI * i1) / (2 * border))) : 1.0f);
+ float vmask2 = (i1 < 2 * border ? SQR(sin((rtengine::RT_PI * i1) / (2 * border))) : 1.0f);
+
+ for (int j = 0; j < TS; ++j) {
+ float j1 = abs((j > TS / 2 ? j - TS + 1 : j));
+ tilemask_in[i][j] = (vmask * (j1 < border ? SQR(sin((rtengine::RT_PI * j1) / (2 * border))) : 1.0f)) + epsilon;
+ tilemask_out[i][j] = (vmask2 * (j1 < 2 * border ? SQR(sin((rtengine::RT_PI * j1) / (2 * border))) : 1.0f)) + epsilon;
+
+ }
+ }
+
+ }
+
+ float *LbloxArray[numThreads];
+ float *fLbloxArray[numThreads];
+
int begy = lp.yc - lp.lyT;
int begx = lp.xc - lp.lxL;
@@ -8694,7 +9020,7 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
edge = 2;
vari[0] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
vari[1] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
- vari[2] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
+ vari[2] = 8.f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0));
vari[3] = 8.f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0));
vari[4] = 8.f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0));
@@ -8704,23 +9030,44 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
edge = 3;
vari[0] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
vari[1] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
- vari[2] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiself / 25.0));
- vari[3] = 8.f * SQR((lp.noiself / 125.0) * (1.0 + lp.noiselc / 25.0));
+ vari[2] = 8.f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0));
+ vari[3] = 8.f * SQR((lp.noiselc / 125.0) * (1.0 + lp.noiselc / 25.0));
}
if ((lp.noiself > 0.1f || lp.noiselc > 0.1f)) {
+ float kr3 = 0.f;
+ float kr4 = 0.f;
+ float kr5 = 0.f;
+
+ if (lp.noiselc < 30.f) {
+ kr3 = 0.f;
+ kr4 = 0.f;
+ kr5 = 0.f;
+ } else if (lp.noiselc < 50.f) {
+ kr3 = 0.5f;
+ kr4 = 0.3f;
+ kr5 = 0.2f;
+ } else if (lp.noiselc < 70.f) {
+ kr3 = 0.7f;
+ kr4 = 0.5f;
+ kr5 = 0.3f;
+ } else {
+ kr3 = 1.f;
+ kr4 = 1.f;
+ kr5 = 1.f;
+ }
+
vari[0] = max(0.0001f, vari[0]);
vari[1] = max(0.0001f, vari[1]);
vari[2] = max(0.0001f, vari[2]);
- vari[3] = max(0.0001f, vari[3]);
+ vari[3] = max(0.0001f, kr3 * vari[3]);
if (levred == 7) {
-
- vari[4] = max(0.0001f, vari[4]);
- vari[5] = max(0.0001f, vari[5]);
- vari[6] = max(0.0001f, vari[6]);
+ vari[4] = max(0.0001f, kr4 * vari[4]);
+ vari[5] = max(0.0001f, kr5 * vari[5]);
+ vari[6] = max(0.0001f, kr5 * vari[6]);
}
float* noisevarlum = nullptr; // we need a dummy to pass it to WaveletDenoiseAllL
@@ -8733,6 +9080,21 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
float variC[levred];
if (!adecomp.memoryAllocationFailed && !bdecomp.memoryAllocationFailed) {
+ float madC[8][3];
+ #pragma omp parallel for collapse(2) schedule(dynamic,1)
+
+ for (int lvl = 0; lvl < levred; ++lvl) {
+ // compute median absolute deviation (MAD) of detail coefficients as robust noise estimator
+ for (int dir = 1; dir < 4; ++dir) {
+
+ int Wlvl_ab = adecomp.level_W(lvl);//approximation with only "a" (better than L
+ int Hlvl_ab = adecomp.level_H(lvl);
+
+ float ** WavCoeffs_ab = adecomp.level_coeffs(lvl);
+ madC[lvl][dir - 1] = SQR(Mad(WavCoeffs_ab[dir], Wlvl_ab * Hlvl_ab));
+ }
+
+ }
if (levred == 7) {
edge = 2;
@@ -8779,18 +9141,195 @@ void ImProcFunctions::Lab_Local(int call, float** shbuffer, LabImage * original,
float noisevarab_r = 100.f; //SQR(lp.noisecc / 10.0);
- WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madL, variC, edge, noisevarab_r, false, false, false, numThreads);
- WaveletDenoiseAllAB(Ldecomp, bdecomp, noisevarchrom, madL, variC, edge, noisevarab_r, false, false, false, numThreads);
+ WaveletDenoiseAllAB(Ldecomp, adecomp, noisevarchrom, madC, variC, edge, noisevarab_r, false, false, false, numThreads);
+ WaveletDenoiseAllAB(Ldecomp, bdecomp, noisevarchrom, madC, variC, edge, noisevarab_r, false, false, false, numThreads);
delete[] noisevarchrom;
}
}
if (!Ldecomp.memoryAllocationFailed) {
+ Lin = new array2D(bfw, bfh);
+ // #pragma omp parallel for num_threads(numThreads) if (numThreads>1)
+
+
+ for (int i = 0; i < bfh; ++i) {
+ for (int j = 0; j < bfw; ++j) {
+ (*Lin)[i][j] = bufwv.L[i][j];
+ }
+ }
Ldecomp.reconstruct(bufwv.L[0]);
}
+
+ if (!Ldecomp.memoryAllocationFailed) {
+
+ const int numblox_W = ceil((static_cast(bfw)) / (offset)) + 2 * blkrad;
+ const int numblox_H = ceil((static_cast(bfh)) / (offset)) + 2 * blkrad;
+
+ if ((lp.noiself > 0.1f || lp.noiselc > 0.1f)) {
+ //residual between input and denoised L channel
+ array2D Ldetail(bfw, bfh, ARRAY2D_CLEAR_DATA);
+ //pixel weight
+ array2D totwt(bfw, bfh, ARRAY2D_CLEAR_DATA); //weight for combining DCT blocks
+
+ for (int i = 0; i < numThreads; ++i) {
+ LbloxArray[i] = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float)));
+ fLbloxArray[i] = reinterpret_cast(fftwf_malloc(max_numblox_W * TS * TS * sizeof(float)));
+ }
+
+#ifdef _OPENMP
+ int masterThread = omp_get_thread_num();
+#endif
+#ifdef _OPENMP
+ #pragma omp parallel //num_threads(denoiseNestedLevels) if (denoiseNestedLevels>1)
+#endif
+ {
+#ifdef _OPENMP
+ int subThread = masterThread * 1 + omp_get_thread_num();
+#else
+ int subThread = 0;
+#endif
+ float blurbuffer[TS * TS] ALIGNED64;
+ float *Lblox = LbloxArray[subThread];
+ float *fLblox = fLbloxArray[subThread];
+ float pBuf[bfw + TS + 2 * blkrad * offset] ALIGNED16;
+ float nbrwt[TS * TS] ALIGNED64;
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int vblk = 0; vblk < numblox_H; ++vblk) {
+
+ int top = (vblk - blkrad) * offset;
+ float * datarow = pBuf + blkrad * offset;
+
+ for (int i = 0; i < TS; ++i) {
+ int row = top + i;
+ int rr = row;
+
+ if (row < 0) {
+ rr = MIN(-row, bfh - 1);
+ } else if (row >= bfh) {
+ rr = MAX(0, 2 * bfh - 2 - row);
+ }
+
+ for (int j = 0; j < bufwv.W; ++j) {
+ datarow[j] = ((*Lin)[rr][j] - bufwv.L[rr][j]);
+ }
+
+ for (int j = -blkrad * offset; j < 0; ++j) {
+ datarow[j] = datarow[MIN(-j, bfw - 1)];
+ }
+
+ for (int j = bfw; j < bfw + TS + blkrad * offset; ++j) {
+ datarow[j] = datarow[MAX(0, 2 * bfw - 2 - j)];
+ }//now we have a padded data row
+
+ //now fill this row of the blocks with Lab high pass data
+ for (int hblk = 0; hblk < numblox_W; ++hblk) {
+ int left = (hblk - blkrad) * offset;
+ int indx = (hblk) * TS; //index of block in malloc
+
+ if (top + i >= 0 && top + i < bfh) {
+ int j;
+
+ for (j = 0; j < min((-left), TS); ++j) {
+ Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data
+ }
+
+ for (; j < min(TS, bfw - left); ++j) {
+ Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data
+ totwt[top + i][left + j] += tilemask_in[i][j] * tilemask_out[i][j];
+ }
+
+ for (; j < TS; ++j) {
+ Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data
+ }
+ } else {
+ for (int j = 0; j < TS; ++j) {
+ Lblox[(indx + i)*TS + j] = tilemask_in[i][j] * datarow[left + j]; // luma data
+ }
+ }
+
+ }
+
+ }//end of filling block row
+
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ //fftwf_print_plan (plan_forward_blox);
+ if (numblox_W == max_numblox_W) {
+ fftwf_execute_r2r(plan_forward_blox[0], Lblox, fLblox); // DCT an entire row of tiles
+ } else {
+ fftwf_execute_r2r(plan_forward_blox[1], Lblox, fLblox); // DCT an entire row of tiles
+ }
+
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ // now process the vblk row of blocks for noise reduction
+ float params_Ldetail = min(float(lp.noiseldetail), 99.9f); // max out to avoid div by zero when using noisevar_Ldetail as divisor
+ float noisevar_Ldetail = SQR(static_cast(SQR(100. - params_Ldetail) + 50.*(100. - params_Ldetail)) * TS * 0.5f);
+
+
+
+ for (int hblk = 0; hblk < numblox_W; ++hblk) {
+ ImProcFunctions::RGBtile_denoise(fLblox, hblk, noisevar_Ldetail, nbrwt, blurbuffer);
+ }//end of horizontal block loop
+
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ //now perform inverse FT of an entire row of blocks
+ if (numblox_W == max_numblox_W) {
+ fftwf_execute_r2r(plan_backward_blox[0], fLblox, Lblox); //for DCT
+ } else {
+ fftwf_execute_r2r(plan_backward_blox[1], fLblox, Lblox); //for DCT
+ }
+
+ int topproc = (vblk - blkrad) * offset;
+
+ //add row of blocks to output image tile
+ ImProcFunctions::RGBoutput_tile_row(Lblox, Ldetail, tilemask_out, bfh, bfw, topproc);
+
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ }//end of vertical block loop
+
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ }
+ //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#ifdef _OPENMP
+
+ #pragma omp parallel for //num_threads(denoiseNestedLevels) if (denoiseNestedLevels>1)
+#endif
+
+ for (int i = 0; i < bfh; ++i) {
+ for (int j = 0; j < bfw; ++j) {
+ //may want to include masking threshold for large hipass data to preserve edges/detail
+ bufwv.L[i][j] += Ldetail[i][j] / totwt[i][j]; //note that labdn initially stores the denoised hipass data
+ }
+ }
+
+ }
+
+ delete Lin;
+ }
+
+ if ((lp.noiself > 0.1f || lp.noiselc > 0.1f)) {
+
+ for (int i = 0; i < numThreads; ++i) {
+ fftwf_free(LbloxArray[i]);
+ fftwf_free(fLbloxArray[i]);
+ }
+
+ fftwf_destroy_plan(plan_forward_blox[0]);
+ fftwf_destroy_plan(plan_backward_blox[0]);
+ fftwf_destroy_plan(plan_forward_blox[1]);
+ fftwf_destroy_plan(plan_backward_blox[1]);
+ fftwf_cleanup();
+
+ }
+
if (!adecomp.memoryAllocationFailed) {
adecomp.reconstruct(bufwv.a[0]);
diff --git a/rtengine/procevents.h b/rtengine/procevents.h
index 479374b08..75e150483 100644
--- a/rtengine/procevents.h
+++ b/rtengine/procevents.h
@@ -619,6 +619,7 @@ enum ProcEvent {
Evlocallabsensiexclu = 589,
Evlocallabstruc = 590,
Evlocallabwarm = 591,
+ Evlocallabnoiselumdetail = 592,
NUMOFEVENTS
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index fb2a0c998..c1e311f9e 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -1784,6 +1784,7 @@ bool ChannelMixerParams::operator ==(const ChannelMixerParams& other) const
if (enabled != other.enabled) {
return false;
}
+
for (unsigned int i = 0; i < 3; ++i) {
if (
red[i] != other.red[i]
@@ -2373,6 +2374,7 @@ pastsattog(true),
sensiv(19),
noiselumf(0),
noiselumc(0),
+noiselumdetail(0),
noisechrof(0),
noisechroc(0),
sharradius(40),
@@ -2505,6 +2507,7 @@ bool LocallabParams::operator ==(const LocallabParams& other) const
&& excurve == other.excurve
&& noiselumf == other.noiselumf
&& noiselumc == other.noiselumc
+ && noiselumdetail == other.noiselumdetail
&& noisechrof == other.noisechrof
&& noisechroc == other.noisechroc
&& sharradius == other.sharradius
@@ -3116,6 +3119,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
// Channel mixer
saveToKeyfile(!pedited || pedited->chmixer.enabled, "Channel Mixer", "Enabled", chmixer.enabled, keyFile);
+
if (!pedited || pedited->chmixer.red[0] || pedited->chmixer.red[1] || pedited->chmixer.red[2]) {
Glib::ArrayHandle rmix(chmixer.red, 3, Glib::OWNERSHIP_NONE);
keyFile.set_integer_list("Channel Mixer", "Red", rmix);
@@ -3478,6 +3482,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
saveToKeyfile(!pedited || pedited->locallab.excurve, "Locallab", "ExCurve", locallab.excurve, keyFile);
saveToKeyfile(!pedited || pedited->locallab.noiselumf, "Locallab", "noiselumf", locallab.noiselumf, keyFile);
saveToKeyfile(!pedited || pedited->locallab.noiselumc, "Locallab", "noiselumc", locallab.noiselumc, keyFile);
+ saveToKeyfile(!pedited || pedited->locallab.noiselumdetail, "Locallab", "noiselumdetail", locallab.noiselumdetail, keyFile);
saveToKeyfile(!pedited || pedited->locallab.noisechrof, "Locallab", "noisechrof", locallab.noisechrof, keyFile);
saveToKeyfile(!pedited || pedited->locallab.noisechroc, "Locallab", "noisechroc", locallab.noisechroc, keyFile);
saveToKeyfile(!pedited || pedited->locallab.sharradius, "Locallab", "Sharradius", locallab.sharradius, keyFile);
@@ -3941,19 +3946,21 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
assignFromKeyfile(keyFile, "HLRecovery", "Method", pedited, toneCurve.method, pedited->toneCurve.method);
}
- if (keyFile.has_group ("Channel Mixer")) {
+ if (keyFile.has_group("Channel Mixer")) {
if (ppVersion >= 329) {
assignFromKeyfile(keyFile, "Channel Mixer", "Enabled", pedited, chmixer.enabled, pedited->chmixer.enabled);
} else {
chmixer.enabled = true;
+
if (pedited) {
pedited->chmixer.enabled = true;
}
}
- if (keyFile.has_key ("Channel Mixer", "Red") && keyFile.has_key ("Channel Mixer", "Green") && keyFile.has_key ("Channel Mixer", "Blue")) {
- const std::vector rmix = keyFile.get_integer_list ("Channel Mixer", "Red");
- const std::vector gmix = keyFile.get_integer_list ("Channel Mixer", "Green");
- const std::vector bmix = keyFile.get_integer_list ("Channel Mixer", "Blue");
+
+ if (keyFile.has_key("Channel Mixer", "Red") && keyFile.has_key("Channel Mixer", "Green") && keyFile.has_key("Channel Mixer", "Blue")) {
+ const std::vector rmix = keyFile.get_integer_list("Channel Mixer", "Red");
+ const std::vector gmix = keyFile.get_integer_list("Channel Mixer", "Green");
+ const std::vector bmix = keyFile.get_integer_list("Channel Mixer", "Blue");
if (rmix.size() == 3 && gmix.size() == 3 && bmix.size() == 3) {
memcpy(chmixer.red, rmix.data(), 3 * sizeof(int));
@@ -4192,7 +4199,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
assignFromKeyfile(keyFile, "Vibrance", "SkinTonesCurve", pedited, vibrance.skintonescurve, pedited->vibrance.skintonescurve);
}
- if (keyFile.has_group ("White Balance")) {
+ if (keyFile.has_group("White Balance")) {
assignFromKeyfile(keyFile, "White Balance", "Enabled", pedited, wb.enabled, pedited->wb.enabled);
assignFromKeyfile(keyFile, "White Balance", "Setting", pedited, wb.method, pedited->wb.method);
assignFromKeyfile(keyFile, "White Balance", "Temperature", pedited, wb.temperature, pedited->wb.temperature);
@@ -4529,6 +4536,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
assignFromKeyfile(keyFile, "Locallab", "Shcompr", pedited, locallab.shcompr, pedited->locallab.shcompr);
assignFromKeyfile(keyFile, "Locallab", "noiselumf", pedited, locallab.noiselumf, pedited->locallab.noiselumf);
assignFromKeyfile(keyFile, "Locallab", "noiselumc", pedited, locallab.noiselumc, pedited->locallab.noiselumc);
+ assignFromKeyfile(keyFile, "Locallab", "noiselumdetail", pedited, locallab.noiselumdetail, pedited->locallab.noiselumdetail);
assignFromKeyfile(keyFile, "Locallab", "noisechrof", pedited, locallab.noisechrof, pedited->locallab.noisechrof);
assignFromKeyfile(keyFile, "Locallab", "noisechroc", pedited, locallab.noisechroc, pedited->locallab.noisechroc);
assignFromKeyfile(keyFile, "Locallab", "Sharradius", pedited, locallab.sharradius, pedited->locallab.sharradius);
@@ -5023,15 +5031,17 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
}
}
- if (keyFile.has_group ("HSV Equalizer")) {
+ if (keyFile.has_group("HSV Equalizer")) {
if (ppVersion >= 329) {
assignFromKeyfile(keyFile, "HSV Equalizer", "Enabled", pedited, hsvequalizer.enabled, pedited->hsvequalizer.enabled);
} else {
hsvequalizer.enabled = true;
+
if (pedited) {
pedited->hsvequalizer.enabled = true;
}
}
+
if (ppVersion >= 300) {
assignFromKeyfile(keyFile, "HSV Equalizer", "HCurve", pedited, hsvequalizer.hcurve, pedited->hsvequalizer.hcurve);
assignFromKeyfile(keyFile, "HSV Equalizer", "SCurve", pedited, hsvequalizer.scurve, pedited->hsvequalizer.scurve);
@@ -5039,15 +5049,17 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
}
}
- if (keyFile.has_group ("RGB Curves")) {
+ if (keyFile.has_group("RGB Curves")) {
if (ppVersion >= 329) {
assignFromKeyfile(keyFile, "RGB Curves", "Enabled", pedited, rgbCurves.enabled, pedited->rgbCurves.enabled);
} else {
rgbCurves.enabled = true;
+
if (pedited) {
pedited->rgbCurves.enabled = true;
}
}
+
assignFromKeyfile(keyFile, "RGB Curves", "LumaMode", pedited, rgbCurves.lumamode, pedited->rgbCurves.lumamode);
assignFromKeyfile(keyFile, "RGB Curves", "rCurve", pedited, rgbCurves.rcurve, pedited->rgbCurves.rcurve);
assignFromKeyfile(keyFile, "RGB Curves", "gCurve", pedited, rgbCurves.gcurve, pedited->rgbCurves.gcurve);
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index 924352dfe..85f56de64 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -914,6 +914,7 @@ struct LocallabParams {
int sensiv;
int noiselumf;
int noiselumc;
+ int noiselumdetail;
int noisechrof;
int noisechroc;
int sharradius;
diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc
index cdb5449d7..ba24c7314 100644
--- a/rtengine/refreshmap.cc
+++ b/rtengine/refreshmap.cc
@@ -618,6 +618,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = {
LUMINANCECURVE, // Evlocallabexclumethod
LUMINANCECURVE, // Evlocallabsensiexclu
LUMINANCECURVE, // Evlocallabstruc
- LUMINANCECURVE // Evlocallabwarm
+ LUMINANCECURVE, // Evlocallabwarm
+ LUMINANCECURVE // Evlocallabnoiselumdetail
+
};
diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc
index 83d8ab09e..3fcfe7e9e 100644
--- a/rtengine/simpleprocess.cc
+++ b/rtengine/simpleprocess.cc
@@ -233,7 +233,7 @@ private:
if (!params.wb.enabled) {
currWB = ColorTemp();
} else if (params.wb.method == "Camera") {
- currWB = imgsrc->getWB ();
+ currWB = imgsrc->getWB();
} else if (params.wb.method == "Auto") {
double rm, gm, bm;
imgsrc->getAutoWBMultipliers(rm, gm, bm);
@@ -1103,7 +1103,7 @@ private:
}
ifstream fich(datalab, ios::in);
- int maxdata = 86; //85 10016 //82;//78;//73 10011
+ int maxdata = 87; //86 10017//85 10016 //82;//78;//73 10011
if (fich && versionmip != 0) {
std::string inser;
@@ -1338,6 +1338,7 @@ private:
dataspots[79][0] = params.locallab.sensiexclu;
dataspots[80][0] = params.locallab.struc;
dataspots[81][0] = params.locallab.warm;
+ dataspots[82][0] = params.locallab.noiselumdetail;
dataspots[maxdata - 4][0] = 100.f * params.locallab.hueref;
dataspots[maxdata - 3][0] = params.locallab.chromaref;
@@ -1807,6 +1808,7 @@ private:
params.locallab.sensiexclu = dataspots[79][sp];
params.locallab.struc = dataspots[80][sp];
params.locallab.warm = dataspots[81][sp];
+ params.locallab.noiselumdetail = dataspots[82][sp];
params.locallab.hueref = ((float) dataspots[maxdata - 4][sp]) / 100.f;
params.locallab.chromaref = dataspots[maxdata - 3][sp];
diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc
index 3ee4c1b23..82b1247ee 100644
--- a/rtgui/locallab.cc
+++ b/rtgui/locallab.cc
@@ -106,6 +106,7 @@ Locallab::Locallab():
sensisha(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSIS"), 0, 100, 1, 19))),
noiselumf(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMFINE"), 0, 100, 1, 0))),
noiselumc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMCOARSE"), 0, 100, 1, 0))),
+ noiselumdetail(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMDETAIL"), 0, 100, 1, 50))),
noisechrof(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISECHROFINE"), 0, 100, 1, 0))),
noisechroc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISECHROCOARSE"), 0, 100, 1, 0))),
hueref(Gtk::manage(new Adjuster(M("TP_LOCALLAB_HUEREF"), -3.15, 3.15, 0.01, 0))),
@@ -640,6 +641,7 @@ Locallab::Locallab():
noiselumf->setAdjusterListener(this);
noiselumc->setAdjusterListener(this);
+ noiselumdetail->setAdjusterListener(this);
noisechrof->setAdjusterListener(this);
@@ -648,6 +650,7 @@ Locallab::Locallab():
denoisBox->pack_start(*noiselumf);
denoisBox->pack_start(*noiselumc);
+ denoisBox->pack_start(*noiselumdetail);
denoisBox->pack_start(*noisechrof);
denoisBox->pack_start(*noisechroc);
@@ -1301,6 +1304,7 @@ void Locallab::neutral_pressed()
inverssha->set_active(false);
noiselumf->resetValue(false);
noiselumc->resetValue(false);
+ noiselumdetail->resetValue(false);
noisechrof->resetValue(false);
noisechroc->resetValue(false);
@@ -1806,12 +1810,13 @@ bool Locallab::localComputed_()
sensiexclu->setValue(nextdatasp[79]);
struc->setValue(nextdatasp[80]);
warm->setValue(nextdatasp[81]);
+ noiselumdetail->setValue(nextdatasp[82]);
- double intermed = 0.01 * (double) nextdatasp[82];
+ double intermed = 0.01 * (double) nextdatasp[83];
hueref->setValue(intermed);
- chromaref->setValue(nextdatasp[83]);
- lumaref->setValue(nextdatasp[84]);
- sobelref->setValue(nextdatasp[85]);
+ chromaref->setValue(nextdatasp[84]);
+ lumaref->setValue(nextdatasp[85]);
+ sobelref->setValue(nextdatasp[86]);
int *s_datc;
s_datc = new int[70];
@@ -2095,7 +2100,7 @@ bool Locallab::localComputed_()
void Locallab::localChanged(int **datasp, std::string datastr, std::string ll_str, std::string lh_str, std::string cc_str, std::string hh_str, std::string sk_str, std::string ps_str, std::string ex_str, int sp, int maxdat)
{
- for (int i = 2; i < 86; i++) {
+ for (int i = 2; i < 87; i++) {
nextdatasp[i] = datasp[i][sp];
}
@@ -2181,6 +2186,7 @@ void Locallab::read(const ProcParams* pp, const ParamsEdited* pedited)
sensisha->setEditedState(pedited->locallab.sensisha ? Edited : UnEdited);
noiselumf->setEditedState(pedited->locallab.noiselumf ? Edited : UnEdited);
noiselumc->setEditedState(pedited->locallab.noiselumc ? Edited : UnEdited);
+ noiselumdetail->setEditedState(pedited->locallab.noiselumdetail ? Edited : UnEdited);
noisechrof->setEditedState(pedited->locallab.noisechrof ? Edited : UnEdited);
noisechroc->setEditedState(pedited->locallab.noisechroc ? Edited : UnEdited);
@@ -2390,6 +2396,7 @@ void Locallab::read(const ProcParams* pp, const ParamsEdited* pedited)
lastanbspot = pp->locallab.anbspot;
noiselumf->setValue(pp->locallab.noiselumf);
noiselumc->setValue(pp->locallab.noiselumc);
+ noiselumdetail->setValue(pp->locallab.noiselumdetail);
noisechrof->setValue(pp->locallab.noisechrof);
noisechroc->setValue(pp->locallab.noisechroc);
expcolor->setEnabled(pp->locallab.expcolor);
@@ -2815,6 +2822,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited)
pp->locallab.hlcomprthresh = (int)hlcomprthresh->getValue();
pp->locallab.shcompr = (int)shcompr->getValue();
pp->locallab.noiselumc = noiselumc->getIntValue();
+ pp->locallab.noiselumdetail = noiselumdetail->getIntValue();
pp->locallab.noiselumf = noiselumf->getIntValue();
pp->locallab.noisechrof = noisechrof->getIntValue();
pp->locallab.noisechroc = noisechroc->getIntValue();
@@ -2927,6 +2935,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited)
pedited->locallab.noiselumf = noiselumf->getEditedState();
pedited->locallab.noiselumc = noiselumc->getEditedState();
+ pedited->locallab.noiselumdetail = noiselumdetail->getEditedState();
pedited->locallab.noisechrof = noisechrof->getEditedState();
pedited->locallab.noisechroc = noisechroc->getEditedState();
pedited->locallab.sharradius = sharradius->getEditedState();
@@ -3450,7 +3459,7 @@ void Locallab::inversChanged()
} else {
sensi->show();
- warm->show();
+ warm->show();
llCurveEditorG->show();
curvactiv->show();
qualitycurveMethod->show();
@@ -3698,6 +3707,7 @@ void Locallab::setDefaults(const ProcParams * defParams, const ParamsEdited * pe
noiselumf->setDefault(defParams->locallab.noiselumf);
noiselumc->setDefault(defParams->locallab.noiselumc);
+ noiselumdetail->setDefault(defParams->locallab.noiselumdetail);
noisechrof->setDefault(defParams->locallab.noisechrof);
noisechroc->setDefault(defParams->locallab.noisechroc);
sharradius->setDefault(defParams->locallab.sharradius);
@@ -3772,6 +3782,7 @@ void Locallab::setDefaults(const ProcParams * defParams, const ParamsEdited * pe
noiselumf->setDefaultEditedState(pedited->locallab.noiselumf ? Edited : UnEdited);
noiselumc->setDefaultEditedState(pedited->locallab.noiselumc ? Edited : UnEdited);
+ noiselumdetail->setDefaultEditedState(pedited->locallab.noiselumdetail ? Edited : UnEdited);
noisechrof->setDefaultEditedState(pedited->locallab.noisechrof ? Edited : UnEdited);
noisechroc->setDefaultEditedState(pedited->locallab.noisechroc ? Edited : UnEdited);
sharradius->setDefaultEditedState(pedited->locallab.sharradius ? Edited : UnEdited);
@@ -3845,6 +3856,7 @@ void Locallab::setDefaults(const ProcParams * defParams, const ParamsEdited * pe
noiselumf->setDefaultEditedState(Irrelevant);
noiselumc->setDefaultEditedState(Irrelevant);
+ noiselumdetail->setDefaultEditedState(Irrelevant);
noisechrof->setDefaultEditedState(Irrelevant);
noisechroc->setDefaultEditedState(Irrelevant);
sharradius->setDefaultEditedState(Irrelevant);
@@ -4018,6 +4030,8 @@ void Locallab::adjusterChanged(Adjuster * a, double newval)
listener->panelChanged(Evlocallabnoiselumf, noiselumf->getTextValue());
} else if (a == noiselumc) {
listener->panelChanged(Evlocallabnoiselumc, noiselumc->getTextValue());
+ } else if (a == noiselumdetail) {
+ listener->panelChanged(Evlocallabnoiselumdetail, noiselumdetail->getTextValue());
} else if (a == noisechrof) {
listener->panelChanged(Evlocallabnoisechrof, noisechrof->getTextValue());
} else if (a == noisechroc) {
@@ -4204,6 +4218,7 @@ void Locallab::trimValues(rtengine::procparams::ProcParams * pp)
noiselumf->trimValue(pp->locallab.noiselumf);
noiselumc->trimValue(pp->locallab.noiselumc);
+ noiselumdetail->trimValue(pp->locallab.noiselumdetail);
noisechrof->trimValue(pp->locallab.noisechrof);
noisechroc->trimValue(pp->locallab.noisechroc);
sharradius->trimValue(pp->locallab.sharradius);
@@ -4288,6 +4303,7 @@ void Locallab::setBatchMode(bool batchMode)
noiselumf->showEditedCB();
noiselumc->showEditedCB();
+ noiselumdetail->showEditedCB();
noisechroc->showEditedCB();
noiselumf->showEditedCB();
sharradius->showEditedCB();
diff --git a/rtgui/locallab.h b/rtgui/locallab.h
index d9bbff9ed..3834a6e02 100644
--- a/rtgui/locallab.h
+++ b/rtgui/locallab.h
@@ -115,6 +115,8 @@ private:
Adjuster* const sensisha;
Adjuster* const noiselumf;
Adjuster* const noiselumc;
+ Adjuster* const noiselumdetail;
+
Adjuster* const noisechrof;
Adjuster* const noisechroc;
Adjuster* const hueref;
@@ -231,7 +233,7 @@ private:
- int nextdatasp[86];
+ int nextdatasp[87];
int nextlength;
std::string nextstr;
std::string nextstr2;
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index 7adcea9a3..384ab789e 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -347,6 +347,7 @@ void ParamsEdited::set(bool v)
locallab.noiselumf = v;
locallab.noiselumc = v;
+ locallab.noiselumdetail = v;
locallab.noisechrof = v;
locallab.noisechroc = v;
locallab.sharradius = v;
@@ -1010,6 +1011,7 @@ void ParamsEdited::initFrom(const std::vector&
locallab.noiselumf = locallab.noiselumf && p.locallab.noiselumf == other.locallab.noiselumf;
locallab.noiselumc = locallab.noiselumc && p.locallab.noiselumc == other.locallab.noiselumc;
+ locallab.noiselumdetail = locallab.noiselumdetail && p.locallab.noiselumdetail == other.locallab.noiselumdetail;
locallab.noisechrof = locallab.noisechrof && p.locallab.noisechrof == other.locallab.noisechrof;
locallab.noisechroc = locallab.noisechroc && p.locallab.noisechroc == other.locallab.noisechroc;
locallab.sharradius = locallab.sharradius && p.locallab.sharradius == other.locallab.sharradius;
@@ -1308,7 +1310,7 @@ void ParamsEdited::initFrom(const std::vector&
dirpyrequalizer.skinprotect = dirpyrequalizer.skinprotect && p.dirpyrequalizer.skinprotect == other.dirpyrequalizer.skinprotect;
// dirpyrequalizer.algo = dirpyrequalizer.algo && p.dirpyrequalizer.algo == other.dirpyrequalizer.algo;
dirpyrequalizer.hueskin = dirpyrequalizer.hueskin && p.dirpyrequalizer.hueskin == other.dirpyrequalizer.hueskin;
- hsvequalizer.enabled = hsvequalizer.enabled && p.hsvequalizer.enabled == other.hsvequalizer.enabled;
+ hsvequalizer.enabled = hsvequalizer.enabled && p.hsvequalizer.enabled == other.hsvequalizer.enabled;
hsvequalizer.hcurve = hsvequalizer.hcurve && p.hsvequalizer.hcurve == other.hsvequalizer.hcurve;
hsvequalizer.scurve = hsvequalizer.scurve && p.hsvequalizer.scurve == other.hsvequalizer.scurve;
hsvequalizer.vcurve = hsvequalizer.vcurve && p.hsvequalizer.vcurve == other.hsvequalizer.vcurve;
@@ -1896,7 +1898,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
if (wb.enabled) {
toEdit.wb.enabled = mods.wb.enabled;
}
-
+
if (wb.method) {
toEdit.wb.method = mods.wb.method;
}
@@ -2616,6 +2618,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
toEdit.locallab.noiselumc = mods.locallab.noiselumc;
}
+ if (locallab.noiselumdetail) {
+ toEdit.locallab.noiselumdetail = mods.locallab.noiselumdetail;
+ }
+
if (locallab.noisechrof) {
toEdit.locallab.noisechrof = mods.locallab.noisechrof;
}
@@ -2837,7 +2843,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
if (chmixer.enabled) {
toEdit.chmixer.enabled = mods.chmixer.enabled;
}
-
+
for (int i = 0; i < 3; i++) {
if (chmixer.red[i]) {
toEdit.chmixer.red[i] = dontforceSet && options.baBehav[ADDSET_CHMIXER] ? toEdit.chmixer.red[i] + mods.chmixer.red[i] : mods.chmixer.red[i];
@@ -3660,7 +3666,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
if (hsvequalizer.enabled) {
toEdit.hsvequalizer.enabled = mods.hsvequalizer.enabled;
}
-
+
if (hsvequalizer.hcurve) {
toEdit.hsvequalizer.hcurve = mods.hsvequalizer.hcurve;
}
diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h
index 84d02c1a0..15d45d470 100644
--- a/rtgui/paramsedited.h
+++ b/rtgui/paramsedited.h
@@ -466,6 +466,7 @@ public:
bool noiselumf;
bool noiselumc;
+ bool noiselumdetail;
bool noisechrof;
bool noisechroc;
bool sharradius;