From baf3f8c64add7cf20ff9573434830275e39cd109 Mon Sep 17 00:00:00 2001 From: Desmis Date: Fri, 11 Oct 2019 13:46:19 +0200 Subject: [PATCH] Checkbox Solve PDE Laplacian mask --- rtdata/languages/default | 2 + rtengine/dirpyr_equalizer.cc | 1 - rtengine/improcfun.h | 6 +- rtengine/iplocallab.cc | 657 ++++++++++++++++++----------------- rtengine/procevents.h | 1 + rtengine/procparams.cc | 4 + rtengine/procparams.h | 1 + rtengine/refreshmap.cc | 3 +- rtgui/controlspotpanel.cc | 48 +++ rtgui/controlspotpanel.h | 6 + rtgui/locallab.cc | 7 + rtgui/paramsedited.cc | 7 + rtgui/paramsedited.h | 1 + 13 files changed, 425 insertions(+), 319 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 5a504dd2b..8523de48b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1001,6 +1001,7 @@ HISTORY_MSG_760;Local - Color Laplacian mask HISTORY_MSG_761;Local - SH Laplacian mask HISTORY_MSG_762;Local - cbdl Laplacian mask HISTORY_MSG_763;Local - Blur Laplacian mask +HISTORY_MSG_764;Local - Solve PDE Laplacian mask HISTORY_MSG_CLAMPOOG;Clip out-of-gamut colors HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction HISTORY_MSG_COLORTONING_LABREGION_AB;CT - Color correction @@ -2100,6 +2101,7 @@ TP_LOCALLAB_CHROMASKCOL;Chroma mask TP_LOCALLAB_GAMMASKCOL;Gamma mask TP_LOCALLAB_SLOMASKCOL;Slope mask TP_LOCALLAB_LAPMASKCOL;Laplacian threshold mask +TP_LOCALLAB_LAPLACC;Mask Laplacian solve PDE (except Retinex) TP_LOCALLAB_CHRRT;Chroma TP_LOCALLAB_CIRCRADIUS;Spot size TP_LOCALLAB_COFR;Color & Light - Small defects : red eyes, dust diff --git a/rtengine/dirpyr_equalizer.cc b/rtengine/dirpyr_equalizer.cc index 666cf9b6e..3bf248164 100644 --- a/rtengine/dirpyr_equalizer.cc +++ b/rtengine/dirpyr_equalizer.cc @@ -569,7 +569,6 @@ void ImProcFunctions::cbdl_local_temp(float ** src, float ** loctemp, int srcwid } float multi[6]; - float scalefl[6]; for (int lv = 0; lv < 6; ++lv) { if (scalesloc[lv] < scaleprev) { diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 400b747bd..1153cd385 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -187,8 +187,12 @@ public: void idirpyr(LabImage* data_coarse, LabImage* data_fine, int level, LUTf &rangefn_L, LUTf & nrwt_l, LUTf & nrwt_ab, int pitch, int scale, const int luma, const int chroma/*, LUTf & Lcurve, LUTf & abcurve*/); //locallab + void maskcalccol(bool invmask, bool pde, int bfw, int bfh, int xstart, int ystart, int sk, int cx, int cy, LabImage* bufcolorig, LabImage* bufmaskblurcol, LabImage* originalmaskcol, LabImage* original, /*LabImage * transformed, */int inv, const struct local_params & lp, + const LocCCmaskCurve & locccmasCurve, bool & lcmasutili, const LocLLmaskCurve & locllmasCurve, bool & llmasutili, const LocHHmaskCurve & lochhmasCurve, bool &lhmasutili, bool multiThread, + bool enaMask, bool showmaske, bool deltaE, bool modmask, bool zero, bool modif, float chrom, float rad, float lap, float gamma, float slope, float blendm); + void normalize_mean_dt(float *data, const float *ref, size_t size, float mod); - void retinex_pde(float *datain, float * dataout, int bfw, int bfh, float thresh, float multy, float *dE, int show); + void retinex_pde(float *datain, float * dataout, int bfw, int bfh, float thresh, float multy, float *dE, int show, int dEenable, int normalize); void exposure_pde(float *dataor, float *datain, float * dataout, int bfw, int bfh, float thresh, float mod); void fftw_convol_blur(float *input, float *output, int bfw, int bfh, float radius, int fftkern, int algo); void fftw_convol_blur2(float **input2, float **output2, int bfw, int bfh, float radius, int fftkern, int algo); diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 4c5cd4f53..e29e77e5e 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -2526,8 +2526,317 @@ static float *discrete_laplacian_threshold(float * data_out, const float * data_ return data_out; } +static double *cos_table(size_t size) +{ + double *table = NULL; + double pi_size; + size_t i; -void maskcalccol(bool invmask, int bfw, int bfh, int xstart, int ystart, int sk, int cx, int cy, LabImage* bufcolorig, LabImage* bufmaskblurcol, LabImage* originalmaskcol, LabImage* original, /*LabImage * transformed, */int inv, const struct local_params & lp, + /* allocate the cosinus table */ + if (NULL == (table = (double *) malloc(sizeof(double) * size))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + /* + * fill the cosinus table, + * table[i] = cos(i Pi / n) for i in [0..n[ + */ + pi_size = rtengine::RT_PI / size; + + for (i = 0; i < size; i++) { + table[i] = cos(pi_size * i); + } + + return table; +} + + + +static float *rex_poisson_dct(float * data, size_t nx, size_t ny, double m) +{ + /* + * Copyright 2009-2011 IPOL Image Processing On Line http://www.ipol.im/ + * + + * @file retinex_pde_lib.c discrete Poisson equation + * @brief laplacian, DFT and Poisson routines + * + * @author Nicolas Limare + * some adaptations for Rawtherapee + */ + BENCHFUN + + double *cosx = NULL, *cosy = NULL; + size_t i; + double m2; + + /* + * get the cosinus tables + * cosx[i] = cos(i Pi / nx) for i in [0..nx[ + * cosy[i] = cos(i Pi / ny) for i in [0..ny[ + */ + cosx = cos_table(nx); + cosy = cos_table(ny); + + /* + * we will now multiply data[i, j] by + * m / (4 - 2 * cosx[i] - 2 * cosy[j])) + * and set data[0, 0] to 0 + */ + m2 = m / 2.; + /* + * handle the first value, data[0, 0] = 0 + * after that, by construction, we always have + * cosx[] + cosy[] != 2. + */ + data[0] = 0.; + + /* + * continue with all the array: + * i % nx is the position on the x axis (column number) + * i / nx is the position on the y axis (row number) + */ + for (i = 1; i < nx * ny; i++) { + data[i] *= m2 / (2. - cosx[i % nx] - cosy[i / nx]); + } + + free(cosx); + free(cosy); + + return data; +} + +static void mean_dt(const float * data, size_t size, double * mean_p, double * dt_p) +{ + double mean, dt; + const float *ptr_data; + size_t i; + + mean = 0.; + dt = 0.; + ptr_data = data; + + for (i = 0; i < size; i++) { + mean += *ptr_data; + dt += (*ptr_data) * (*ptr_data); + ptr_data++; + } + + mean /= (double) size; + dt /= (double) size; + dt -= (mean * mean); + dt = sqrt(dt); + + *mean_p = mean; + *dt_p = dt; + + return; +} + +void ImProcFunctions::normalize_mean_dt(float * data, const float * ref, size_t size, float mod) +{ + /* + * Copyright 2009-2011 IPOL Image Processing On Line http://www.ipol.im/ + * + + * @file retinex_pde_lib.c discrete Poisson equation + * @brief laplacian, DFT and Poisson routines + * + * @author Nicolas Limare + * adapted for Rawtherapee - jacques Desmis july 2019 + */ + + double mean_ref, mean_data, dt_ref, dt_data; + double a, b; + size_t i; + float *ptr_data; + float *ptr_dataold; + + if (NULL == data || NULL == ref) { + fprintf(stderr, "a pointer is NULL and should not be so\n"); + abort(); + } + + /* compute mean and variance of the two arrays */ + mean_dt(ref, size, &mean_ref, &dt_ref); + mean_dt(data, size, &mean_data, &dt_data); + + /* compute the normalization coefficients */ + a = dt_ref / dt_data; + b = mean_ref - a * mean_data; + + /* normalize the array */ + ptr_data = data; + ptr_dataold = data; + + for (i = 0; i < size; i++) { + *ptr_data = mod * (a * *ptr_data + b) + (1.f - mod) * *ptr_dataold;//normalize mean and stdv and balance PDE + ptr_data++; + } + + return; +} + +void ImProcFunctions::retinex_pde(float * datain, float * dataout, int bfw, int bfh, float thresh, float multy, float * dE, int show, int dEenable, int normalize) +{ + /* + * Copyright 2009-2011 IPOL Image Processing On Line http://www.ipol.im/ + * + + * @file retinex_pde_lib.c discrete Poisson equation + * @brief laplacian, DFT and Poisson routines + * + * @author Nicolas Limare + * adapted for Rawtherapee by Jacques Desmis 6-2019 + */ + + BENCHFUN +#ifdef _OPENMP + + if (multiThread) { + fftwf_init_threads(); + fftwf_plan_with_nthreads(omp_get_max_threads()); + } + +#endif + fftwf_plan dct_fw, dct_fw04, dct_bw; + float *data_fft, *data_fft04, *data_tmp, *data, *data_tmp04; + float *datashow = nullptr; + + if (show != 0) { + if (NULL == (datashow = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + } + + if (NULL == (data_tmp = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + if (NULL == (data_tmp04 = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + //first call to laplacian with plein strength + (void) discrete_laplacian_threshold(data_tmp, datain, bfw, bfh, thresh); + + if (NULL == (data_fft = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + if (show == 1) { + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + datashow[y * bfw + x] = data_tmp[y * bfw + x]; + } + } + } + + //second call to laplacian with 40% strength ==> reduce effect if we are far from ref (deltaE) + (void) discrete_laplacian_threshold(data_tmp04, datain, bfw, bfh, 0.4f * thresh); + + if (NULL == (data_fft04 = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + if (NULL == (data = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { + fprintf(stderr, "allocation error\n"); + abort(); + } + + //execute first + dct_fw = fftwf_plan_r2r_2d(bfh, bfw, data_tmp, data_fft, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); + fftwf_execute(dct_fw); + + //execute second + if (dEenable == 1) { + dct_fw04 = fftwf_plan_r2r_2d(bfh, bfw, data_tmp04, data_fft04, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); + fftwf_execute(dct_fw04); + } + + if (dEenable == 1) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int y = 0; y < bfh ; y++) {//mix two fftw Laplacian : plein if dE near ref + for (int x = 0; x < bfw; x++) { + float prov = pow(dE[y * bfw + x], 4.5f); + data_fft[y * bfw + x] = prov * data_fft[y * bfw + x] + (1.f - prov) * data_fft04[y * bfw + x]; + } + } + } + + if (show == 2) { + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + datashow[y * bfw + x] = data_fft[y * bfw + x]; + } + } + } + + fftwf_free(data_fft04); + fftwf_free(data_tmp); + fftwf_free(data_tmp04); + if (dEenable == 1) { + fftwf_destroy_plan(dct_fw04); + } + /* solve the Poisson PDE in Fourier space */ + /* 1. / (float) (bfw * bfh)) is the DCT normalisation term, see libfftw */ + (void) rex_poisson_dct(data_fft, bfw, bfh, 1. / (double)(bfw * bfh)); + + if (show == 3) { + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + datashow[y * bfw + x] = data_fft[y * bfw + x]; + } + } + } + + dct_bw = fftwf_plan_r2r_2d(bfh, bfw, data_fft, data, FFTW_REDFT01, FFTW_REDFT01, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); + fftwf_execute(dct_bw); + fftwf_destroy_plan(dct_fw); + fftwf_destroy_plan(dct_bw); + fftwf_free(data_fft); + fftwf_cleanup(); + + if (multiThread) { + fftwf_cleanup_threads(); + } + + if (show != 4 && normalize == 1) { + normalize_mean_dt(data, datain, bfw * bfh, 1.f); + } + + if (show == 0 || show == 4) { + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + dataout[y * bfw + x] = CLIPLOC(multy * data[y * bfw + x]); + } + } + } else if (show == 1 || show == 2 || show == 3) { + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + dataout[y * bfw + x] = CLIPLOC(multy * datashow[y * bfw + x]); + } + } + + fftwf_free(datashow); + } +} + +void ImProcFunctions::maskcalccol(bool invmask, bool pde, int bfw, int bfh, int xstart, int ystart, int sk, int cx, int cy, LabImage* bufcolorig, LabImage* bufmaskblurcol, LabImage* originalmaskcol, LabImage* original, /*LabImage * transformed, */int inv, const struct local_params & lp, const LocCCmaskCurve & locccmasCurve, bool & lcmasutili, const LocLLmaskCurve & locllmasCurve, bool & llmasutili, const LocHHmaskCurve & lochhmasCurve, bool &lhmasutili, bool multiThread, bool enaMask, bool showmaske, bool deltaE, bool modmask, bool zero, bool modif, float chrom, float rad, float lap, float gamma, float slope, float blendm) { @@ -2535,7 +2844,6 @@ void maskcalccol(bool invmask, int bfw, int bfh, int xstart, int ystart, int sk, array2D guid(bfw, bfh); float meanfab, fab; mean_fab(xstart, ystart, bfw, bfh, bufcolorig, original, fab, meanfab, chrom); -// meanfab = 5000.f; float kinv = 1.f; float kneg = 1.f; @@ -2637,7 +2945,7 @@ void maskcalccol(bool invmask, int bfw, int bfh, int xstart, int ystart, int sk, } } } - + if (rad > 0.f) { guidedFilter(guid, ble, ble, rad * 10.f / sk, 0.001, multiThread, 4); } @@ -2670,8 +2978,12 @@ void maskcalccol(bool invmask, int bfw, int bfh, int xstart, int ystart, int sk, datain[y * bfw + x] = bufmaskblurcol->L[y][x]; } } - - (void) discrete_laplacian_threshold(data_tmp, datain, bfw, bfh, 200.f * lap); + if(!pde) { + (void) discrete_laplacian_threshold(data_tmp, datain, bfw, bfh, 200.f * lap); + } else { + ImProcFunctions::retinex_pde(datain, data_tmp, bfw, bfh, 12.f * lap, 1.f, nullptr, 0, 0, 1); + } + #ifdef _OPENMP #pragma omp parallel for #endif @@ -4442,308 +4754,8 @@ const int fftw_size[] = {18144, 18000, 17920, 17836, 17820, 17640, 17600, 17550, int N_fftwsize = sizeof(fftw_size) / sizeof(fftw_size[0]); -static double *cos_table(size_t size) -{ - double *table = NULL; - double pi_size; - size_t i; - - /* allocate the cosinus table */ - if (NULL == (table = (double *) malloc(sizeof(double) * size))) { - fprintf(stderr, "allocation error\n"); - abort(); - } - - /* - * fill the cosinus table, - * table[i] = cos(i Pi / n) for i in [0..n[ - */ - pi_size = rtengine::RT_PI / size; - - for (i = 0; i < size; i++) { - table[i] = cos(pi_size * i); - } - - return table; -} - -static void mean_dt(const float * data, size_t size, double * mean_p, double * dt_p) -{ - double mean, dt; - const float *ptr_data; - size_t i; - - mean = 0.; - dt = 0.; - ptr_data = data; - - for (i = 0; i < size; i++) { - mean += *ptr_data; - dt += (*ptr_data) * (*ptr_data); - ptr_data++; - } - - mean /= (double) size; - dt /= (double) size; - dt -= (mean * mean); - dt = sqrt(dt); - - *mean_p = mean; - *dt_p = dt; - - return; -} - -void ImProcFunctions::normalize_mean_dt(float * data, const float * ref, size_t size, float mod) -{ - /* - * Copyright 2009-2011 IPOL Image Processing On Line http://www.ipol.im/ - * - - * @file retinex_pde_lib.c discrete Poisson equation - * @brief laplacian, DFT and Poisson routines - * - * @author Nicolas Limare - * adapted for Rawtherapee - jacques Desmis july 2019 - */ - - double mean_ref, mean_data, dt_ref, dt_data; - double a, b; - size_t i; - float *ptr_data; - float *ptr_dataold; - - if (NULL == data || NULL == ref) { - fprintf(stderr, "a pointer is NULL and should not be so\n"); - abort(); - } - - /* compute mean and variance of the two arrays */ - mean_dt(ref, size, &mean_ref, &dt_ref); - mean_dt(data, size, &mean_data, &dt_data); - - /* compute the normalization coefficients */ - a = dt_ref / dt_data; - b = mean_ref - a * mean_data; - - /* normalize the array */ - ptr_data = data; - ptr_dataold = data; - - for (i = 0; i < size; i++) { - *ptr_data = mod * (a * *ptr_data + b) + (1.f - mod) * *ptr_dataold;//normalize mean and stdv and balance PDE - ptr_data++; - } - - return; -} - -static float *rex_poisson_dct(float * data, size_t nx, size_t ny, double m) -{ - /* - * Copyright 2009-2011 IPOL Image Processing On Line http://www.ipol.im/ - * - - * @file retinex_pde_lib.c discrete Poisson equation - * @brief laplacian, DFT and Poisson routines - * - * @author Nicolas Limare - * some adaptations for Rawtherapee - */ - BENCHFUN - - double *cosx = NULL, *cosy = NULL; - size_t i; - double m2; - - /* - * get the cosinus tables - * cosx[i] = cos(i Pi / nx) for i in [0..nx[ - * cosy[i] = cos(i Pi / ny) for i in [0..ny[ - */ - cosx = cos_table(nx); - cosy = cos_table(ny); - - /* - * we will now multiply data[i, j] by - * m / (4 - 2 * cosx[i] - 2 * cosy[j])) - * and set data[0, 0] to 0 - */ - m2 = m / 2.; - /* - * handle the first value, data[0, 0] = 0 - * after that, by construction, we always have - * cosx[] + cosy[] != 2. - */ - data[0] = 0.; - - /* - * continue with all the array: - * i % nx is the position on the x axis (column number) - * i / nx is the position on the y axis (row number) - */ - for (i = 1; i < nx * ny; i++) { - data[i] *= m2 / (2. - cosx[i % nx] - cosy[i / nx]); - } - - free(cosx); - free(cosy); - - return data; -} -void ImProcFunctions::retinex_pde(float * datain, float * dataout, int bfw, int bfh, float thresh, float multy, float * dE, int show) -{ - /* - * Copyright 2009-2011 IPOL Image Processing On Line http://www.ipol.im/ - * - - * @file retinex_pde_lib.c discrete Poisson equation - * @brief laplacian, DFT and Poisson routines - * - * @author Nicolas Limare - * adapted for Rawtherapee by Jacques Desmis 6-2019 - */ - - BENCHFUN -#ifdef _OPENMP - - if (multiThread) { - fftwf_init_threads(); - fftwf_plan_with_nthreads(omp_get_max_threads()); - } - -#endif - fftwf_plan dct_fw, dct_fw04, dct_bw; - float *data_fft, *data_fft04, *data_tmp, *data, *data_tmp04; - float *datashow = nullptr; - - if (show != 0) { - if (NULL == (datashow = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { - fprintf(stderr, "allocation error\n"); - abort(); - } - } - - if (NULL == (data_tmp = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { - fprintf(stderr, "allocation error\n"); - abort(); - } - - if (NULL == (data_tmp04 = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { - fprintf(stderr, "allocation error\n"); - abort(); - } - - //first call to laplacian with plein strength - (void) discrete_laplacian_threshold(data_tmp, datain, bfw, bfh, thresh); - - if (NULL == (data_fft = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { - fprintf(stderr, "allocation error\n"); - abort(); - } - - if (show == 1) { - for (int y = 0; y < bfh ; y++) { - for (int x = 0; x < bfw; x++) { - datashow[y * bfw + x] = data_tmp[y * bfw + x]; - } - } - } - - //second call to laplacian with 40% strength ==> reduce effect if we are far from ref (deltaE) - (void) discrete_laplacian_threshold(data_tmp04, datain, bfw, bfh, 0.4f * thresh); - - if (NULL == (data_fft04 = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { - fprintf(stderr, "allocation error\n"); - abort(); - } - - if (NULL == (data = (float *) fftwf_malloc(sizeof(float) * bfw * bfh))) { - fprintf(stderr, "allocation error\n"); - abort(); - } - - //execute first - dct_fw = fftwf_plan_r2r_2d(bfh, bfw, data_tmp, data_fft, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); - fftwf_execute(dct_fw); - //execute second - dct_fw04 = fftwf_plan_r2r_2d(bfh, bfw, data_tmp04, data_fft04, FFTW_REDFT10, FFTW_REDFT10, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); - fftwf_execute(dct_fw04); - -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int y = 0; y < bfh ; y++) {//mix two fftw Laplacian : plein if dE near ref - for (int x = 0; x < bfw; x++) { - float prov = pow(dE[y * bfw + x], 4.5f); - data_fft[y * bfw + x] = prov * data_fft[y * bfw + x] + (1.f - prov) * data_fft04[y * bfw + x]; - } - } - - if (show == 2) { - for (int y = 0; y < bfh ; y++) { - for (int x = 0; x < bfw; x++) { - datashow[y * bfw + x] = data_fft[y * bfw + x]; - } - } - } - - fftwf_free(data_fft04); - fftwf_free(data_tmp); - fftwf_free(data_tmp04); - fftwf_destroy_plan(dct_fw04); - - /* solve the Poisson PDE in Fourier space */ - /* 1. / (float) (bfw * bfh)) is the DCT normalisation term, see libfftw */ - (void) rex_poisson_dct(data_fft, bfw, bfh, 1. / (double)(bfw * bfh)); - - if (show == 3) { - for (int y = 0; y < bfh ; y++) { - for (int x = 0; x < bfw; x++) { - datashow[y * bfw + x] = data_fft[y * bfw + x]; - } - } - } - - dct_bw = fftwf_plan_r2r_2d(bfh, bfw, data_fft, data, FFTW_REDFT01, FFTW_REDFT01, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); - fftwf_execute(dct_bw); - fftwf_destroy_plan(dct_fw); - fftwf_destroy_plan(dct_bw); - fftwf_free(data_fft); - fftwf_cleanup(); - - if (multiThread) { - fftwf_cleanup_threads(); - } - - if (show != 4) { - normalize_mean_dt(data, datain, bfw * bfh, 1.f); - } - - if (show == 0 || show == 4) { - -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int y = 0; y < bfh ; y++) { - for (int x = 0; x < bfw; x++) { - dataout[y * bfw + x] = CLIPLOC(multy * data[y * bfw + x]); - } - } - } else if (show == 1 || show == 2 || show == 3) { - for (int y = 0; y < bfh ; y++) { - for (int x = 0; x < bfw; x++) { - dataout[y * bfw + x] = CLIPLOC(multy * datashow[y * bfw + x]); - } - } - - fftwf_free(datashow); - } -} @@ -6895,6 +6907,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o float lap = params->locallab.spots.at(sp).lapmaskbl; + float pde = params->locallab.spots.at(sp).laplac; if (lap > 0.f && (lp.enablMask || lp.showmaskblmet == 3)) { float *datain = new float[GH * GW]; @@ -6910,7 +6923,11 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o } } - (void) discrete_laplacian_threshold(data_tmp, datain, GW, GH, 200.f * lap); + if(!pde) { + (void) discrete_laplacian_threshold(data_tmp, datain, GW, GH, 200.f * lap); + } else { + ImProcFunctions::retinex_pde(datain, data_tmp, GW, GH, 12.f * lap, 1.f, nullptr, 0, 0, 1); + } #ifdef _OPENMP #pragma omp parallel for @@ -7377,8 +7394,9 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o float slope = lp.slomacb; float blendm = lp.blendmacb; float lap = params->locallab.spots.at(sp).lapmaskcb; + float pde = params->locallab.spots.at(sp).laplac; - maskcalccol(false, bfw, bfh, xstart, ystart, sk, cx, cy, loctemp.get(), bufmaskorigcb.get(), originalmaskcb.get(), original, inv, lp, + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, loctemp.get(), bufmaskorigcb.get(), originalmaskcb.get(), original, inv, lp, locccmascbCurve, lcmascbutili, locllmascbCurve, llmascbutili, lochhmascbCurve, lhmascbutili, multiThread, enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm); @@ -7650,9 +7668,10 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o float slope = lp.slomatm; float blendm = lp.blendmatm; float lap = params->locallab.spots.at(sp).lapmasktm; + float pde = params->locallab.spots.at(sp).laplac; if (!params->locallab.spots.at(sp).enatmMaskaft) { - maskcalccol(false, bfw, bfh, xstart, ystart, sk, cx, cy, bufgbm.get(), bufmaskorigtm.get(), originalmasktm.get(), original, inv, lp, + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufgbm.get(), bufmaskorigtm.get(), originalmasktm.get(), original, inv, lp, locccmastmCurve, lcmastmutili, locllmastmCurve, llmastmutili, lochhmastmCurve, lhmastmutili, multiThread, enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm); @@ -7674,7 +7693,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o if (enatmMasktmap) { //calculate new values for original, originalmasktm, bufmaskorigtm...in function of tmp1 - maskcalccol(false, bfw, bfh, xstart, ystart, sk, cx, cy, tmp1.get(), bufmaskorigtm.get(), originalmasktm.get(), original, inv, lp, + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, tmp1.get(), bufmaskorigtm.get(), originalmasktm.get(), original, inv, lp, locccmastmCurve, lcmastmutili, locllmastmCurve, llmastmutili, lochhmastmCurve, lhmastmutili, multiThread, enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm); @@ -7839,8 +7858,9 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o float slope = lp.slomaSH; float blendm = lp.blendmaSH; float lap = params->locallab.spots.at(sp).lapmaskSH; + float pde = params->locallab.spots.at(sp).laplac; - maskcalccol(false, bfw, bfh, xstart, ystart, sk, cx, cy, bufexporig.get(), bufmaskorigSH.get(), originalmaskSH.get(), original, inv, lp, + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufexporig.get(), bufmaskorigSH.get(), originalmaskSH.get(), original, inv, lp, locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili, multiThread, enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm); @@ -7933,8 +7953,9 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o float slope = lp.slomaSH; float blendm = lp.blendmaSH; float lap = params->locallab.spots.at(sp).lapmaskSH; + float pde = params->locallab.spots.at(sp).laplac; - maskcalccol(false, GW, GH, 0, 0, sk, cx, cy, bufcolorig.get(), bufmaskblurcol.get(), originalmaskSH.get(), original, inv, lp, + maskcalccol(false, pde, GW, GH, 0, 0, sk, cx, cy, bufcolorig.get(), bufmaskblurcol.get(), originalmaskSH.get(), original, inv, lp, locccmasSHCurve, lcmasSHutili, locllmasSHCurve, llmasSHutili, lochhmasSHCurve, lhmasSHutili, multiThread, enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm); @@ -8099,7 +8120,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o } } - ImProcFunctions::retinex_pde(datain, dataout, bfwr, bfhr, 8.f * lp.strng, 1.f, dE, lp.showmasksoftmet); + ImProcFunctions::retinex_pde(datain, dataout, bfwr, bfhr, 8.f * lp.strng, 1.f, dE, lp.showmasksoftmet, 1, 1); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif @@ -10032,8 +10053,9 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o float slope = lp.slomaexp; float blendm = lp.blendmaexp; float lap = params->locallab.spots.at(sp).lapmaskexp; + float pde = params->locallab.spots.at(sp).laplac; - maskcalccol(false, bfw, bfh, xstart, ystart, sk, cx, cy, bufexporig.get(), bufmaskblurexp.get(), originalmaskexp.get(), original, inv, lp, + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufexporig.get(), bufmaskblurexp.get(), originalmaskexp.get(), original, inv, lp, locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili, multiThread, enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm); @@ -10296,8 +10318,9 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o float slope = lp.slomaexp; float blendm = lp.blendmaexp; float lap = params->locallab.spots.at(sp).lapmaskexp; + float pde = params->locallab.spots.at(sp).laplac; - maskcalccol(false, GW, GH, 0, 0, sk, cx, cy, bufexporig.get(), bufmaskblurexp.get(), originalmaskexp.get(), original, inv, lp, + maskcalccol(false, pde, GW, GH, 0, 0, sk, cx, cy, bufexporig.get(), bufmaskblurexp.get(), originalmaskexp.get(), original, inv, lp, locccmasexpCurve, lcmasexputili, locllmasexpCurve, llmasexputili, lochhmasexpCurve, lhmasexputili, multiThread, enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm); @@ -10535,8 +10558,9 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o float slope = lp.slomacol; float blendm = lp.blendmacol; float lap = params->locallab.spots.at(sp).lapmaskcol; + float pde = params->locallab.spots.at(sp).laplac; - maskcalccol(false, bfw, bfh, xstart, ystart, sk, cx, cy, bufcolorig.get(), bufmaskblurcol.get(), originalmaskcol.get(), original, inv, lp, + maskcalccol(false, pde, bfw, bfh, xstart, ystart, sk, cx, cy, bufcolorig.get(), bufmaskblurcol.get(), originalmaskcol.get(), original, inv, lp, locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili, multiThread, enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm); @@ -10737,8 +10761,9 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o float slope = lp.slomacol; float blendm = lp.blendmacol; float lap = params->locallab.spots.at(sp).lapmaskcol; + float pde = params->locallab.spots.at(sp).laplac; - maskcalccol(false, GW, GH, 0, 0, sk, cx, cy, bufcolorig.get(), bufmaskblurcol.get(), originalmaskcol.get(), original, inv, lp, + maskcalccol(false, pde, GW, GH, 0, 0, sk, cx, cy, bufcolorig.get(), bufmaskblurcol.get(), originalmaskcol.get(), original, inv, lp, locccmasCurve, lcmasutili, locllmasCurve, llmasutili, lochhmasCurve, lhmasutili, multiThread, enaMask, showmaske, deltaE, modmask, zero, modif, chrom, rad, lap, gamma, slope, blendm); diff --git a/rtengine/procevents.h b/rtengine/procevents.h index ab0684f51..cc9dc8701 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -790,6 +790,7 @@ enum ProcEventCode { EvlocallablapmaskSH = 760, Evlocallablapmaskcb = 761, Evlocallablapmaskbl = 762, + Evlocallablaplac = 763, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index de2953450..eca46aee4 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2432,6 +2432,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : transitweak(1.0), transitgrad(0.0), avoid(false), + laplac(false), // Color & Light expcolor(false), curvactiv(false), @@ -2708,6 +2709,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && transitweak == other.transitweak && transitgrad == other.transitgrad && avoid == other.avoid + && laplac == other.laplac // Color & Light && expcolor == other.expcolor && curvactiv == other.curvactiv @@ -3970,6 +3972,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->locallab.spots.at(i).transitweak, "Locallab", "Transitweak_" + std::to_string(i), spot.transitweak, keyFile); saveToKeyfile(!pedited || pedited->locallab.spots.at(i).transitgrad, "Locallab", "Transitgrad_" + std::to_string(i), spot.transitgrad, keyFile); saveToKeyfile(!pedited || pedited->locallab.spots.at(i).avoid, "Locallab", "Avoid_" + std::to_string(i), spot.avoid, keyFile); + saveToKeyfile(!pedited || pedited->locallab.spots.at(i).laplac, "Locallab", "Laplac_" + std::to_string(i), spot.laplac, keyFile); // Color & Light saveToKeyfile(!pedited || pedited->locallab.spots.at(i).expcolor, "Locallab", "Expcolor_" + std::to_string(i), spot.expcolor, keyFile); saveToKeyfile(!pedited || pedited->locallab.spots.at(i).curvactiv, "Locallab", "Curvactiv_" + std::to_string(i), spot.curvactiv, keyFile); @@ -5347,6 +5350,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "Transitweak_" + std::to_string(i), pedited, spot.transitweak, spotEdited.transitweak); assignFromKeyfile(keyFile, "Locallab", "Transitgrad_" + std::to_string(i), pedited, spot.transitgrad, spotEdited.transitgrad); assignFromKeyfile(keyFile, "Locallab", "Avoid_" + std::to_string(i), pedited, spot.avoid, spotEdited.avoid); + assignFromKeyfile(keyFile, "Locallab", "Laplac_" + std::to_string(i), pedited, spot.laplac, spotEdited.laplac); // Color & Light assignFromKeyfile(keyFile, "Locallab", "Expcolor_" + std::to_string(i), pedited, spot.expcolor, spotEdited.expcolor); assignFromKeyfile(keyFile, "Locallab", "Curvactiv_" + std::to_string(i), pedited, spot.curvactiv, spotEdited.curvactiv); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 3c72be194..71c3aeda9 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -979,6 +979,7 @@ struct LocallabParams { double transitweak; double transitgrad; bool avoid; + bool laplac; // Color & Light bool expcolor; bool curvactiv; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index df1b9fba8..8b49823c4 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -789,7 +789,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { LUMINANCECURVE, //Evlocallablapmaskcol LUMINANCECURVE, //EvlocallablapmaskSH LUMINANCECURVE, //Evlocallablapmaskcb - LUMINANCECURVE //Evlocallablapmaskbl + LUMINANCECURVE, //Evlocallablapmaskbl + LUMINANCECURVE //Evlocallablaplac }; namespace rtengine diff --git a/rtgui/controlspotpanel.cc b/rtgui/controlspotpanel.cc index 5d739a0e1..25ad9ac55 100644 --- a/rtgui/controlspotpanel.cc +++ b/rtgui/controlspotpanel.cc @@ -70,6 +70,7 @@ ControlSpotPanel::ControlSpotPanel(): transitgrad_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_TRANSITGRAD"), -1.0, 1.0, 0.01, 0.0))), avoid_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_AVOID")))), + laplac_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_LAPLACC")))), lastObject_(-1), nbSpotChanged_(false), @@ -271,6 +272,9 @@ ControlSpotPanel::ControlSpotPanel(): avoidConn_ = avoid_->signal_toggled().connect( sigc::mem_fun(*this, &ControlSpotPanel::avoidChanged)); pack_start(*avoid_); + laplacConn_ = laplac_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::laplacChanged)); + pack_start(*laplac_); show_all(); @@ -575,6 +579,7 @@ void ControlSpotPanel::load_ControlSpot_param() transitweak_->setValue((double)row[spots_.transitweak]); transitgrad_->setValue((double)row[spots_.transitgrad]); avoid_->set_active(row[spots_.avoid]); + laplac_->set_active(row[spots_.laplac]); } void ControlSpotPanel::controlspotChanged() @@ -1040,6 +1045,41 @@ void ControlSpotPanel::avoidChanged() } } +void ControlSpotPanel::laplacChanged() +{ + // printf("laplacChanged\n"); + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + if (multiImage) { + if (laplac_->get_inconsistent()) { + laplac_->set_inconsistent(false); + laplacConn_.block(true); + laplac_->set_active(false); + laplacConn_.block(false); + } + } + + row[spots_.laplac] = laplac_->get_active(); + + // Raise event + if (listener) { + if (laplac_->get_active()) { + listener->panelChanged(Evlocallablaplac, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(Evlocallablaplac, M("GENERAL_DISABLED")); + } + } +} + void ControlSpotPanel::disableParamlistener(bool cond) { // printf("disableParamlistener: %d\n", cond); @@ -1071,6 +1111,7 @@ void ControlSpotPanel::disableParamlistener(bool cond) transitweak_->block(cond); transitgrad_->block(cond); avoidConn_.block(cond); + laplacConn_.block(cond); } void ControlSpotPanel::setParamEditable(bool cond) @@ -1098,6 +1139,7 @@ void ControlSpotPanel::setParamEditable(bool cond) transitweak_->set_sensitive(cond); transitgrad_->set_sensitive(cond); avoid_->set_sensitive(cond); + laplac_->set_sensitive(cond); } void ControlSpotPanel::addControlSpotCurve(Gtk::TreeModel::Row& row) @@ -1731,6 +1773,7 @@ ControlSpotPanel::SpotRow* ControlSpotPanel::getSpot(const int id) r->transitweak = row[spots_.transitweak]; r->transitgrad = row[spots_.transitgrad]; r->avoid = row[spots_.avoid]; + r->laplac = row[spots_.laplac]; return r; } @@ -1857,6 +1900,7 @@ void ControlSpotPanel::addControlSpot(SpotRow* newSpot) row[spots_.transitweak] = newSpot->transitweak; row[spots_.transitgrad] = newSpot->transitgrad; row[spots_.avoid] = newSpot->avoid; + row[spots_.laplac] = newSpot->laplac; updateParamVisibility(); disableParamlistener(false); @@ -1902,6 +1946,7 @@ int ControlSpotPanel::updateControlSpot(SpotRow* spot) row[spots_.transitweak] = spot->transitweak; row[spots_.transitgrad] = spot->transitgrad; row[spots_.avoid] = spot->avoid; + row[spots_.laplac] = spot->laplac; updateControlSpotCurve(row); updateParamVisibility(); @@ -1993,6 +2038,7 @@ ControlSpotPanel::SpotEdited* ControlSpotPanel::getEditedStates() se->transitweak = transitweak_->getEditedState(); se->transitgrad = transitgrad_->getEditedState(); se->avoid = !avoid_->get_inconsistent(); + se->laplac = !laplac_->get_inconsistent(); return se; } @@ -2062,6 +2108,7 @@ void ControlSpotPanel::setEditedStates(SpotEdited* se) transitweak_->setEditedState(se->transitweak ? Edited : UnEdited); transitgrad_->setEditedState(se->transitgrad ? Edited : UnEdited); avoid_->set_inconsistent(multiImage && !se->avoid); + laplac_->set_inconsistent(multiImage && !se->laplac); // Update Control Spot GUI according to widgets edited states updateParamVisibility(); @@ -2212,6 +2259,7 @@ ControlSpotPanel::ControlSpots::ControlSpots() add(transitweak); add(transitgrad); add(avoid); + add(laplac); } //----------------------------------------------------------------------------- diff --git a/rtgui/controlspotpanel.h b/rtgui/controlspotpanel.h index 9d542c75b..5a361b453 100644 --- a/rtgui/controlspotpanel.h +++ b/rtgui/controlspotpanel.h @@ -66,6 +66,7 @@ public: double transitweak; double transitgrad; bool avoid; + bool laplac; }; /** @@ -97,6 +98,7 @@ public: bool transitweak; bool transitgrad; bool avoid; + bool laplac; }; /** @@ -263,6 +265,7 @@ private: void adjusterChanged(ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight); void adjusterChanged2(ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR); void avoidChanged(); + void laplacChanged(); void disableParamlistener(bool cond); @@ -310,6 +313,7 @@ private: Gtk::TreeModelColumn transitweak; Gtk::TreeModelColumn transitgrad; Gtk::TreeModelColumn avoid; + Gtk::TreeModelColumn laplac; }; class RenameDialog: @@ -376,6 +380,8 @@ private: Gtk::CheckButton* const avoid_; sigc::connection avoidConn_; + Gtk::CheckButton* const laplac_; + sigc::connection laplacConn_; // Internal variables int lastObject_; diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index 6c0894503..100a0b391 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -2595,6 +2595,7 @@ void Locallab::read(const ProcParams* pp, const ParamsEdited* pedited) r->transitweak = pp->locallab.spots.at(i).transitweak; r->transitgrad = pp->locallab.spots.at(i).transitgrad; r->avoid = pp->locallab.spots.at(i).avoid; + r->laplac = pp->locallab.spots.at(i).laplac; expsettings->addControlSpot(r); } @@ -2722,6 +2723,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited) r->transitweak = newSpot->transitweak; r->transitgrad = newSpot->transitgrad; r->avoid = newSpot->avoid; + r->laplac = newSpot->laplac; expsettings->addControlSpot(r); // ProcParams update @@ -2938,6 +2940,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited) r->transitweak = newSpot->transitweak; r->transitgrad = newSpot->transitgrad; r->avoid = newSpot->avoid; + r->laplac = newSpot->laplac; expsettings->addControlSpot(r); // ProcParams update @@ -3052,6 +3055,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited) pp->locallab.spots.at(pp->locallab.selspot).transitweak = r->transitweak; pp->locallab.spots.at(pp->locallab.selspot).transitgrad = r->transitgrad; pp->locallab.spots.at(pp->locallab.selspot).avoid = r->avoid; + pp->locallab.spots.at(pp->locallab.selspot).laplac = r->laplac; // Color & Light pp->locallab.spots.at(pp->locallab.selspot).expcolor = expcolor->getEnabled(); pp->locallab.spots.at(pp->locallab.selspot).curvactiv = curvactiv->get_active(); @@ -3412,6 +3416,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited) pe->locallab.spots.at(pp->locallab.selspot).transitgrad = pe->locallab.spots.at(pp->locallab.selspot).transitgrad || se->transitgrad; pe->locallab.spots.at(pp->locallab.selspot).balan = pe->locallab.spots.at(pp->locallab.selspot).balan || se->balan; pe->locallab.spots.at(pp->locallab.selspot).avoid = pe->locallab.spots.at(pp->locallab.selspot).avoid || se->avoid; + pe->locallab.spots.at(pp->locallab.selspot).laplac = pe->locallab.spots.at(pp->locallab.selspot).laplac || se->laplac; // Color & Light pe->locallab.spots.at(pp->locallab.selspot).expcolor = pe->locallab.spots.at(pp->locallab.selspot).expcolor || !expcolor->get_inconsistent(); pe->locallab.spots.at(pp->locallab.selspot).curvactiv = pe->locallab.spots.at(pp->locallab.selspot).curvactiv || !curvactiv->get_inconsistent(); @@ -3693,6 +3698,7 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited) pedited->locallab.spots.at(pp->locallab.selspot).transitweak = pedited->locallab.spots.at(pp->locallab.selspot).transitweak || se->transitweak; pedited->locallab.spots.at(pp->locallab.selspot).transitgrad = pedited->locallab.spots.at(pp->locallab.selspot).transitgrad || se->transitgrad; pedited->locallab.spots.at(pp->locallab.selspot).avoid = pedited->locallab.spots.at(pp->locallab.selspot).avoid || se->avoid; + pedited->locallab.spots.at(pp->locallab.selspot).laplac = pedited->locallab.spots.at(pp->locallab.selspot).laplac || se->laplac; // Color & Light pedited->locallab.spots.at(pp->locallab.selspot).expcolor = pedited->locallab.spots.at(pp->locallab.selspot).expcolor || !expcolor->get_inconsistent(); pedited->locallab.spots.at(pp->locallab.selspot).curvactiv = pedited->locallab.spots.at(pp->locallab.selspot).curvactiv || !curvactiv->get_inconsistent(); @@ -8029,6 +8035,7 @@ void Locallab::updateLocallabGUI(const rtengine::procparams::ProcParams* pp, con se->transitweak = spotState->transitweak; se->transitgrad = spotState->transitgrad; se->avoid = spotState->avoid; + se->laplac = spotState->laplac; expsettings->setEditedStates(se); // Color & Light diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 8017b55b0..9205c6322 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -973,6 +973,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).transitweak = locallab.spots.at(j).transitweak && pSpot.transitweak == otherSpot.transitweak; locallab.spots.at(j).transitgrad = locallab.spots.at(j).transitgrad && pSpot.transitgrad == otherSpot.transitgrad; locallab.spots.at(j).avoid = locallab.spots.at(j).avoid && pSpot.avoid == otherSpot.avoid; + locallab.spots.at(j).laplac = locallab.spots.at(j).laplac && pSpot.laplac == otherSpot.laplac; // Color & Light locallab.spots.at(j).expcolor = locallab.spots.at(j).expcolor && pSpot.expcolor == otherSpot.expcolor; locallab.spots.at(j).curvactiv = locallab.spots.at(j).curvactiv && pSpot.curvactiv == otherSpot.curvactiv; @@ -2778,6 +2779,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).avoid = mods.locallab.spots.at(i).avoid; } + if (locallab.spots.at(i).laplac) { + toEdit.locallab.spots.at(i).laplac = mods.locallab.spots.at(i).laplac; + } + // Color & Light if (locallab.spots.at(i).expcolor) { toEdit.locallab.spots.at(i).expcolor = mods.locallab.spots.at(i).expcolor; @@ -4711,6 +4716,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : transitweak(v), transitgrad(v), avoid(v), + laplac(v), // Color & Light expcolor(v), curvactiv(v), @@ -4984,6 +4990,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) transitweak = v; transitgrad = v; avoid = v; + laplac = v; // Color & Light expcolor = v; curvactiv = v; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 6b3a85007..7a0052f95 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -391,6 +391,7 @@ public: bool transitweak; bool transitgrad; bool avoid; + bool laplac; // Color & Light bool expcolor; bool curvactiv;