From 5a30c7e147cbb8bacaa6382dbb2ecc4fa740f642 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 17 Oct 2018 00:17:22 +0200 Subject: [PATCH 01/14] Calculate dual demosaic contrast threshold and log it in console output but don't use it, #4866 --- rtengine/dual_demosaic_RT.cc | 2 +- rtengine/rt_algo.cc | 66 ++++++++++++++++++++++++++++++++++-- rtengine/rt_algo.h | 2 +- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 6e92fd1e2..5425e9d01 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -118,7 +118,7 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi } // calculate contrast based blend factors to use vng4 in regions with low contrast JaggedArray blend(winw, winh); - buildBlendMask(L, blend, winw, winh, contrast / 100.f); + buildBlendMask(L, blend, winw, winh, contrast / 100.f, 1.f, true); // the following is split into 3 loops intentionally to avoid cache conflicts on CPUs with only 4-way cache #pragma omp parallel for diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index c56a72a2c..0e4c1567d 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef _OPENMP #include #endif @@ -32,7 +33,8 @@ #include "rt_algo.h" #include "rt_math.h" #include "sleef.c" - +#include "jaggedarray.h" +#include "StopWatch.h" namespace { float calcBlendFactor(float val, float threshold) { // sigmoid function @@ -190,7 +192,7 @@ void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& maxOut += minVal; } -void buildBlendMask(float** luminance, float **blend, int W, int H, float contrastThreshold, float amount) { +void buildBlendMask(float** luminance, float **blend, int W, int H, float contrastThreshold, float amount, bool autoContrast) { constexpr float scale = 0.0625f / 327.68f; @@ -201,6 +203,64 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float contra } } } else { + if (autoContrast) { + StopWatch StopC("calculate dual demosaic auto contrast threshold"); + constexpr int tilesize = 80; + const int numTilesW = W / tilesize; + const int numTilesH = H / tilesize; + std::vector>> variances(numTilesH, std::vector>(numTilesW)); + + #pragma omp parallel for + for (int i = 0; i < numTilesH; ++i) { + int tileY = i * tilesize; + for (int j = 0; j < numTilesW; ++j) { + int tileX = j * tilesize; + double avg = 0.; + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; ++x) { + avg += luminance[y][x]; + } + } + avg /= SQR(tilesize); + double var = 0.0; + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; ++x) { + var += SQR(luminance[y][x] - avg); + } + } + var /= (SQR(tilesize) * avg); + variances[i][j].first = var; + variances[i][j].second = avg; + // std::cout << "y : " << tileY << " ; x : " << tileX << " ; avg : " << avg << " ; var : " << var << std::endl; + } + } + float minvar = RT_INFINITY_F; + int minY = 0, minX = 0; + for (int i = 0; i < numTilesH; ++i) { + for (int j = 0; j < numTilesW; ++j) { + if (variances[i][j].first < minvar && variances[i][j].second > 2000.f && variances[i][j].second < 20000.f) { + minvar = variances[i][j].first; + minY = tilesize * i; + minX = tilesize * j; + } + } + } +// std::cout << "minY : " << minY << std::endl; +// std::cout << "minX : " << minX << std::endl; +// std::cout << "minvar : " << minvar << std::endl; + + JaggedArray Lum(tilesize, tilesize); + JaggedArray Blend(tilesize, tilesize); + for (int i = 0; i < tilesize; ++i) { + for (int j = 0; j < tilesize; ++j) { + Lum[i][j] = luminance[i + minY][j + minX]; + } + } +// std::cout << "contrastThreshold : " << contrastThreshold << std::endl; + + calcContrastThreshold(Lum, Blend, tilesize, tilesize); + } + #ifdef _OPENMP #pragma omp parallel #endif @@ -318,6 +378,8 @@ int calcContrastThreshold(float** luminance, float **blend, int W, int H) { break; } } + std::cout << "dual demosaic auto contrast threshold : " << c << std::endl; + return c; } } diff --git a/rtengine/rt_algo.h b/rtengine/rt_algo.h index e20713b8f..3a91c327b 100644 --- a/rtengine/rt_algo.h +++ b/rtengine/rt_algo.h @@ -24,6 +24,6 @@ namespace rtengine { void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& minOut, float maxPrct, float& maxOut, bool multiThread = true); -void buildBlendMask(float** luminance, float **blend, int W, int H, float contrastThreshold, float amount = 1.f); +void buildBlendMask(float** luminance, float **blend, int W, int H, float contrastThreshold, float amount = 1.f, bool autoContrast = false); int calcContrastThreshold(float** luminance, float **blend, int W, int H); } From bb0743898b35b55eee060bc6fe6bd1bc54cd7320 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 17 Oct 2018 13:36:41 +0200 Subject: [PATCH 02/14] SSE code for auto calculation of dual demosaic contrast threshold, #4866 --- rtengine/rt_algo.cc | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index 0e4c1567d..49c972a47 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -194,8 +194,6 @@ void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& void buildBlendMask(float** luminance, float **blend, int W, int H, float contrastThreshold, float amount, bool autoContrast) { - constexpr float scale = 0.0625f / 327.68f; - if(contrastThreshold == 0.f) { for(int j = 0; j < H; ++j) { for(int i = 0; i < W; ++i) { @@ -203,6 +201,7 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float contra } } } else { + constexpr float scale = 0.0625f / 327.68f; if (autoContrast) { StopWatch StopC("calculate dual demosaic auto contrast threshold"); constexpr int tilesize = 80; @@ -215,25 +214,46 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float contra int tileY = i * tilesize; for (int j = 0; j < numTilesW; ++j) { int tileX = j * tilesize; - double avg = 0.; +#ifdef __SSE2__ + vfloat avgv = ZEROV; + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; x += 4) { + avgv += LVFU(luminance[y][x]); + } + } + float avg = vhadd(avgv); +#else + float avg = 0.; for (int y = tileY; y < tileY + tilesize; ++y) { for (int x = tileX; x < tileX + tilesize; ++x) { avg += luminance[y][x]; } } +#endif avg /= SQR(tilesize); - double var = 0.0; +#ifdef __SSE2__ + vfloat varv = ZEROV; + avgv = F2V(avg); + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; x +=4) { + varv += SQRV(LVFU(luminance[y][x]) - avgv); + } + } + float var = vhadd(varv); +#else + float var = 0.0; for (int y = tileY; y < tileY + tilesize; ++y) { for (int x = tileX; x < tileX + tilesize; ++x) { var += SQR(luminance[y][x] - avg); } } +#endif var /= (SQR(tilesize) * avg); variances[i][j].first = var; variances[i][j].second = avg; - // std::cout << "y : " << tileY << " ; x : " << tileX << " ; avg : " << avg << " ; var : " << var << std::endl; } } + float minvar = RT_INFINITY_F; int minY = 0, minX = 0; for (int i = 0; i < numTilesH; ++i) { @@ -256,7 +276,6 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float contra Lum[i][j] = luminance[i + minY][j + minX]; } } -// std::cout << "contrastThreshold : " << contrastThreshold << std::endl; calcContrastThreshold(Lum, Blend, tilesize, tilesize); } From 0da47b0da37610c4728d3835496a788d41475132 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 18 Oct 2018 22:09:35 +0200 Subject: [PATCH 03/14] 2-pass dual-demosaic-contrast-threshold detection if 1-pass does not find a flat area, #4866 --- rtengine/dual_demosaic_RT.cc | 20 +----- rtengine/rawimagesource.cc | 4 +- rtengine/rawimagesource.h | 2 +- rtengine/rt_algo.cc | 125 ++++++++++++++++++----------------- 4 files changed, 70 insertions(+), 81 deletions(-) diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 5425e9d01..862516416 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -36,7 +36,7 @@ using namespace std; namespace rtengine { -void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast, int autoX, int autoY) +void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast) { BENCHFUN @@ -91,24 +91,6 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi { 0.019334, 0.119193, 0.950227 } }; - if (autoContrast && autoX >= 0 && autoY >= 0) { - constexpr int rectSize = 40; - const int autoWidth = min(rectSize, winw - autoX); - const int autoHeight = min(rectSize, winh - autoY); - if (std::min(autoWidth, autoHeight) > 20) { - array2D autoL(autoWidth, autoHeight); - for(int i = 0; i < autoHeight; ++i) { - Color::RGB2L(red[i + autoY] + autoX, green[i + autoY] + autoX, blue[i + autoY] + autoX, autoL[i], xyz_rgb, autoWidth); - } - // calculate contrast based blend factors to use vng4 in regions with low contrast - JaggedArray blend(autoWidth - 2, autoHeight - 2); - int c = calcContrastThreshold(autoL, blend, autoWidth, autoHeight); - if(c < 100) { - contrast = c; // alternative : contrast = c - 1 - } - } - } - #pragma omp parallel { #pragma omp for diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 1f84cad54..3de802232 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2074,7 +2074,7 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c double threshold = raw.bayersensor.dualDemosaicContrast; dual_demosaic_RT (true, raw, W, H, rawData, red, green, blue, threshold, false); } else { - dual_demosaic_RT (true, raw, W, H, rawData, red, green, blue, contrastThreshold, true, 0, 0); + dual_demosaic_RT (true, raw, W, H, rawData, red, green, blue, contrastThreshold, true); } } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::PIXELSHIFT) ) { pixelshift(0, 0, W, H, raw, currFrame, ri->get_maker(), ri->get_model(), raw.expos); @@ -2107,7 +2107,7 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c double threshold = raw.xtranssensor.dualDemosaicContrast; dual_demosaic_RT (false, raw, W, H, rawData, red, green, blue, threshold, false); } else { - dual_demosaic_RT (false, raw, W, H, rawData, red, green, blue, contrastThreshold, true, 0, 0); + dual_demosaic_RT (false, raw, W, H, rawData, red, green, blue, contrastThreshold, true); } } else if(raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::MONO) ) { nodemosaic(true); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index ad7807a44..1e2a1984d 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -274,7 +274,7 @@ protected: void igv_interpolate(int winw, int winh); void lmmse_interpolate_omp(int winw, int winh, array2D &rawData, array2D &red, array2D &green, array2D &blue, int iterations); void amaze_demosaic_RT(int winx, int winy, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue);//Emil's code for AMaZE - void dual_demosaic_RT(bool isBayer, const RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast = false, int autoX = -1, int autoY = -1); + void dual_demosaic_RT(bool isBayer, const RAWParams &raw, int winw, int winh, const array2D &rawData, array2D &red, array2D &green, array2D &blue, double &contrast, bool autoContrast = false); void fast_demosaic();//Emil's code for fast demosaicing void dcb_demosaic(int iterations, bool dcb_enhance); void ahd_demosaic(); diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index 49c972a47..71fa4fa6f 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -204,80 +204,87 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float contra constexpr float scale = 0.0625f / 327.68f; if (autoContrast) { StopWatch StopC("calculate dual demosaic auto contrast threshold"); - constexpr int tilesize = 80; - const int numTilesW = W / tilesize; - const int numTilesH = H / tilesize; - std::vector>> variances(numTilesH, std::vector>(numTilesW)); + for (int pass = 0; pass < 2; ++pass) { + const int tilesize = 80 / (pass + 1); + const int numTilesW = W / tilesize; + const int numTilesH = H / tilesize; + std::vector>> variances(numTilesH, std::vector>(numTilesW)); - #pragma omp parallel for - for (int i = 0; i < numTilesH; ++i) { - int tileY = i * tilesize; - for (int j = 0; j < numTilesW; ++j) { - int tileX = j * tilesize; + #pragma omp parallel for + for (int i = 0; i < numTilesH; ++i) { + int tileY = i * tilesize; + for (int j = 0; j < numTilesW; ++j) { + int tileX = j * tilesize; #ifdef __SSE2__ - vfloat avgv = ZEROV; - for (int y = tileY; y < tileY + tilesize; ++y) { - for (int x = tileX; x < tileX + tilesize; x += 4) { - avgv += LVFU(luminance[y][x]); + vfloat avgv = ZEROV; + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; x += 4) { + avgv += LVFU(luminance[y][x]); + } } - } - float avg = vhadd(avgv); + float avg = vhadd(avgv); #else - float avg = 0.; - for (int y = tileY; y < tileY + tilesize; ++y) { - for (int x = tileX; x < tileX + tilesize; ++x) { - avg += luminance[y][x]; + float avg = 0.; + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; ++x) { + avg += luminance[y][x]; + } } - } #endif - avg /= SQR(tilesize); + avg /= SQR(tilesize); #ifdef __SSE2__ - vfloat varv = ZEROV; - avgv = F2V(avg); - for (int y = tileY; y < tileY + tilesize; ++y) { - for (int x = tileX; x < tileX + tilesize; x +=4) { - varv += SQRV(LVFU(luminance[y][x]) - avgv); + vfloat varv = ZEROV; + avgv = F2V(avg); + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; x +=4) { + varv += SQRV(LVFU(luminance[y][x]) - avgv); + } } - } - float var = vhadd(varv); + float var = vhadd(varv); #else - float var = 0.0; - for (int y = tileY; y < tileY + tilesize; ++y) { - for (int x = tileX; x < tileX + tilesize; ++x) { - var += SQR(luminance[y][x] - avg); + float var = 0.0; + for (int y = tileY; y < tileY + tilesize; ++y) { + for (int x = tileX; x < tileX + tilesize; ++x) { + var += SQR(luminance[y][x] - avg); + } + } + #endif + var /= (SQR(tilesize) * avg); + variances[i][j].first = var; + variances[i][j].second = avg; + } + } + + float minvar = RT_INFINITY_F; + int minI = 0, minJ = 0; + for (int i = 0; i < numTilesH; ++i) { + for (int j = 0; j < numTilesW; ++j) { + if (variances[i][j].first < minvar && variances[i][j].second > 2000.f && variances[i][j].second < 20000.f) { + minvar = variances[i][j].first; + minI = i; + minJ = j; } } -#endif - var /= (SQR(tilesize) * avg); - variances[i][j].first = var; - variances[i][j].second = avg; } - } - float minvar = RT_INFINITY_F; - int minY = 0, minX = 0; - for (int i = 0; i < numTilesH; ++i) { - for (int j = 0; j < numTilesW; ++j) { - if (variances[i][j].first < minvar && variances[i][j].second > 2000.f && variances[i][j].second < 20000.f) { - minvar = variances[i][j].first; - minY = tilesize * i; - minX = tilesize * j; + const int minY = tilesize * minI; + const int minX = tilesize * minJ; + std::cout << "minvar : " << minvar << std::endl; + +// if (minvar <= 1.f || pass == 1) { + // a variance <= 1 means we already found a flat region and can skip second pass + JaggedArray Lum(tilesize, tilesize); + JaggedArray Blend(tilesize, tilesize); + for (int i = 0; i < tilesize; ++i) { + for (int j = 0; j < tilesize; ++j) { + Lum[i][j] = luminance[i + minY][j + minX]; + } } - } - } -// std::cout << "minY : " << minY << std::endl; -// std::cout << "minX : " << minX << std::endl; -// std::cout << "minvar : " << minvar << std::endl; - JaggedArray Lum(tilesize, tilesize); - JaggedArray Blend(tilesize, tilesize); - for (int i = 0; i < tilesize; ++i) { - for (int j = 0; j < tilesize; ++j) { - Lum[i][j] = luminance[i + minY][j + minX]; - } + /*contrastThreshold = */calcContrastThreshold(Lum, Blend, tilesize, tilesize);// / 100.f; +// break; +// } } - - calcContrastThreshold(Lum, Blend, tilesize, tilesize); } #ifdef _OPENMP @@ -368,7 +375,7 @@ int calcContrastThreshold(float** luminance, float **blend, int W, int H) { } } - const float limit = (W - 2) * (H - 2) / 100.f; + const float limit = (W - 4) * (H - 4) / 100.f; int c; for (c = 1; c < 100; ++c) { From 8b65900066854ff496998194a0a3ee9dbd044127 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 21 Oct 2018 20:21:43 +0200 Subject: [PATCH 04/14] Dual demosaic: Add auto threshold checkbox and show used value in ui, #4866 --- rtdata/languages/default | 4 ++- rtengine/dual_demosaic_RT.cc | 7 ++-- rtengine/improccoordinator.cc | 13 ++++++-- rtengine/improccoordinator.h | 12 +++++++ rtengine/ipsharpen.cc | 18 ++++++---- rtengine/procparams.cc | 20 +++++++++++ rtengine/procparams.h | 2 ++ rtengine/rt_algo.cc | 15 ++++----- rtengine/rt_algo.h | 2 +- rtengine/rtengine.h | 9 +++++ rtgui/bayerprocess.cc | 63 +++++++++++++++++++++++------------ rtgui/bayerprocess.h | 6 +++- rtgui/paramsedited.cc | 16 +++++++-- rtgui/paramsedited.h | 2 ++ rtgui/ppversion.h | 4 ++- rtgui/toolpanelcoord.cc | 2 ++ rtgui/toolpanelcoord.h | 2 ++ rtgui/xtransprocess.cc | 44 ++++++++++++++++++++++++ rtgui/xtransprocess.h | 9 ++++- 19 files changed, 201 insertions(+), 49 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 4ac12a093..72a76a75a 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -728,7 +728,8 @@ HISTORY_MSG_492;RGB Curves HISTORY_MSG_493;L*a*b* Adjustments HISTORY_MSG_CLAMPOOG;Clip out-of-gamut colors HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction -HISTORY_MSG_DUALDEMOSAIC_CONTRAST;AMaZE+VNG4 - Contrast threshold +HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold +HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold HISTORY_MSG_HISTMATCHING;Auto-matched tone curve HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D @@ -1815,6 +1816,7 @@ TP_RAW_DMETHOD;Method TP_RAW_DMETHOD_PROGRESSBAR;%1 demosaicing... TP_RAW_DMETHOD_PROGRESSBAR_REFINE;Demosaicing refinement... TP_RAW_DMETHOD_TOOLTIP;Note: IGV and LMMSE are dedicated to high ISO images to aid in noise reduction without leading to maze patterns, posterization or a washed-out look.\nPixel Shift is for Pentax/Sony Pixel Shift files. It falls back to AMaZE for non-Pixel Shift files. +TP_RAW_DUALDEMOSAICAUTOCONTRAST;Auto threshold TP_RAW_DUALDEMOSAICCONTRAST;Contrast threshold TP_RAW_EAHD;EAHD TP_RAW_FALSECOLOR;False color suppression steps diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 862516416..1498f600c 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -40,7 +40,7 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi { BENCHFUN - if (contrast == 0.0 && !autoContrast) { + if (contrast == 0.f) { // contrast == 0.0 means only first demosaicer will be used if(isBayer) { if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4) ) { @@ -100,7 +100,10 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi } // calculate contrast based blend factors to use vng4 in regions with low contrast JaggedArray blend(winw, winh); - buildBlendMask(L, blend, winw, winh, contrast / 100.f, 1.f, true); + float contrastf = contrast / 100.f; + + buildBlendMask(L, blend, winw, winh, contrastf, 1.f, autoContrast); + contrast = contrastf * 100.f; // the following is split into 3 loops intentionally to avoid cache conflicts on CPUs with only 4-way cache #pragma omp parallel for diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 832d193a2..f81aabd30 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -93,7 +93,7 @@ ImProcCoordinator::ImProcCoordinator() fw(0), fh(0), tr(0), fullw(1), fullh(1), pW(-1), pH(-1), - plistener(nullptr), imageListener(nullptr), aeListener(nullptr), acListener(nullptr), abwListener(nullptr), awbListener(nullptr), frameCountListener(nullptr), imageTypeListener(nullptr), actListener(nullptr), adnListener(nullptr), awavListener(nullptr), dehaListener(nullptr), hListener(nullptr), + plistener(nullptr), imageListener(nullptr), aeListener(nullptr), acListener(nullptr), abwListener(nullptr), awbListener(nullptr), bayerAutoContrastListener(nullptr), xtransAutoContrastListener(nullptr), frameCountListener(nullptr), imageTypeListener(nullptr), actListener(nullptr), adnListener(nullptr), awavListener(nullptr), dehaListener(nullptr), hListener(nullptr), resultValid(false), lastOutputProfile("BADFOOD"), lastOutputIntent(RI__COUNT), lastOutputBPC(false), thread(nullptr), changeSinceLast(0), updaterRunning(false), destroying(false), utili(false), autili(false), butili(false), ccutili(false), cclutili(false), clcutili(false), opautili(false), wavcontlutili(false), colourToningSatLimit(0.f), colourToningSatLimitOpacity(0.f), highQualityComputed(false) {} @@ -239,10 +239,17 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) imgsrc->setBorder(std::max(params.raw.bayersensor.border, 2)); } } - bool autoContrast = false; - double contrastThreshold = 0.f; + bool autoContrast = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicAutoContrast : params.raw.xtranssensor.dualDemosaicAutoContrast; + double contrastThreshold = params.raw.bayersensor.dualDemosaicContrast; imgsrc->demosaic(rp, autoContrast, contrastThreshold); //enabled demosaic + if (imgsrc->getSensorType() == ST_BAYER && bayerAutoContrastListener) { + bayerAutoContrastListener->autoContrastChanged(autoContrast ? contrastThreshold : -1.0); + } + if (imgsrc->getSensorType() == ST_FUJI_XTRANS && xtransAutoContrastListener) { + xtransAutoContrastListener->autoContrastChanged(autoContrast ? contrastThreshold : -1.0); + } + // if a demosaic happened we should also call getimage later, so we need to set the M_INIT flag todo |= M_INIT; diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index dba12cdd7..1c87ff4cd 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -158,6 +158,8 @@ protected: AutoCamListener* acListener; AutoBWListener* abwListener; AutoWBListener* awbListener; + AutoContrastListener *bayerAutoContrastListener; + AutoContrastListener *xtransAutoContrastListener; FrameCountListener *frameCountListener; ImageTypeListener *imageTypeListener; @@ -344,6 +346,16 @@ public: frameCountListener = fcl; } + void setBayerAutoContrastListener (AutoContrastListener* acl) + { + bayerAutoContrastListener = acl; + } + + void setXtransAutoContrastListener (AutoContrastListener* acl) + { + xtransAutoContrastListener = acl; + } + void setImageTypeListener (ImageTypeListener* itl) { imageTypeListener = itl; diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index eaf0db732..a84132a4c 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -176,7 +176,8 @@ BENCHFUN // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(luminance, blend, W, H, sharpenParam.contrast / 100.f, sharpenParam.deconvamount / 100.0); + float contrast = sharpenParam.contrast / 100.f; + buildBlendMask(luminance, blend, W, H, contrast, sharpenParam.deconvamount / 100.0); const float damping = sharpenParam.deconvdamping / 5.0; const bool needdamp = sharpenParam.deconvdamping > 0; @@ -222,7 +223,8 @@ void ImProcFunctions::sharpening (LabImage* lab, const SharpeningParams &sharpen if(showMask) { // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(lab->L, blend, W, H, sharpenParam.contrast / 100.f, sharpenParam.method == "rld" ? sharpenParam.deconvamount / 100.0 : 1.f); + float contrast = sharpenParam.contrast / 100.f; + buildBlendMask(lab->L, blend, W, H, contrast, sharpenParam.method == "rld" ? sharpenParam.deconvamount / 100.0 : 1.f); #ifdef _OPENMP #pragma omp parallel for #endif @@ -256,7 +258,8 @@ BENCHFUN // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(lab->L, blend, W, H, sharpenParam.contrast / 100.f); + float contrast = sharpenParam.contrast / 100.f; + buildBlendMask(lab->L, blend, W, H, contrast); #ifdef _OPENMP #pragma omp parallel @@ -610,7 +613,8 @@ BENCHFUN // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(luminance, blend, W, H, params->sharpenMicro.contrast / 100.f); + float contrast = params->sharpenMicro.contrast / 100.f; + buildBlendMask(luminance, blend, W, H, contrast); #ifdef _OPENMP #pragma omp parallel @@ -819,7 +823,8 @@ void ImProcFunctions::sharpeningcam (CieImage* ncie, float** b2, bool showMask) if(showMask) { // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(ncie->sh_p, blend, W, H, params->sharpening.contrast / 100.f); + float contrast = params->sharpening.contrast / 100.f; + buildBlendMask(ncie->sh_p, blend, W, H, contrast); #ifdef _OPENMP #pragma omp parallel for #endif @@ -852,7 +857,8 @@ void ImProcFunctions::sharpeningcam (CieImage* ncie, float** b2, bool showMask) // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); - buildBlendMask(ncie->sh_p, blend, W, H, params->sharpening.contrast / 100.f); + float contrast = params->sharpening.contrast / 100.f; + buildBlendMask(ncie->sh_p, blend, W, H, contrast); #ifdef _OPENMP #pragma omp parallel diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index d8d6aee33..f8df8ee63 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2388,6 +2388,7 @@ RAWParams::BayerSensor::BayerSensor() : greenthresh(0), dcb_iterations(2), lmmse_iterations(2), + dualDemosaicAutoContrast(true), dualDemosaicContrast(20), pixelShiftMotionCorrectionMethod(PSMotionCorrectionMethod::AUTO), pixelShiftEperIso(0.0), @@ -2425,6 +2426,7 @@ bool RAWParams::BayerSensor::operator ==(const BayerSensor& other) const && greenthresh == other.greenthresh && dcb_iterations == other.dcb_iterations && lmmse_iterations == other.lmmse_iterations + && dualDemosaicAutoContrast == other.dualDemosaicAutoContrast && dualDemosaicContrast == other.dualDemosaicContrast && pixelShiftMotionCorrectionMethod == other.pixelShiftMotionCorrectionMethod && pixelShiftEperIso == other.pixelShiftEperIso @@ -2512,6 +2514,7 @@ Glib::ustring RAWParams::BayerSensor::getPSDemosaicMethodString(PSDemosaicMethod RAWParams::XTransSensor::XTransSensor() : method(getMethodString(Method::THREE_PASS)), + dualDemosaicAutoContrast(true), dualDemosaicContrast(20), ccSteps(0), blackred(0.0), @@ -2524,6 +2527,7 @@ bool RAWParams::XTransSensor::operator ==(const XTransSensor& other) const { return method == other.method + && dualDemosaicAutoContrast == other.dualDemosaicAutoContrast && dualDemosaicContrast == other.dualDemosaicContrast && ccSteps == other.ccSteps && blackred == other.blackred @@ -3409,6 +3413,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->raw.bayersensor.dcbIterations, "RAW Bayer", "DCBIterations", raw.bayersensor.dcb_iterations, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.dcbEnhance, "RAW Bayer", "DCBEnhance", raw.bayersensor.dcb_enhance, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.lmmseIterations, "RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations, keyFile); + saveToKeyfile(!pedited || pedited->raw.bayersensor.dualDemosaicAutoContrast, "RAW Bayer", "DualDemosaicAutoContrast", raw.bayersensor.dualDemosaicAutoContrast, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.dualDemosaicContrast, "RAW Bayer", "DualDemosaicContrast", raw.bayersensor.dualDemosaicContrast, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod, "RAW Bayer", "PixelShiftMotionCorrectionMethod", toUnderlying(raw.bayersensor.pixelShiftMotionCorrectionMethod), keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftEperIso, "RAW Bayer", "PixelShiftEperIso", raw.bayersensor.pixelShiftEperIso, keyFile); @@ -3426,6 +3431,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftDemosaicMethod, "RAW Bayer", "pixelShiftDemosaicMethod", raw.bayersensor.pixelShiftDemosaicMethod, keyFile); saveToKeyfile(!pedited || pedited->raw.bayersensor.pdafLinesFilter, "RAW Bayer", "PDAFLinesFilter", raw.bayersensor.pdafLinesFilter, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.method, "RAW X-Trans", "Method", raw.xtranssensor.method, keyFile); + saveToKeyfile(!pedited || pedited->raw.xtranssensor.dualDemosaicAutoContrast, "RAW X-Trans", "DualDemosaicAutoContrast", raw.xtranssensor.dualDemosaicAutoContrast, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.dualDemosaicContrast, "RAW X-Trans", "DualDemosaicContrast", raw.xtranssensor.dualDemosaicContrast, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.ccSteps, "RAW X-Trans", "CcSteps", raw.xtranssensor.ccSteps, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.exBlackRed, "RAW X-Trans", "PreBlackRed", raw.xtranssensor.blackred, keyFile); @@ -4836,6 +4842,13 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "RAW Bayer", "DCBIterations", pedited, raw.bayersensor.dcb_iterations, pedited->raw.bayersensor.dcbIterations); assignFromKeyfile(keyFile, "RAW Bayer", "DCBEnhance", pedited, raw.bayersensor.dcb_enhance, pedited->raw.bayersensor.dcbEnhance); assignFromKeyfile(keyFile, "RAW Bayer", "LMMSEIterations", pedited, raw.bayersensor.lmmse_iterations, pedited->raw.bayersensor.lmmseIterations); + assignFromKeyfile(keyFile, "RAW Bayer", "DualDemosaicAutoContrast", pedited, raw.bayersensor.dualDemosaicAutoContrast, pedited->raw.bayersensor.dualDemosaicAutoContrast); + if (ppVersion < 344) { + raw.bayersensor.dualDemosaicAutoContrast = false; + if (pedited) { + pedited->raw.bayersensor.dualDemosaicAutoContrast = true; + } + } assignFromKeyfile(keyFile, "RAW Bayer", "DualDemosaicContrast", pedited, raw.bayersensor.dualDemosaicContrast, pedited->raw.bayersensor.dualDemosaicContrast); if (keyFile.has_key("RAW Bayer", "PixelShiftMotionCorrectionMethod")) { @@ -4883,6 +4896,13 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("RAW X-Trans")) { assignFromKeyfile(keyFile, "RAW X-Trans", "Method", pedited, raw.xtranssensor.method, pedited->raw.xtranssensor.method); + assignFromKeyfile(keyFile, "RAW X-Trans", "DualDemosaicAutoContrast", pedited, raw.xtranssensor.dualDemosaicAutoContrast, pedited->raw.xtranssensor.dualDemosaicAutoContrast); + if (ppVersion < 344) { + raw.xtranssensor.dualDemosaicAutoContrast = false; + if (pedited) { + pedited->raw.xtranssensor.dualDemosaicAutoContrast = true; + } + } assignFromKeyfile(keyFile, "RAW X-Trans", "DualDemosaicContrast", pedited, raw.xtranssensor.dualDemosaicContrast, pedited->raw.xtranssensor.dualDemosaicContrast); assignFromKeyfile(keyFile, "RAW X-Trans", "CcSteps", pedited, raw.xtranssensor.ccSteps, pedited->raw.xtranssensor.ccSteps); assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackRed", pedited, raw.xtranssensor.blackred, pedited->raw.xtranssensor.exBlackRed); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 0b8b5ba56..d8fa89a64 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1285,6 +1285,7 @@ struct RAWParams { int greenthresh; int dcb_iterations; int lmmse_iterations; + bool dualDemosaicAutoContrast; double dualDemosaicContrast; PSMotionCorrectionMethod pixelShiftMotionCorrectionMethod; double pixelShiftEperIso; @@ -1332,6 +1333,7 @@ struct RAWParams { }; Glib::ustring method; + bool dualDemosaicAutoContrast; double dualDemosaicContrast; int ccSteps; double blackred; diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index 71fa4fa6f..975b08374 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -34,7 +34,7 @@ #include "rt_math.h" #include "sleef.c" #include "jaggedarray.h" -#include "StopWatch.h" + namespace { float calcBlendFactor(float val, float threshold) { // sigmoid function @@ -192,7 +192,7 @@ void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& maxOut += minVal; } -void buildBlendMask(float** luminance, float **blend, int W, int H, float contrastThreshold, float amount, bool autoContrast) { +void buildBlendMask(float** luminance, float **blend, int W, int H, float &contrastThreshold, float amount, bool autoContrast) { if(contrastThreshold == 0.f) { for(int j = 0; j < H; ++j) { @@ -203,7 +203,6 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float contra } else { constexpr float scale = 0.0625f / 327.68f; if (autoContrast) { - StopWatch StopC("calculate dual demosaic auto contrast threshold"); for (int pass = 0; pass < 2; ++pass) { const int tilesize = 80 / (pass + 1); const int numTilesW = W / tilesize; @@ -269,9 +268,8 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float contra const int minY = tilesize * minI; const int minX = tilesize * minJ; - std::cout << "minvar : " << minvar << std::endl; -// if (minvar <= 1.f || pass == 1) { + if (minvar <= 1.f || pass == 1) { // a variance <= 1 means we already found a flat region and can skip second pass JaggedArray Lum(tilesize, tilesize); JaggedArray Blend(tilesize, tilesize); @@ -281,9 +279,9 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float contra } } - /*contrastThreshold = */calcContrastThreshold(Lum, Blend, tilesize, tilesize);// / 100.f; -// break; -// } + contrastThreshold = std::min(contrastThreshold, calcContrastThreshold(Lum, Blend, tilesize, tilesize) / 100.f); + break; + } } } @@ -404,7 +402,6 @@ int calcContrastThreshold(float** luminance, float **blend, int W, int H) { break; } } - std::cout << "dual demosaic auto contrast threshold : " << c << std::endl; return c; } diff --git a/rtengine/rt_algo.h b/rtengine/rt_algo.h index 3a91c327b..0207e6f57 100644 --- a/rtengine/rt_algo.h +++ b/rtengine/rt_algo.h @@ -24,6 +24,6 @@ namespace rtengine { void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& minOut, float maxPrct, float& maxOut, bool multiThread = true); -void buildBlendMask(float** luminance, float **blend, int W, int H, float contrastThreshold, float amount = 1.f, bool autoContrast = false); +void buildBlendMask(float** luminance, float **blend, int W, int H, float &contrastThreshold, float amount = 1.f, bool autoContrast = false); int calcContrastThreshold(float** luminance, float **blend, int W, int H); } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index d26d82396..fcb00457a 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -365,6 +365,13 @@ public : virtual void imageTypeChanged (bool isRaw, bool isBayer, bool isXtrans, bool is_Mono = false) = 0; }; +class AutoContrastListener +{ +public : + virtual ~AutoContrastListener() = default; + virtual void autoContrastChanged (double autoContrast) = 0; +}; + class WaveletListener { public : @@ -470,6 +477,8 @@ public: virtual void setPreviewImageListener (PreviewImageListener* l) = 0; virtual void setAutoCamListener (AutoCamListener* l) = 0; virtual void setFrameCountListener (FrameCountListener* l) = 0; + virtual void setBayerAutoContrastListener (AutoContrastListener* l) = 0; + virtual void setXtransAutoContrastListener (AutoContrastListener* l) = 0; virtual void setAutoBWListener (AutoBWListener* l) = 0; virtual void setAutoWBListener (AutoWBListener* l) = 0; virtual void setAutoColorTonListener (AutoColorTonListener* l) = 0; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index d68f5c2d3..ed9f86ab6 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -30,6 +30,7 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA auto m = ProcEventMapper::getInstance(); EvDemosaicBorder = m->newEvent(DEMOSAIC, "HISTORY_MSG_RAW_BORDER"); EvDemosaicContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_DUALDEMOSAIC_CONTRAST"); + EvDemosaicAutoContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST"); EvDemosaicPixelshiftDemosaicMethod = m->newEvent(DEMOSAIC, "HISTORY_MSG_PIXELSHIFT_DEMOSAIC"); Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); @@ -46,17 +47,26 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA hb1->pack_end (*method, Gtk::PACK_EXPAND_WIDGET, 4); pack_start( *hb1, Gtk::PACK_SHRINK, 4); + dualDemosaicOptions = Gtk::manage(new Gtk::VBox()); + Gtk::HBox* hbAutoContrast = Gtk::manage(new Gtk::HBox()); - dualDemosaicOptions = Gtk::manage (new Gtk::VBox ()); + dualDemosaicAutoContrast = Gtk::manage(new CheckBox(M("TP_RAW_DUALDEMOSAICAUTOCONTRAST"), multiImage)); + dualDemosaicAutoContrast->setCheckBoxListener(this); - dualDemosaicContrast = Gtk::manage(new Adjuster (M("TP_RAW_DUALDEMOSAICCONTRAST"), 0, 100, 1, 20)); - dualDemosaicContrast->setAdjusterListener (this); + dualDemosaicLabel = Gtk::manage(new Gtk::Label("")); + + dualDemosaicContrast = Gtk::manage(new Adjuster(M("TP_RAW_DUALDEMOSAICCONTRAST"), 0, 100, 1, 20)); + dualDemosaicContrast->setAdjusterListener(this); if (dualDemosaicContrast->delay < options.adjusterMaxDelay) { dualDemosaicContrast->delay = options.adjusterMaxDelay; } + dualDemosaicAutoContrast->show(); dualDemosaicContrast->show(); + hbAutoContrast->pack_start(*dualDemosaicAutoContrast); + hbAutoContrast->pack_start(*dualDemosaicLabel); + dualDemosaicOptions->pack_start(*hbAutoContrast); dualDemosaicOptions->pack_start(*dualDemosaicContrast); pack_start( *dualDemosaicOptions, Gtk::PACK_SHRINK, 4); @@ -300,6 +310,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftNonGreenCross->setValue (pp->raw.bayersensor.pixelShiftNonGreenCross); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); + dualDemosaicAutoContrast->setValue (pp->raw.bayersensor.dualDemosaicAutoContrast); dualDemosaicContrast->setValue (pp->raw.bayersensor.dualDemosaicContrast); pixelShiftMotionMethod->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrectionMethod); pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); @@ -324,6 +335,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftEqualBrightChannel->setEdited (pedited->raw.bayersensor.pixelShiftEqualBrightChannel); pixelShiftNonGreenCross->setEdited (pedited->raw.bayersensor.pixelShiftNonGreenCross); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); + dualDemosaicAutoContrast->setEdited ( pedited->raw.bayersensor.dualDemosaicAutoContrast ? Edited : UnEdited); dualDemosaicContrast->setEditedState ( pedited->raw.bayersensor.dualDemosaicContrast ? Edited : UnEdited); pixelShiftEperIso->setEditedState ( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftSigma->setEditedState ( pedited->raw.bayersensor.pixelShiftSigma ? Edited : UnEdited); @@ -385,6 +397,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.dcb_enhance = dcbEnhance->getLastActive (); pp->raw.bayersensor.border = border->getIntValue(); pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); + pp->raw.bayersensor.dualDemosaicAutoContrast = dualDemosaicAutoContrast->getLastActive (); pp->raw.bayersensor.dualDemosaicContrast = dualDemosaicContrast->getValue(); pp->raw.bayersensor.pixelShiftMotionCorrectionMethod = (RAWParams::BayerSensor::PSMotionCorrectionMethod)pixelShiftMotionMethod->get_active_row_number(); pp->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getValue(); @@ -425,6 +438,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.dcbEnhance = !dcbEnhance->get_inconsistent(); //pedited->raw.bayersensor.allEnhance = !allEnhance->get_inconsistent(); pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); + pedited->raw.bayersensor.dualDemosaicAutoContrast = !dualDemosaicAutoContrast->get_inconsistent(); pedited->raw.bayersensor.dualDemosaicContrast = dualDemosaicContrast->getEditedState (); pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod = pixelShiftMotionMethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->raw.bayersensor.pixelShiftDemosaicMethod = pixelShiftDemosaicMethod->get_active_text() != M("GENERAL_UNCHANGED"); @@ -603,7 +617,11 @@ void BayerProcess::imageNumberChanged () void BayerProcess::checkBoxToggled (CheckBox* c, CheckValue newval) { - if (c == dcbEnhance) { + if (c == dualDemosaicAutoContrast) { + if (listener) { + listener->panelChanged (EvDemosaicAutoContrast, dualDemosaicAutoContrast->getValueAsStr ()); + } + } else if (c == dcbEnhance) { if (listener) { listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->getValueAsStr ()); } @@ -711,23 +729,24 @@ void BayerProcess::FrameCountChanged(int n, int frameNum) }; idle_register.add(func, new Data { this, n, frameNum }); - - // GThreadLock lock; - // imageNumber->block (true); - - // imageNumber->remove_all(); - // imageNumber->append("1"); - // for(int i = 2; i <= std::min(n, 4); ++i) { - // std::ostringstream entry; - // entry << i; - // imageNumber->append(entry.str()); - // } - // imageNumber->set_active(std::min(frameNum, n - 1)); - // if(n == 1) { - // imageNumberBox->hide(); - // } else { - // imageNumberBox->show(); - // } - // imageNumber->block (false); } +void BayerProcess::autoContrastChanged (double autoContrast) +{ + struct Data { + BayerProcess *me; + double autoContrast; + }; + const auto func = [](gpointer data) -> gboolean { + Data *d = static_cast(data); + BayerProcess *me = d->me; + if (d->autoContrast == -1.0) { + me->dualDemosaicLabel->set_text(""); + } else { + me->dualDemosaicLabel->set_text(Glib::ustring::format(std::fixed, std::setprecision(0), d->autoContrast)); + } + return FALSE; + }; + + idle_register.add(func, new Data { this, autoContrast }); +} diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index cfd063ca9..fe7163ffc 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -25,7 +25,7 @@ #include "guiutils.h" #include "toolpanel.h" -class BayerProcess : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel, public rtengine::FrameCountListener +class BayerProcess : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel, public rtengine::FrameCountListener, public rtengine::AutoContrastListener { protected: @@ -59,11 +59,14 @@ protected: Adjuster* pixelShiftSigma; Gtk::VBox *dualDemosaicOptions; Adjuster* dualDemosaicContrast; + CheckBox* dualDemosaicAutoContrast; + Gtk::Label* dualDemosaicLabel; int oldMethod; IdleRegister idle_register; rtengine::ProcEvent EvDemosaicBorder; + rtengine::ProcEvent EvDemosaicAutoContrast; rtengine::ProcEvent EvDemosaicContrast; rtengine::ProcEvent EvDemosaicPixelshiftDemosaicMethod; public: @@ -83,6 +86,7 @@ public: void checkBoxToggled(CheckBox* c, CheckValue newval); void pixelShiftMotionMethodChanged(); void pixelShiftDemosaicMethodChanged(); + void autoContrastChanged (double autoContrast); void FrameCountChanged(int n, int frameNum); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 2ccb62f65..04b8363f3 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -405,6 +405,7 @@ void ParamsEdited::set(bool v) raw.bayersensor.dcbEnhance = v; //raw.bayersensor.allEnhance = v; raw.bayersensor.lmmseIterations = v; + raw.bayersensor.dualDemosaicAutoContrast = v; raw.bayersensor.dualDemosaicContrast = v; raw.bayersensor.pixelShiftMotionCorrectionMethod = v; raw.bayersensor.pixelShiftEperIso = v; @@ -425,6 +426,7 @@ void ParamsEdited::set(bool v) raw.bayersensor.linenoiseDirection = v; raw.bayersensor.pdafLinesFilter = v; raw.xtranssensor.method = v; + raw.xtranssensor.dualDemosaicAutoContrast = v; raw.xtranssensor.dualDemosaicContrast = v; raw.xtranssensor.ccSteps = v; raw.xtranssensor.exBlackRed = v; @@ -962,6 +964,7 @@ void ParamsEdited::initFrom(const std::vector& raw.bayersensor.dcbEnhance = raw.bayersensor.dcbEnhance && p.raw.bayersensor.dcb_enhance == other.raw.bayersensor.dcb_enhance; //raw.bayersensor.allEnhance = raw.bayersensor.allEnhance && p.raw.bayersensor.all_enhance == other.raw.bayersensor.all_enhance; raw.bayersensor.lmmseIterations = raw.bayersensor.lmmseIterations && p.raw.bayersensor.lmmse_iterations == other.raw.bayersensor.lmmse_iterations; + raw.bayersensor.dualDemosaicAutoContrast = raw.bayersensor.dualDemosaicAutoContrast && p.raw.bayersensor.dualDemosaicAutoContrast == other.raw.bayersensor.dualDemosaicAutoContrast; raw.bayersensor.dualDemosaicContrast = raw.bayersensor.dualDemosaicContrast && p.raw.bayersensor.dualDemosaicContrast == other.raw.bayersensor.dualDemosaicContrast; raw.bayersensor.pixelShiftMotionCorrectionMethod = raw.bayersensor.pixelShiftMotionCorrectionMethod && p.raw.bayersensor.pixelShiftMotionCorrectionMethod == other.raw.bayersensor.pixelShiftMotionCorrectionMethod; raw.bayersensor.pixelShiftEperIso = raw.bayersensor.pixelShiftEperIso && p.raw.bayersensor.pixelShiftEperIso == other.raw.bayersensor.pixelShiftEperIso; @@ -982,6 +985,7 @@ void ParamsEdited::initFrom(const std::vector& raw.bayersensor.linenoiseDirection = raw.bayersensor.linenoiseDirection && p.raw.bayersensor.linenoiseDirection == other.raw.bayersensor.linenoiseDirection; raw.bayersensor.pdafLinesFilter = raw.bayersensor.pdafLinesFilter && p.raw.bayersensor.pdafLinesFilter == other.raw.bayersensor.pdafLinesFilter; raw.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; + raw.xtranssensor.dualDemosaicAutoContrast = raw.xtranssensor.dualDemosaicAutoContrast && p.raw.xtranssensor.dualDemosaicAutoContrast == other.raw.xtranssensor.dualDemosaicAutoContrast; raw.xtranssensor.dualDemosaicContrast = raw.xtranssensor.dualDemosaicContrast && p.raw.xtranssensor.dualDemosaicContrast == other.raw.xtranssensor.dualDemosaicContrast; raw.xtranssensor.ccSteps = raw.xtranssensor.ccSteps && p.raw.xtranssensor.ccSteps == other.raw.xtranssensor.ccSteps; raw.xtranssensor.exBlackRed = raw.xtranssensor.exBlackRed && p.raw.xtranssensor.blackred == other.raw.xtranssensor.blackred; @@ -2526,6 +2530,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.raw.bayersensor.lmmse_iterations = mods.raw.bayersensor.lmmse_iterations; } + if (raw.bayersensor.dualDemosaicAutoContrast) { + toEdit.raw.bayersensor.dualDemosaicAutoContrast = mods.raw.bayersensor.dualDemosaicAutoContrast; + } + if (raw.bayersensor.dualDemosaicContrast) { toEdit.raw.bayersensor.dualDemosaicContrast = mods.raw.bayersensor.dualDemosaicContrast; } @@ -2606,6 +2614,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.raw.xtranssensor.method = mods.raw.xtranssensor.method; } + if (raw.xtranssensor.dualDemosaicAutoContrast) { + toEdit.raw.xtranssensor.dualDemosaicAutoContrast = mods.raw.xtranssensor.dualDemosaicAutoContrast; + } + if (raw.xtranssensor.dualDemosaicContrast) { toEdit.raw.xtranssensor.dualDemosaicContrast = mods.raw.xtranssensor.dualDemosaicContrast; } @@ -3126,7 +3138,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng bool RAWParamsEdited::BayerSensor::isUnchanged() const { - return method && border && imageNum && dcbIterations && dcbEnhance && lmmseIterations && dualDemosaicContrast /*&& allEnhance*/ && greenEq + return method && border && imageNum && dcbIterations && dcbEnhance && lmmseIterations && dualDemosaicAutoContrast && dualDemosaicContrast /*&& allEnhance*/ && greenEq && pixelShiftMotionCorrectionMethod && pixelShiftEperIso && pixelShiftSigma && pixelShiftShowMotion && pixelShiftShowMotionMaskOnly && pixelShiftHoleFill && pixelShiftMedian && pixelShiftNonGreenCross && pixelShiftDemosaicMethod && pixelShiftGreen && pixelShiftBlur && pixelShiftSmooth && pixelShiftEqualBright && pixelShiftEqualBrightChannel && linenoise && linenoiseDirection && pdafLinesFilter && exBlack0 && exBlack1 && exBlack2 && exBlack3 && exTwoGreen; @@ -3134,7 +3146,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const bool RAWParamsEdited::XTransSensor::isUnchanged() const { - return method && exBlackRed && exBlackGreen && exBlackBlue; + return method && exBlackRed && exBlackGreen && exBlackBlue && dualDemosaicAutoContrast && dualDemosaicContrast; } bool RAWParamsEdited::isUnchanged() const diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 0a795696c..faa3a6c8e 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -744,6 +744,7 @@ public: bool dcbIterations; bool dcbEnhance; bool lmmseIterations; + bool dualDemosaicAutoContrast; bool dualDemosaicContrast; bool pixelShiftMotionCorrectionMethod; bool pixelShiftEperIso; @@ -774,6 +775,7 @@ public: public: bool method; + bool dualDemosaicAutoContrast; bool dualDemosaicContrast; bool ccSteps; bool exBlackRed; diff --git a/rtgui/ppversion.h b/rtgui/ppversion.h index 050c4c653..417171197 100644 --- a/rtgui/ppversion.h +++ b/rtgui/ppversion.h @@ -1,11 +1,13 @@ #pragma once // This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes -#define PPVERSION 343 +#define PPVERSION 344 #define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified /* Log of version changes + 344 2018-10-21 + dual demosaic auto contrast threshold 343 2018-09-06 raw auto ca correction avoid colour shift 342 2018-09-05 diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index deecb7682..6e8e80cf2 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -517,6 +517,8 @@ void ToolPanelCoordinator::initImage (rtengine::StagedImageProcessor* ipc_, bool ipc->setAutoCamListener (colorappearance); ipc->setAutoBWListener (blackwhite); ipc->setFrameCountListener (bayerprocess); + ipc->setBayerAutoContrastListener (bayerprocess); + ipc->setXtransAutoContrastListener (xtransprocess); ipc->setAutoWBListener (whitebalance); ipc->setAutoColorTonListener (colortoning); ipc->setAutoChromaListener (dirpyrdenoise); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 1c46ee54e..866efafa5 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -220,6 +220,8 @@ public: void panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr); void imageTypeChanged (bool isRaw, bool isBayer, bool isXtrans, bool isMono = false); + +// void autoContrastChanged (double autoContrast); // profilechangelistener interface void profileChange (const rtengine::procparams::PartialProfile* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited = nullptr, bool fromLastSave = false); void setDefaults (rtengine::procparams::ProcParams* defparams); diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 27b5810c4..df771d8ca 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -28,6 +28,7 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP { auto m = ProcEventMapper::getInstance(); EvDemosaicContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_DUALDEMOSAIC_CONTRAST"); + EvDemosaicAutoContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST"); Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") + ": ")), Gtk::PACK_SHRINK, 4); @@ -68,6 +69,12 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP pack_start( *hb1, Gtk::PACK_SHRINK, 4); dualDemosaicOptions = Gtk::manage (new Gtk::VBox ()); + Gtk::HBox* hbAutoContrast = Gtk::manage(new Gtk::HBox()); + + dualDemosaicAutoContrast = Gtk::manage(new CheckBox(M("TP_RAW_DUALDEMOSAICAUTOCONTRAST"), multiImage)); + dualDemosaicAutoContrast->setCheckBoxListener(this); + + dualDemosaicLabel = Gtk::manage(new Gtk::Label("")); dualDemosaicContrast = Gtk::manage(new Adjuster (M("TP_RAW_DUALDEMOSAICCONTRAST"), 0, 100, 1, 20)); dualDemosaicContrast->setAdjusterListener (this); @@ -76,7 +83,11 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP dualDemosaicContrast->delay = options.adjusterMaxDelay; } + dualDemosaicAutoContrast->show(); dualDemosaicContrast->show(); + hbAutoContrast->pack_start(*dualDemosaicAutoContrast); + hbAutoContrast->pack_start(*dualDemosaicLabel); + dualDemosaicOptions->pack_start(*hbAutoContrast); dualDemosaicOptions->pack_start(*dualDemosaicContrast); pack_start( *dualDemosaicOptions, Gtk::PACK_SHRINK, 4); @@ -108,6 +119,7 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param } if(pedited ) { + dualDemosaicAutoContrast->setEdited ( pedited->raw.xtranssensor.dualDemosaicAutoContrast ? Edited : UnEdited); dualDemosaicContrast->setEditedState ( pedited->raw.xtranssensor.dualDemosaicContrast ? Edited : UnEdited); ccSteps->setEditedState (pedited->raw.xtranssensor.ccSteps ? Edited : UnEdited); @@ -115,6 +127,7 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param method->set_active_text(M("GENERAL_UNCHANGED")); } } + dualDemosaicAutoContrast->setValue (pp->raw.xtranssensor.dualDemosaicAutoContrast); dualDemosaicContrast->setValue (pp->raw.xtranssensor.dualDemosaicContrast); ccSteps->setValue (pp->raw.xtranssensor.ccSteps); if (!batchMode) { @@ -129,6 +142,7 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) { + pp->raw.xtranssensor.dualDemosaicAutoContrast = dualDemosaicAutoContrast->getLastActive (); pp->raw.xtranssensor.dualDemosaicContrast = dualDemosaicContrast->getValue(); pp->raw.xtranssensor.ccSteps = ccSteps->getIntValue(); @@ -140,6 +154,7 @@ void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* p if (pedited) { pedited->raw.xtranssensor.method = method->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->raw.xtranssensor.dualDemosaicAutoContrast = !dualDemosaicAutoContrast->get_inconsistent(); pedited->raw.xtranssensor.dualDemosaicContrast = dualDemosaicContrast->getEditedState (); pedited->raw.xtranssensor.ccSteps = ccSteps->getEditedState (); } @@ -185,6 +200,15 @@ void XTransProcess::adjusterChanged (Adjuster* a, double newval) } } +void XTransProcess::checkBoxToggled (CheckBox* c, CheckValue newval) +{ + if (c == dualDemosaicAutoContrast) { + if (listener) { + listener->panelChanged (EvDemosaicAutoContrast, dualDemosaicAutoContrast->getValueAsStr ()); + } + } +} + void XTransProcess::methodChanged () { const int curSelection = method->get_active_row_number(); @@ -207,3 +231,23 @@ void XTransProcess::methodChanged () : EvDemosaicMethod, method->get_active_text()); } } + +void XTransProcess::autoContrastChanged (double autoContrast) +{ + struct Data { + XTransProcess *me; + double autoContrast; + }; + const auto func = [](gpointer data) -> gboolean { + Data *d = static_cast(data); + XTransProcess *me = d->me; + if (d->autoContrast == -1.0) { + me->dualDemosaicLabel->set_text(""); + } else { + me->dualDemosaicLabel->set_text(Glib::ustring::format(std::fixed, std::setprecision(0), d->autoContrast)); + } + return FALSE; + }; + + idle_register.add(func, new Data { this, autoContrast }); +} diff --git a/rtgui/xtransprocess.h b/rtgui/xtransprocess.h index edc0965b8..af3f25596 100644 --- a/rtgui/xtransprocess.h +++ b/rtgui/xtransprocess.h @@ -21,11 +21,12 @@ #include #include "adjuster.h" +#include "checkbox.h" #include "guiutils.h" #include "toolpanel.h" -class XTransProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel +class XTransProcess : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel, public rtengine::AutoContrastListener { protected: @@ -34,9 +35,13 @@ protected: Adjuster* ccSteps; Gtk::VBox *dualDemosaicOptions; Adjuster* dualDemosaicContrast; + CheckBox* dualDemosaicAutoContrast; + Gtk::Label* dualDemosaicLabel; int oldSelection; sigc::connection methodconn; + IdleRegister idle_register; + rtengine::ProcEvent EvDemosaicAutoContrast; rtengine::ProcEvent EvDemosaicContrast; public: @@ -50,7 +55,9 @@ public: void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr); void methodChanged(); + void autoContrastChanged (double autoContrast); void adjusterChanged(Adjuster* a, double newval); + void checkBoxToggled(CheckBox* c, CheckValue newval); }; #endif From 3cd065ea2168c72224fec68aba9897997cde9063 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 21 Oct 2018 21:18:05 +0200 Subject: [PATCH 05/14] partial paste: add dualdemosaic auto threshold --- rtgui/partialpastedlg.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 6b192dba9..91e542e85 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -828,8 +828,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param if (!raw_method->get_active ()) { filterPE.raw.bayersensor.method = falsePE.raw.bayersensor.method; + filterPE.raw.bayersensor.dualDemosaicAutoContrast = falsePE.raw.bayersensor.dualDemosaicAutoContrast; filterPE.raw.bayersensor.dualDemosaicContrast = falsePE.raw.bayersensor.dualDemosaicContrast; filterPE.raw.xtranssensor.method = falsePE.raw.xtranssensor.method; + filterPE.raw.xtranssensor.dualDemosaicAutoContrast = falsePE.raw.xtranssensor.dualDemosaicAutoContrast; filterPE.raw.xtranssensor.dualDemosaicContrast = falsePE.raw.xtranssensor.dualDemosaicContrast; } From 459f64bac2f50740aea15495a5790e264a1c9108 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 21 Oct 2018 22:55:56 +0200 Subject: [PATCH 06/14] Disable demosaic timing code --- rtengine/demosaic_algos.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index c0d0c2a2b..10ef0dd0e 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -37,7 +37,7 @@ #include "sleef.c" #include "opthelper.h" #include "median.h" -#define BENCHMARK +//#define BENCHMARK #include "StopWatch.h" #ifdef _OPENMP #include From e2965cc6b431e2b2e9c042b8a0c7ceff644743f6 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 22 Oct 2018 14:22:49 +0200 Subject: [PATCH 07/14] dual demosaic: improved auto threshold detection and fall back to more detailed demosaicer if no flat region was found, #4866 --- rtengine/rt_algo.cc | 5 +++-- rtgui/bayerprocess.cc | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index 975b08374..8472fb858 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -269,8 +269,10 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float &contr const int minY = tilesize * minI; const int minX = tilesize * minJ; +// std::cout << pass << ": minvar : " << minvar << std::endl; if (minvar <= 1.f || pass == 1) { // a variance <= 1 means we already found a flat region and can skip second pass + // in second pass we allow a variance of 2 JaggedArray Lum(tilesize, tilesize); JaggedArray Blend(tilesize, tilesize); for (int i = 0; i < tilesize; ++i) { @@ -278,8 +280,7 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float &contr Lum[i][j] = luminance[i + minY][j + minX]; } } - - contrastThreshold = std::min(contrastThreshold, calcContrastThreshold(Lum, Blend, tilesize, tilesize) / 100.f); + contrastThreshold = (pass == 0 || minvar <= 2.f) ? calcContrastThreshold(Lum, Blend, tilesize, tilesize) / 100.f : 0.f; break; } } diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 9b5ffece2..f9b6ef9e5 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -312,6 +312,9 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); dualDemosaicAutoContrast->setValue (pp->raw.bayersensor.dualDemosaicAutoContrast); dualDemosaicContrast->setValue (pp->raw.bayersensor.dualDemosaicContrast); + if (!batchMode) { + dualDemosaicContrast->set_sensitive(!pp->raw.bayersensor.dualDemosaicAutoContrast); + } pixelShiftMotionMethod->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrectionMethod); pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); pixelShiftSigma->setValue (pp->raw.bayersensor.pixelShiftSigma); @@ -622,6 +625,9 @@ void BayerProcess::imageNumberChanged () void BayerProcess::checkBoxToggled (CheckBox* c, CheckValue newval) { if (c == dualDemosaicAutoContrast) { + if (!batchMode) { + dualDemosaicContrast->set_sensitive(newval == CheckValue::off); + } if (listener) { listener->panelChanged (EvDemosaicAutoContrast, dualDemosaicAutoContrast->getValueAsStr ()); } From be987d8f32b96e72ed0215253b85bb8fc5967ecd Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 22 Oct 2018 17:24:36 +0200 Subject: [PATCH 08/14] dual demosaic auto contrast: fix segfault when falling back to zero, #4866 --- rtengine/rt_algo.cc | 112 ++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 52 deletions(-) diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index 8472fb858..4bdcc88a3 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -286,64 +286,72 @@ void buildBlendMask(float** luminance, float **blend, int W, int H, float &contr } } -#ifdef _OPENMP - #pragma omp parallel -#endif - { -#ifdef __SSE2__ - const vfloat contrastThresholdv = F2V(contrastThreshold); - const vfloat scalev = F2V(scale); - const vfloat amountv = F2V(amount); -#endif -#ifdef _OPENMP - #pragma omp for schedule(dynamic,16) -#endif - - for(int j = 2; j < H - 2; ++j) { - int i = 2; -#ifdef __SSE2__ - for(; i < W - 5; i += 4) { - vfloat contrastv = vsqrtf(SQRV(LVFU(luminance[j][i+1]) - LVFU(luminance[j][i-1])) + SQRV(LVFU(luminance[j+1][i]) - LVFU(luminance[j-1][i])) + - SQRV(LVFU(luminance[j][i+2]) - LVFU(luminance[j][i-2])) + SQRV(LVFU(luminance[j+2][i]) - LVFU(luminance[j-2][i]))) * scalev; - - STVFU(blend[j][i], amountv * calcBlendFactor(contrastv, contrastThresholdv)); - } -#endif - for(; i < W - 2; ++i) { - - float contrast = sqrtf(rtengine::SQR(luminance[j][i+1] - luminance[j][i-1]) + rtengine::SQR(luminance[j+1][i] - luminance[j-1][i]) + - rtengine::SQR(luminance[j][i+2] - luminance[j][i-2]) + rtengine::SQR(luminance[j+2][i] - luminance[j-2][i])) * scale; - - blend[j][i] = amount * calcBlendFactor(contrast, contrastThreshold); + if(contrastThreshold == 0.f) { + for(int j = 0; j < H; ++j) { + for(int i = 0; i < W; ++i) { + blend[j][i] = amount; } } - + } else { #ifdef _OPENMP - #pragma omp single + #pragma omp parallel #endif { - // upper border - for(int j = 0; j < 2; ++j) { - for(int i = 2; i < W - 2; ++i) { - blend[j][i] = blend[2][i]; - } - } - // lower border - for(int j = H - 2; j < H; ++j) { - for(int i = 2; i < W - 2; ++i) { - blend[j][i] = blend[H-3][i]; - } - } - for(int j = 0; j < H; ++j) { - // left border - blend[j][0] = blend[j][1] = blend[j][2]; - // right border - blend[j][W - 2] = blend[j][W - 1] = blend[j][W - 3]; - } - } +#ifdef __SSE2__ + const vfloat contrastThresholdv = F2V(contrastThreshold); + const vfloat scalev = F2V(scale); + const vfloat amountv = F2V(amount); +#endif +#ifdef _OPENMP + #pragma omp for schedule(dynamic,16) +#endif - // blur blend mask to smooth transitions - gaussianBlur(blend, blend, W, H, 2.0); + for(int j = 2; j < H - 2; ++j) { + int i = 2; +#ifdef __SSE2__ + for(; i < W - 5; i += 4) { + vfloat contrastv = vsqrtf(SQRV(LVFU(luminance[j][i+1]) - LVFU(luminance[j][i-1])) + SQRV(LVFU(luminance[j+1][i]) - LVFU(luminance[j-1][i])) + + SQRV(LVFU(luminance[j][i+2]) - LVFU(luminance[j][i-2])) + SQRV(LVFU(luminance[j+2][i]) - LVFU(luminance[j-2][i]))) * scalev; + + STVFU(blend[j][i], amountv * calcBlendFactor(contrastv, contrastThresholdv)); + } +#endif + for(; i < W - 2; ++i) { + + float contrast = sqrtf(rtengine::SQR(luminance[j][i+1] - luminance[j][i-1]) + rtengine::SQR(luminance[j+1][i] - luminance[j-1][i]) + + rtengine::SQR(luminance[j][i+2] - luminance[j][i-2]) + rtengine::SQR(luminance[j+2][i] - luminance[j-2][i])) * scale; + + blend[j][i] = amount * calcBlendFactor(contrast, contrastThreshold); + } + } + +#ifdef _OPENMP + #pragma omp single +#endif + { + // upper border + for(int j = 0; j < 2; ++j) { + for(int i = 2; i < W - 2; ++i) { + blend[j][i] = blend[2][i]; + } + } + // lower border + for(int j = H - 2; j < H; ++j) { + for(int i = 2; i < W - 2; ++i) { + blend[j][i] = blend[H-3][i]; + } + } + for(int j = 0; j < H; ++j) { + // left border + blend[j][0] = blend[j][1] = blend[j][2]; + // right border + blend[j][W - 2] = blend[j][W - 1] = blend[j][W - 3]; + } + } + + // blur blend mask to smooth transitions + gaussianBlur(blend, blend, W, H, 2.0); + } } } } From 0cafab38b675e67ee5d0a6891aa87777e6274cb2 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 23 Oct 2018 18:46:28 +0200 Subject: [PATCH 09/14] Disable adjuster reset button if adjuster auto button is enabled --- rtgui/adjuster.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rtgui/adjuster.cc b/rtgui/adjuster.cc index 3f12b0cfb..46aa3952b 100644 --- a/rtgui/adjuster.cc +++ b/rtgui/adjuster.cc @@ -239,10 +239,12 @@ void Adjuster::autoToggled () // Disable the slider and spin button spin->set_sensitive(false); slider->set_sensitive(false); + reset->set_sensitive(false); } else { // Enable the slider and spin button spin->set_sensitive(true); slider->set_sensitive(true); + reset->set_sensitive(true); } } @@ -471,10 +473,12 @@ void Adjuster::setAutoValue (bool a) // Disable the slider and spin button spin->set_sensitive(false); slider->set_sensitive(false); + reset->set_sensitive(false); } else { // Enable the slider and spin button spin->set_sensitive(true); slider->set_sensitive(true); + reset->set_sensitive(true); } } } From 392e00cd69832342a0cbff23691a39b1fc1a3743 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 23 Oct 2018 19:52:40 +0200 Subject: [PATCH 10/14] Dual demosaic auto contrast threshold: Use adjuster with auto button, #4866 --- rtdata/languages/default | 1 + rtengine/dual_demosaic_RT.cc | 2 +- rtengine/improccoordinator.cc | 6 +-- rtengine/rt_algo.cc | 2 +- rtgui/bayerprocess.cc | 74 ++++++++++++++++++----------------- rtgui/bayerprocess.h | 4 +- rtgui/xtransprocess.cc | 67 ++++++++++++++++++------------- rtgui/xtransprocess.h | 3 +- 8 files changed, 86 insertions(+), 73 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 0d87f7677..cc978ce92 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1818,6 +1818,7 @@ TP_RAW_DMETHOD_PROGRESSBAR;%1 demosaicing... TP_RAW_DMETHOD_PROGRESSBAR_REFINE;Demosaicing refinement... TP_RAW_DMETHOD_TOOLTIP;Note: IGV and LMMSE are dedicated to high ISO images to aid in noise reduction without leading to maze patterns, posterization or a washed-out look.\nPixel Shift is for Pentax/Sony Pixel Shift files. It falls back to AMaZE for non-Pixel Shift files. TP_RAW_DUALDEMOSAICAUTOCONTRAST;Auto threshold +TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP;If the check-box is checked (recommended), RawTherapee calculates an optimum value based on flat regions in the image.\nIf there is no flat region in the image or the image is too noisy, the value will be set to 0.\nTo set the value manually, uncheck the check-box first (reasonable values depend on the image). TP_RAW_DUALDEMOSAICCONTRAST;Contrast threshold TP_RAW_EAHD;EAHD TP_RAW_FALSECOLOR;False color suppression steps diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 1498f600c..4ffac9296 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -40,7 +40,7 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi { BENCHFUN - if (contrast == 0.f) { + if (contrast == 0.f && !autoContrast) { // contrast == 0.0 means only first demosaicer will be used if(isBayer) { if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4) ) { diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 6547c37b6..78c1a6a09 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -240,13 +240,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } bool autoContrast = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicAutoContrast : params.raw.xtranssensor.dualDemosaicAutoContrast; - double contrastThreshold = params.raw.bayersensor.dualDemosaicContrast; + double contrastThreshold = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicContrast : params.raw.xtranssensor.dualDemosaicContrast; imgsrc->demosaic(rp, autoContrast, contrastThreshold); //enabled demosaic - if (imgsrc->getSensorType() == ST_BAYER && bayerAutoContrastListener) { + if (imgsrc->getSensorType() == ST_BAYER && bayerAutoContrastListener && autoContrast) { bayerAutoContrastListener->autoContrastChanged(autoContrast ? contrastThreshold : -1.0); } - if (imgsrc->getSensorType() == ST_FUJI_XTRANS && xtransAutoContrastListener) { + if (imgsrc->getSensorType() == ST_FUJI_XTRANS && xtransAutoContrastListener && autoContrast) { xtransAutoContrastListener->autoContrastChanged(autoContrast ? contrastThreshold : -1.0); } diff --git a/rtengine/rt_algo.cc b/rtengine/rt_algo.cc index 4bdcc88a3..ae385508a 100644 --- a/rtengine/rt_algo.cc +++ b/rtengine/rt_algo.cc @@ -194,7 +194,7 @@ void findMinMaxPercentile(const float* data, size_t size, float minPrct, float& void buildBlendMask(float** luminance, float **blend, int W, int H, float &contrastThreshold, float amount, bool autoContrast) { - if(contrastThreshold == 0.f) { + if(contrastThreshold == 0.f && !autoContrast) { for(int j = 0; j < H; ++j) { for(int i = 0; i < W; ++i) { blend[j][i] = amount; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index f9b6ef9e5..3648c8f89 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -48,25 +48,16 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA pack_start( *hb1, Gtk::PACK_SHRINK, 4); dualDemosaicOptions = Gtk::manage(new Gtk::VBox()); - Gtk::HBox* hbAutoContrast = Gtk::manage(new Gtk::HBox()); - - dualDemosaicAutoContrast = Gtk::manage(new CheckBox(M("TP_RAW_DUALDEMOSAICAUTOCONTRAST"), multiImage)); - dualDemosaicAutoContrast->setCheckBoxListener(this); - - dualDemosaicLabel = Gtk::manage(new Gtk::Label("")); dualDemosaicContrast = Gtk::manage(new Adjuster(M("TP_RAW_DUALDEMOSAICCONTRAST"), 0, 100, 1, 20)); dualDemosaicContrast->setAdjusterListener(this); - + dualDemosaicContrast->addAutoButton(M("TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP")); + dualDemosaicContrast->setAutoValue(true); if (dualDemosaicContrast->delay < options.adjusterMaxDelay) { dualDemosaicContrast->delay = options.adjusterMaxDelay; } - dualDemosaicAutoContrast->show(); dualDemosaicContrast->show(); - hbAutoContrast->pack_start(*dualDemosaicAutoContrast); - hbAutoContrast->pack_start(*dualDemosaicLabel); - dualDemosaicOptions->pack_start(*hbAutoContrast); dualDemosaicOptions->pack_start(*dualDemosaicContrast); pack_start( *dualDemosaicOptions, Gtk::PACK_SHRINK, 4); @@ -310,11 +301,9 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftNonGreenCross->setValue (pp->raw.bayersensor.pixelShiftNonGreenCross); ccSteps->setValue (pp->raw.bayersensor.ccSteps); lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations); - dualDemosaicAutoContrast->setValue (pp->raw.bayersensor.dualDemosaicAutoContrast); + dualDemosaicContrast->setAutoValue(pp->raw.bayersensor.dualDemosaicAutoContrast); dualDemosaicContrast->setValue (pp->raw.bayersensor.dualDemosaicContrast); - if (!batchMode) { - dualDemosaicContrast->set_sensitive(!pp->raw.bayersensor.dualDemosaicAutoContrast); - } + pixelShiftMotionMethod->set_active ((int)pp->raw.bayersensor.pixelShiftMotionCorrectionMethod); pixelShiftEperIso->setValue (pp->raw.bayersensor.pixelShiftEperIso); pixelShiftSigma->setValue (pp->raw.bayersensor.pixelShiftSigma); @@ -338,8 +327,8 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params pixelShiftEqualBrightChannel->setEdited (pedited->raw.bayersensor.pixelShiftEqualBrightChannel); pixelShiftNonGreenCross->setEdited (pedited->raw.bayersensor.pixelShiftNonGreenCross); lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited); - dualDemosaicAutoContrast->setEdited ( pedited->raw.bayersensor.dualDemosaicAutoContrast ? Edited : UnEdited); dualDemosaicContrast->setEditedState ( pedited->raw.bayersensor.dualDemosaicContrast ? Edited : UnEdited); + dualDemosaicContrast->setAutoInconsistent (multiImage && !pedited->raw.bayersensor.dualDemosaicAutoContrast); pixelShiftEperIso->setEditedState ( pedited->raw.bayersensor.pixelShiftEperIso ? Edited : UnEdited); pixelShiftSigma->setEditedState ( pedited->raw.bayersensor.pixelShiftSigma ? Edited : UnEdited); @@ -360,6 +349,7 @@ void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const Params } } + lastAutoContrast = pp->raw.bayersensor.dualDemosaicAutoContrast; if (!batchMode) { dcbOptions->set_visible(pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCB) || pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4)); @@ -400,7 +390,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pp->raw.bayersensor.dcb_enhance = dcbEnhance->getLastActive (); pp->raw.bayersensor.border = border->getIntValue(); pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue(); - pp->raw.bayersensor.dualDemosaicAutoContrast = dualDemosaicAutoContrast->getLastActive (); + pp->raw.bayersensor.dualDemosaicAutoContrast = dualDemosaicContrast->getAutoValue(); pp->raw.bayersensor.dualDemosaicContrast = dualDemosaicContrast->getValue(); pp->raw.bayersensor.pixelShiftMotionCorrectionMethod = (RAWParams::BayerSensor::PSMotionCorrectionMethod)pixelShiftMotionMethod->get_active_row_number(); pp->raw.bayersensor.pixelShiftEperIso = pixelShiftEperIso->getValue(); @@ -441,7 +431,7 @@ void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pe pedited->raw.bayersensor.dcbEnhance = !dcbEnhance->get_inconsistent(); //pedited->raw.bayersensor.allEnhance = !allEnhance->get_inconsistent(); pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState (); - pedited->raw.bayersensor.dualDemosaicAutoContrast = !dualDemosaicAutoContrast->get_inconsistent(); + pedited->raw.bayersensor.dualDemosaicAutoContrast = !dualDemosaicContrast->getAutoInconsistent (); pedited->raw.bayersensor.dualDemosaicContrast = dualDemosaicContrast->getEditedState (); pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod = pixelShiftMotionMethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->raw.bayersensor.pixelShiftDemosaicMethod = pixelShiftDemosaicMethod->get_active_text() != M("GENERAL_UNCHANGED"); @@ -556,10 +546,6 @@ void BayerProcess::adjusterChanged (Adjuster* a, double newval) } } -void BayerProcess::adjusterAutoToggled(Adjuster* a, bool newval) -{ -} - void BayerProcess::methodChanged () { const int currentSelection = method->get_active_row_number(); @@ -624,14 +610,7 @@ void BayerProcess::imageNumberChanged () void BayerProcess::checkBoxToggled (CheckBox* c, CheckValue newval) { - if (c == dualDemosaicAutoContrast) { - if (!batchMode) { - dualDemosaicContrast->set_sensitive(newval == CheckValue::off); - } - if (listener) { - listener->panelChanged (EvDemosaicAutoContrast, dualDemosaicAutoContrast->getValueAsStr ()); - } - } else if (c == dcbEnhance) { + if (c == dcbEnhance) { if (listener) { listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->getValueAsStr ()); } @@ -684,6 +663,33 @@ void BayerProcess::checkBoxToggled (CheckBox* c, CheckValue newval) } } +void BayerProcess::adjusterAutoToggled(Adjuster* a, bool newval) +{ + if (multiImage) { + if (dualDemosaicContrast->getAutoInconsistent()) { + dualDemosaicContrast->setAutoInconsistent (false); + dualDemosaicContrast->setAutoValue (false); + } else if (lastAutoContrast) { + dualDemosaicContrast->setAutoInconsistent (true); + } + + lastAutoContrast = dualDemosaicContrast->getAutoValue(); + } + + if (listener) { + + if (a == dualDemosaicContrast) { + if (dualDemosaicContrast->getAutoInconsistent()) { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_UNCHANGED")); + } else if (dualDemosaicContrast->getAutoValue()) { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_DISABLED")); + } + } + } +} + void BayerProcess::pixelShiftMotionMethodChanged () { if (!batchMode) { @@ -750,11 +756,9 @@ void BayerProcess::autoContrastChanged (double autoContrast) const auto func = [](gpointer data) -> gboolean { Data *d = static_cast(data); BayerProcess *me = d->me; - if (d->autoContrast == -1.0) { - me->dualDemosaicLabel->set_text(""); - } else { - me->dualDemosaicLabel->set_text(Glib::ustring::format(std::fixed, std::setprecision(0), d->autoContrast)); - } + me->disableListener(); + me->dualDemosaicContrast->setValue(d->autoContrast); + me->enableListener(); return FALSE; }; diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index cde3270bb..d72d82cc4 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -59,10 +59,8 @@ protected: Adjuster* pixelShiftSigma; Gtk::VBox *dualDemosaicOptions; Adjuster* dualDemosaicContrast; - CheckBox* dualDemosaicAutoContrast; - Gtk::Label* dualDemosaicLabel; int oldMethod; - + bool lastAutoContrast; IdleRegister idle_register; rtengine::ProcEvent EvDemosaicBorder; diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 670ddccf3..1707b84ff 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -69,25 +69,17 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP pack_start( *hb1, Gtk::PACK_SHRINK, 4); dualDemosaicOptions = Gtk::manage (new Gtk::VBox ()); - Gtk::HBox* hbAutoContrast = Gtk::manage(new Gtk::HBox()); - - dualDemosaicAutoContrast = Gtk::manage(new CheckBox(M("TP_RAW_DUALDEMOSAICAUTOCONTRAST"), multiImage)); - dualDemosaicAutoContrast->setCheckBoxListener(this); - - dualDemosaicLabel = Gtk::manage(new Gtk::Label("")); dualDemosaicContrast = Gtk::manage(new Adjuster (M("TP_RAW_DUALDEMOSAICCONTRAST"), 0, 100, 1, 20)); dualDemosaicContrast->setAdjusterListener (this); + dualDemosaicContrast->addAutoButton(M("TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP")); + dualDemosaicContrast->setAutoValue(true); if (dualDemosaicContrast->delay < options.adjusterMaxDelay) { dualDemosaicContrast->delay = options.adjusterMaxDelay; } - dualDemosaicAutoContrast->show(); dualDemosaicContrast->show(); - hbAutoContrast->pack_start(*dualDemosaicAutoContrast); - hbAutoContrast->pack_start(*dualDemosaicLabel); - dualDemosaicOptions->pack_start(*hbAutoContrast); dualDemosaicOptions->pack_start(*dualDemosaicContrast); pack_start( *dualDemosaicOptions, Gtk::PACK_SHRINK, 4); @@ -119,7 +111,7 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param } if(pedited ) { - dualDemosaicAutoContrast->setEdited ( pedited->raw.xtranssensor.dualDemosaicAutoContrast ? Edited : UnEdited); + dualDemosaicContrast->setAutoInconsistent (multiImage && !pedited->raw.xtranssensor.dualDemosaicAutoContrast); dualDemosaicContrast->setEditedState ( pedited->raw.xtranssensor.dualDemosaicContrast ? Edited : UnEdited); ccSteps->setEditedState (pedited->raw.xtranssensor.ccSteps ? Edited : UnEdited); @@ -127,9 +119,12 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param method->set_active_text(M("GENERAL_UNCHANGED")); } } - dualDemosaicAutoContrast->setValue (pp->raw.xtranssensor.dualDemosaicAutoContrast); + dualDemosaicContrast->setAutoValue(pp->raw.xtranssensor.dualDemosaicAutoContrast); dualDemosaicContrast->setValue (pp->raw.xtranssensor.dualDemosaicContrast); ccSteps->setValue (pp->raw.xtranssensor.ccSteps); + + lastAutoContrast = pp->raw.bayersensor.dualDemosaicAutoContrast; + if (!batchMode) { dualDemosaicOptions->set_visible(pp->raw.xtranssensor.method == procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::FOUR_PASS) || pp->raw.xtranssensor.method == procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::TWO_PASS)); @@ -142,7 +137,7 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited) { - pp->raw.xtranssensor.dualDemosaicAutoContrast = dualDemosaicAutoContrast->getLastActive (); + pp->raw.xtranssensor.dualDemosaicAutoContrast = dualDemosaicContrast->getAutoValue(); pp->raw.xtranssensor.dualDemosaicContrast = dualDemosaicContrast->getValue(); pp->raw.xtranssensor.ccSteps = ccSteps->getIntValue(); @@ -154,7 +149,7 @@ void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* p if (pedited) { pedited->raw.xtranssensor.method = method->get_active_text() != M("GENERAL_UNCHANGED"); - pedited->raw.xtranssensor.dualDemosaicAutoContrast = !dualDemosaicAutoContrast->get_inconsistent(); + pedited->raw.xtranssensor.dualDemosaicAutoContrast = !dualDemosaicContrast->getAutoInconsistent (); pedited->raw.xtranssensor.dualDemosaicContrast = dualDemosaicContrast->getEditedState (); pedited->raw.xtranssensor.ccSteps = ccSteps->getEditedState (); } @@ -200,17 +195,31 @@ void XTransProcess::adjusterChanged(Adjuster* a, double newval) } } -void XTransProcess::checkBoxToggled (CheckBox* c, CheckValue newval) -{ - if (c == dualDemosaicAutoContrast) { - if (listener) { - listener->panelChanged (EvDemosaicAutoContrast, dualDemosaicAutoContrast->getValueAsStr ()); - } - } -} - void XTransProcess::adjusterAutoToggled(Adjuster* a, bool newval) { + if (multiImage) { + if (dualDemosaicContrast->getAutoInconsistent()) { + dualDemosaicContrast->setAutoInconsistent (false); + dualDemosaicContrast->setAutoValue (false); + } else if (lastAutoContrast) { + dualDemosaicContrast->setAutoInconsistent (true); + } + + lastAutoContrast = dualDemosaicContrast->getAutoValue(); + } + + if (listener) { + + if (a == dualDemosaicContrast) { + if (dualDemosaicContrast->getAutoInconsistent()) { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_UNCHANGED")); + } else if (dualDemosaicContrast->getAutoValue()) { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvDemosaicAutoContrast, M ("GENERAL_DISABLED")); + } + } + } } void XTransProcess::methodChanged () @@ -236,6 +245,10 @@ void XTransProcess::methodChanged () } } +void XTransProcess::checkBoxToggled (CheckBox* c, CheckValue newval) +{ +} + void XTransProcess::autoContrastChanged (double autoContrast) { struct Data { @@ -245,11 +258,9 @@ void XTransProcess::autoContrastChanged (double autoContrast) const auto func = [](gpointer data) -> gboolean { Data *d = static_cast(data); XTransProcess *me = d->me; - if (d->autoContrast == -1.0) { - me->dualDemosaicLabel->set_text(""); - } else { - me->dualDemosaicLabel->set_text(Glib::ustring::format(std::fixed, std::setprecision(0), d->autoContrast)); - } + me->disableListener(); + me->dualDemosaicContrast->setValue(d->autoContrast); + me->enableListener(); return FALSE; }; diff --git a/rtgui/xtransprocess.h b/rtgui/xtransprocess.h index a90a97326..9c958a10c 100644 --- a/rtgui/xtransprocess.h +++ b/rtgui/xtransprocess.h @@ -35,8 +35,7 @@ protected: Adjuster* ccSteps; Gtk::VBox *dualDemosaicOptions; Adjuster* dualDemosaicContrast; - CheckBox* dualDemosaicAutoContrast; - Gtk::Label* dualDemosaicLabel; + bool lastAutoContrast; int oldSelection; sigc::connection methodconn; From 4d46e618bb4cac9cbedcf56d321ef335396953af Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 23 Oct 2018 21:03:23 +0200 Subject: [PATCH 11/14] Calculate dual demosaic auto contrast threshold when saving file, #4866 --- rtengine/simpleprocess.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index fbee20f44..06e2b13bf 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -209,8 +209,10 @@ private: if (pl) { pl->setProgress (0.20); } - double contrastThresholdDummy; - imgsrc->demosaic (params.raw, false, contrastThresholdDummy); + bool autoContrast = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicAutoContrast : params.raw.xtranssensor.dualDemosaicAutoContrast; + double contrastThreshold = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicContrast : params.raw.xtranssensor.dualDemosaicContrast; + + imgsrc->demosaic (params.raw, autoContrast, contrastThreshold); if (pl) { From 96acd92a7c43c5cc2e89f52690b731fb363bc322 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Tue, 23 Oct 2018 21:10:01 +0200 Subject: [PATCH 12/14] Changes suggested by code review, #4890 --- rtengine/ipsharpen.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index a84132a4c..321dd635f 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -177,7 +177,7 @@ BENCHFUN // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); float contrast = sharpenParam.contrast / 100.f; - buildBlendMask(luminance, blend, W, H, contrast, sharpenParam.deconvamount / 100.0); + buildBlendMask(luminance, blend, W, H, contrast, sharpenParam.deconvamount / 100.f); const float damping = sharpenParam.deconvdamping / 5.0; const bool needdamp = sharpenParam.deconvdamping > 0; @@ -224,7 +224,7 @@ void ImProcFunctions::sharpening (LabImage* lab, const SharpeningParams &sharpen // calculate contrast based blend factors to reduce sharpening in regions with low contrast JaggedArray blend(W, H); float contrast = sharpenParam.contrast / 100.f; - buildBlendMask(lab->L, blend, W, H, contrast, sharpenParam.method == "rld" ? sharpenParam.deconvamount / 100.0 : 1.f); + buildBlendMask(lab->L, blend, W, H, contrast, sharpenParam.method == "rld" ? sharpenParam.deconvamount / 100.f : 1.f); #ifdef _OPENMP #pragma omp parallel for #endif From 7a1cc62d5c640834f17f161f71fa137b6fd4d890 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 24 Oct 2018 12:23:15 +0200 Subject: [PATCH 13/14] Fix two small memory leaks, #4866 --- rtgui/bayerprocess.cc | 1 + rtgui/xtransprocess.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 3648c8f89..7491d3896 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -759,6 +759,7 @@ void BayerProcess::autoContrastChanged (double autoContrast) me->disableListener(); me->dualDemosaicContrast->setValue(d->autoContrast); me->enableListener(); + delete d; return FALSE; }; diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 1707b84ff..1bb5303b0 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -261,6 +261,7 @@ void XTransProcess::autoContrastChanged (double autoContrast) me->disableListener(); me->dualDemosaicContrast->setValue(d->autoContrast); me->enableListener(); + delete d; return FALSE; }; From 15cedc3a3c2f6277f296b1f6633bb7f6dc9b5924 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 24 Oct 2018 12:49:38 +0200 Subject: [PATCH 14/14] call idle_register.deystroy() --- rtgui/bayerprocess.cc | 4 ++++ rtgui/bayerprocess.h | 1 + rtgui/xtransprocess.cc | 3 +++ rtgui/xtransprocess.h | 1 + 4 files changed, 9 insertions(+) diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 7491d3896..2a65a158e 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -251,6 +251,10 @@ BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RA } +BayerProcess::~BayerProcess () +{ + idle_register.destroy(); +} void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index d72d82cc4..b0974e7a4 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -70,6 +70,7 @@ protected: public: BayerProcess (); + ~BayerProcess (); void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 1bb5303b0..47556e54f 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -97,6 +97,9 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &XTransProcess::methodChanged) ); } +XTransProcess::~XTransProcess () { + idle_register.destroy(); +} void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { diff --git a/rtgui/xtransprocess.h b/rtgui/xtransprocess.h index 9c958a10c..7a706b1ac 100644 --- a/rtgui/xtransprocess.h +++ b/rtgui/xtransprocess.h @@ -46,6 +46,7 @@ protected: public: XTransProcess (); + ~XTransProcess (); void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr);