diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt
index c5c8afa82..f52cfa256 100644
--- a/rtengine/CMakeLists.txt
+++ b/rtengine/CMakeLists.txt
@@ -32,6 +32,7 @@ set(CAMCONSTSFILE "camconst.json")
set(RTENGINESOURCEFILES
badpixels.cc
CA_correct_RT.cc
+ capturesharpening.cc
EdgePreservingDecomposition.cc
FTblockDN.cc
PF_correct_RT.cc
diff --git a/rtengine/capturesharpening.cc b/rtengine/capturesharpening.cc
new file mode 100644
index 000000000..71cefaca6
--- /dev/null
+++ b/rtengine/capturesharpening.cc
@@ -0,0 +1,218 @@
+/*
+ * This file is part of RawTherapee.
+ *
+ * Copyright (c) 2019 Ingo Weyrich (heckflosse67@gmx.de)
+ *
+ * RawTherapee is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RawTherapee is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RawTherapee. If not, see .
+*/
+#include
+#include
+
+#include "jaggedarray.h"
+#include "rtengine.h"
+#include "rawimagesource.h"
+#include "rt_math.h"
+#include "improcfun.h"
+#include "procparams.h"
+#include "color.h"
+#include "gauss.h"
+#include "rt_algo.h"
+#define BENCHMARK
+#include "StopWatch.h"
+#ifdef _OPENMP
+#include
+#endif
+#include "opthelper.h"
+#include "../rtgui/multilangmgr.h"
+
+namespace {
+void CaptureDeconvSharpening (float** luminance, float** tmp, const float * const * blend, int W, int H, double sigma, int iterations, rtengine::ProgressListener* plistener, double start, double step)
+{
+
+ rtengine::JaggedArray tmpI(W, H);
+
+#ifdef _OPENMP
+ #pragma omp parallel
+#endif
+ {
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+ for (int i = 0; i < H; i++) {
+ for(int j = 0; j < W; j++) {
+ tmpI[i][j] = max(luminance[i][j], 0.f);
+ }
+ }
+
+ for (int k = 0; k < iterations; k++) {
+ // apply gaussian blur and divide luminance by result of gaussian blur
+ gaussianBlur(tmpI, tmp, W, H, sigma, nullptr, GAUSS_DIV, luminance);
+ gaussianBlur(tmp, tmpI, W, H, sigma, nullptr, GAUSS_MULT);
+ if (plistener) {
+#ifdef _OPENMP
+ #pragma omp single
+#endif
+ start += step;
+ plistener->setProgress(start);
+ }
+ } // end for
+
+#ifdef _OPENMP
+ #pragma omp for
+#endif
+
+ for (int i = 0; i < H; ++i) {
+ for (int j = 0; j < W; ++j) {
+ luminance[i][j] = rtengine::intp(blend[i][j], max(tmpI[i][j], 0.0f), luminance[i][j]);
+ }
+ }
+ } // end parallel
+}
+
+}
+
+namespace rtengine
+{
+
+void RawImageSource::captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold) {
+BENCHFUN
+
+
+ if (plistener) {
+ plistener->setProgressStr(M("TP_PDSHARPENING_LABEL"));
+ plistener->setProgress(0.0);
+ }
+
+ const float xyz_rgb[3][3] = { // XYZ from RGB
+ { 0.412453, 0.357580, 0.180423 },
+ { 0.212671, 0.715160, 0.072169 },
+ { 0.019334, 0.119193, 0.950227 }
+ };
+
+ float contrast = conrastThreshold / 100.f;
+
+ array2D& redVals = redCache ? *redCache : red;
+ array2D& greenVals = greenCache ? *greenCache : green;
+ array2D& blueVals = blueCache ? *blueCache : blue;
+
+ if (showMask) {
+ StopWatch Stop1("Show mask");
+ array2D& L = blue; // blue will be overridden anyway => we can use its buffer to store L
+#ifdef _OPENMP
+ #pragma omp parallel for
+#endif
+
+ for (int i = 0; i < H; ++i) {
+ Color::RGB2L(redVals[i], greenVals[i], blueVals[i], L[i], xyz_rgb, W);
+ }
+ if (plistener) {
+ plistener->setProgress(0.1);
+ }
+ array2D& blend = red; // red will be overridden anyway => we can use its buffer to store the blend mask
+ buildBlendMask(L, blend, W, H, contrast, 1.f, sharpeningParams.autoContrast);
+ if (plistener) {
+ plistener->setProgress(0.2);
+ }
+ conrastThreshold = contrast * 100.f;
+#ifdef _OPENMP
+ #pragma omp parallel for
+#endif
+ for (int i = 0; i < H; ++i) {
+ for (int j = 0; j < W; ++j) {
+ red[i][j] = green[i][j] = blue[i][j] = blend[i][j] * 16384.f;
+ }
+ }
+ if (plistener) {
+ plistener->setProgress(1.0);
+ }
+ return;
+ }
+
+ array2D* Lbuffer = nullptr;
+ if (!redCache) {
+ Lbuffer = new array2D(W, H);
+ }
+
+ array2D* YOldbuffer = nullptr;
+ if (!greenCache) {
+ YOldbuffer = new array2D(W, H);
+ }
+
+ array2D* YNewbuffer = nullptr;
+ if (!blueCache) {
+ YNewbuffer = new array2D(W, H);
+ }
+ array2D& L = Lbuffer ? *Lbuffer : red;
+ array2D& YOld = YOldbuffer ? * YOldbuffer : green;
+ array2D& YNew = YNewbuffer ? * YNewbuffer : blue;
+
+ StopWatch Stop1("rgb2YL");
+#ifdef _OPENMP
+ #pragma omp parallel for schedule(dynamic, 16)
+#endif
+ for (int i = 0; i < H; ++i) {
+ Color::RGB2L(redVals[i], greenVals[i], blueVals[i], L[i], xyz_rgb, W);
+ Color::RGB2Y(redVals[i], greenVals[i], blueVals[i], YOld[i], YNew[i], sharpeningParams.gamma, W);
+ }
+ if (plistener) {
+ plistener->setProgress(0.1);
+ }
+ // calculate contrast based blend factors to reduce sharpening in regions with low contrast
+ JaggedArray blend(W, H);
+ buildBlendMask(L, blend, W, H, contrast, 1.f, sharpeningParams.autoContrast);
+ if (plistener) {
+ plistener->setProgress(0.2);
+ }
+ conrastThreshold = contrast * 100.f;
+
+ Stop1.stop();
+ array2D& tmp = L; // L is not used anymore now => we can use its buffer as the needed temporary buffer
+ CaptureDeconvSharpening(YNew, tmp, blend, W, H, sharpeningParams.deconvradius, sharpeningParams.deconviter, plistener, 0.2, (0.9 - 0.2) / sharpeningParams.deconviter);
+ if (plistener) {
+ plistener->setProgress(0.9);
+ }
+ StopWatch Stop2("Y2RGB");
+ const float gamma = sharpeningParams.gamma;
+#ifdef _OPENMP
+ #pragma omp parallel for schedule(dynamic, 16)
+#endif
+ for (int i = 0; i < H; ++i) {
+ int j = 0;
+#ifdef __SSE2__
+ const vfloat gammav = F2V(gamma);
+ for (; j < W - 3; j += 4) {
+ const vfloat factor = pow_F(LVFU(YNew[i][j]) / vmaxf(LVFU(YOld[i][j]), F2V(0.00001f)), gammav);
+ STVFU(red[i][j], LVFU(redVals[i][j]) * factor);
+ STVFU(green[i][j], LVFU(greenVals[i][j]) * factor);
+ STVFU(blue[i][j], LVFU(blueVals[i][j]) * factor);
+ }
+
+#endif
+ for (; j < W; ++j) {
+ const float factor = pow_F(YNew[i][j] / std::max(YOld[i][j], 0.00001f), gamma);
+ red[i][j] = redVals[i][j] * factor;
+ green[i][j] = greenVals[i][j] * factor;
+ blue[i][j] = blueVals[i][j] * factor;
+ }
+ }
+ Stop2.stop();
+ delete Lbuffer;
+ delete YOldbuffer;
+ delete YNewbuffer;
+ if (plistener) {
+ plistener->setProgress(1.0);
+ }
+}
+
+} /* namespace */
diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h
index 1a5469744..64bb53a49 100644
--- a/rtengine/imagesource.h
+++ b/rtengine/imagesource.h
@@ -46,7 +46,7 @@ struct LensProfParams;
struct RAWParams;
struct RetinexParams;
struct ToneCurveParams;
-struct SharpeningParams;
+struct CaptureSharpeningParams;
}
class ImageMatrices
@@ -182,7 +182,7 @@ public:
return this;
}
virtual void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) = 0;
- virtual void captureSharpening(const procparams::SharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold) = 0;
+ virtual void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold) = 0;
};
}
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index 60b95a2e8..d88892a3b 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -1149,6 +1149,32 @@ bool SharpeningParams::operator !=(const SharpeningParams& other) const
return !(*this == other);
}
+CaptureSharpeningParams::CaptureSharpeningParams() :
+ enabled(false),
+ autoContrast(true),
+ contrast(10.0),
+ gamma(1.35),
+ deconvradius(0.75),
+ deconviter(30)
+{
+}
+
+bool CaptureSharpeningParams::operator ==(const CaptureSharpeningParams& other) const
+{
+ return
+ enabled == other.enabled
+ && contrast == other.contrast
+ && gamma == other.gamma
+ && autoContrast == other.autoContrast
+ && deconvradius == other.deconvradius
+ && deconviter == other.deconviter;
+}
+
+bool CaptureSharpeningParams::operator !=(const CaptureSharpeningParams& other) const
+{
+ return !(*this == other);
+}
+
SharpenEdgeParams::SharpenEdgeParams() :
enabled(false),
passes(2),
@@ -2830,12 +2856,6 @@ void ProcParams::setDefaults()
prsharpening.deconvdamping = 0;
pdsharpening = {};
- pdsharpening.contrast = 10.0;
- pdsharpening.autoContrast = true;
- prsharpening.method = "rld";
- pdsharpening.gamma = 1.35;
- pdsharpening.deconvradius = 0.75;
- pdsharpening.deconviter = 30;
vibrance = {};
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index 4be6de254..cbcec0e18 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -542,6 +542,20 @@ struct SharpenMicroParams {
bool operator !=(const SharpenMicroParams& other) const;
};
+struct CaptureSharpeningParams {
+ bool enabled;
+ bool autoContrast;
+ double contrast;
+ double gamma;
+ double deconvradius;
+ int deconviter;
+
+ CaptureSharpeningParams();
+
+ bool operator ==(const CaptureSharpeningParams& other) const;
+ bool operator !=(const CaptureSharpeningParams& other) const;
+};
+
/**
* Parameters of the vibrance
*/
@@ -1530,7 +1544,7 @@ public:
ColorToningParams colorToning; ///< Color Toning parameters
SharpeningParams sharpening; ///< Sharpening parameters
SharpeningParams prsharpening; ///< Sharpening parameters for post resize sharpening
- SharpeningParams pdsharpening; ///< Sharpening parameters for post demosaic sharpening
+ CaptureSharpeningParams pdsharpening; ///< Sharpening parameters for post demosaic sharpening
SharpenEdgeParams sharpenEdge; ///< Sharpen edge parameters
SharpenMicroParams sharpenMicro; ///< Sharpen microcontrast parameters
VibranceParams vibrance; ///< Vibrance parameters
diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc
index 2b45bfe38..931a46ede 100644
--- a/rtengine/rawimagesource.cc
+++ b/rtengine/rawimagesource.cc
@@ -38,14 +38,12 @@
#include "camconst.h"
#include "procparams.h"
#include "color.h"
-#include "rt_algo.h"
-#define BENCHMARK
-#include "StopWatch.h"
+//#define BENCHMARK
+//#include "StopWatch.h"
#ifdef _OPENMP
#include
#endif
#include "opthelper.h"
-#include "../rtgui/multilangmgr.h"
#define clipretinex( val, minv, maxv ) (( val = (val < minv ? minv : val ) ) > maxv ? maxv : val )
#undef CLIPD
#define CLIPD(a) ((a)>0.0f?((a)<1.0f?(a):1.0f):0.0f)
@@ -5000,138 +4998,6 @@ void RawImageSource::getRawValues(int x, int y, int rotate, int &R, int &G, int
}
}
-void RawImageSource::captureSharpening(const procparams::SharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold) {
-BENCHFUN
-
-
- if (plistener) {
- plistener->setProgressStr(M("TP_PDSHARPENING_LABEL"));
- plistener->setProgress(0.0);
- }
-
- const float xyz_rgb[3][3] = { // XYZ from RGB
- { 0.412453, 0.357580, 0.180423 },
- { 0.212671, 0.715160, 0.072169 },
- { 0.019334, 0.119193, 0.950227 }
- };
-
- float contrast = conrastThreshold / 100.f;
-
- array2D& redVals = redCache ? *redCache : red;
- array2D& greenVals = greenCache ? *greenCache : green;
- array2D& blueVals = blueCache ? *blueCache : blue;
-
- if (showMask) {
- StopWatch Stop1("Show mask");
- array2D& L = blue; // blue will be overridden anyway => we can use its buffer to store L
-#ifdef _OPENMP
- #pragma omp parallel for
-#endif
-
- for (int i = 0; i < H; ++i) {
- Color::RGB2L(redVals[i], greenVals[i], blueVals[i], L[i], xyz_rgb, W);
- }
- if (plistener) {
- plistener->setProgress(0.1);
- }
- array2D& blend = red; // red will be overridden anyway => we can use its buffer to store the blend mask
- buildBlendMask(L, blend, W, H, contrast, 1.f, sharpeningParams.autoContrast);
- if (plistener) {
- plistener->setProgress(0.2);
- }
- conrastThreshold = contrast * 100.f;
-#ifdef _OPENMP
- #pragma omp parallel for
-#endif
- for (int i = 0; i < H; ++i) {
- for (int j = 0; j < W; ++j) {
- red[i][j] = green[i][j] = blue[i][j] = blend[i][j] * 16384.f;
- }
- }
- if (plistener) {
- plistener->setProgress(1.0);
- }
- return;
- }
-
- array2D* Lbuffer = nullptr;
- if (!redCache) {
- Lbuffer = new array2D(W, H);
- }
-
- array2D* YOldbuffer = nullptr;
- if (!greenCache) {
- YOldbuffer = new array2D(W, H);
- }
-
- array2D* YNewbuffer = nullptr;
- if (!blueCache) {
- YNewbuffer = new array2D(W, H);
- }
- array2D& L = Lbuffer ? *Lbuffer : red;
- array2D& YOld = YOldbuffer ? * YOldbuffer : green;
- array2D& YNew = YNewbuffer ? * YNewbuffer : blue;
-
- StopWatch Stop1("rgb2YL");
-#ifdef _OPENMP
- #pragma omp parallel for schedule(dynamic, 16)
-#endif
- for (int i = 0; i < H; ++i) {
- Color::RGB2L(redVals[i], greenVals[i], blueVals[i], L[i], xyz_rgb, W);
- Color::RGB2Y(redVals[i], greenVals[i], blueVals[i], YOld[i], YNew[i], sharpeningParams.gamma, W);
- }
- if (plistener) {
- plistener->setProgress(0.1);
- }
- // calculate contrast based blend factors to reduce sharpening in regions with low contrast
- JaggedArray blend(W, H);
- buildBlendMask(L, blend, W, H, contrast, 1.f, sharpeningParams.autoContrast);
- if (plistener) {
- plistener->setProgress(0.2);
- }
- conrastThreshold = contrast * 100.f;
-
- Stop1.stop();
- array2D& tmp = L; // L is not used anymore now => we can use its buffer as the needed temporary buffer
- ProcParams dummy;
- ImProcFunctions ipf(&dummy);
- ipf.deconvsharpening(YNew, tmp, blend, W, H, sharpeningParams, 1.0);
- if (plistener) {
- plistener->setProgress(0.9);
- }
- StopWatch Stop2("Y2RGB");
- const float gamma = sharpeningParams.gamma;
-#ifdef _OPENMP
- #pragma omp parallel for schedule(dynamic, 16)
-#endif
- for (int i = 0; i < H; ++i) {
- int j = 0;
-#ifdef __SSE2__
- const vfloat gammav = F2V(gamma);
- for (; j < W - 3; j += 4) {
- const vfloat factor = pow_F(LVFU(YNew[i][j]) / vmaxf(LVFU(YOld[i][j]), F2V(0.00001f)), gammav);
- STVFU(red[i][j], LVFU(redVals[i][j]) * factor);
- STVFU(green[i][j], LVFU(greenVals[i][j]) * factor);
- STVFU(blue[i][j], LVFU(blueVals[i][j]) * factor);
- }
-
-#endif
- for (; j < W; ++j) {
- const float factor = pow_F(YNew[i][j] / std::max(YOld[i][j], 0.00001f), gamma);
- red[i][j] = redVals[i][j] * factor;
- green[i][j] = greenVals[i][j] * factor;
- blue[i][j] = blueVals[i][j] * factor;
- }
- }
- Stop2.stop();
- delete Lbuffer;
- delete YOldbuffer;
- delete YNewbuffer;
- if (plistener) {
- plistener->setProgress(1.0);
- }
-}
-
void RawImageSource::cleanup ()
{
delete phaseOneIccCurve;
diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h
index bbc15c448..5e1c9b424 100644
--- a/rtengine/rawimagesource.h
+++ b/rtengine/rawimagesource.h
@@ -311,7 +311,7 @@ protected:
void hflip (Imagefloat* im);
void vflip (Imagefloat* im);
void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override;
- void captureSharpening(const procparams::SharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold) override;
+ void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold) override;
};
}
diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h
index 175f664f8..6b4a67773 100644
--- a/rtengine/stdimagesource.h
+++ b/rtengine/stdimagesource.h
@@ -102,7 +102,7 @@ public:
void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override { R = G = B = 0;}
void flushRGB () override;
- void captureSharpening(const procparams::SharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold) override {};
+ void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold) override {};
};
}
#endif
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index 4029d0b9b..db0c24123 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -169,7 +169,6 @@ void ParamsEdited::set(bool v)
pdsharpening.contrast = v;
pdsharpening.autoContrast = v;
pdsharpening.gamma = v;
- pdsharpening.deconvamount = v;
pdsharpening.deconvradius = v;
pdsharpening.deconviter = v;
prsharpening.enabled = v;
@@ -1733,10 +1732,6 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
toEdit.pdsharpening.autoContrast = mods.pdsharpening.autoContrast;
}
- if (pdsharpening.deconvamount) {
- toEdit.pdsharpening.deconvamount = dontforceSet && options.baBehav[ADDSET_SHARP_AMOUNT] ? toEdit.pdsharpening.deconvamount + mods.pdsharpening.deconvamount : mods.pdsharpening.deconvamount;
- }
-
if (pdsharpening.gamma) {
toEdit.pdsharpening.gamma = dontforceSet && options.baBehav[ADDSET_SHARP_GAMMA] ? toEdit.pdsharpening.gamma + mods.pdsharpening.gamma : mods.pdsharpening.gamma;
}
@@ -3292,7 +3287,7 @@ bool FilmNegativeParamsEdited::isUnchanged() const
return enabled && redRatio && greenExp && blueRatio;
}
-bool SharpeningParamsEdited::isUnchanged() const
+bool CaptureSharpeningParamsEdited::isUnchanged() const
{
return enabled && contrast && autoContrast && gamma && deconvradius && deconviter;
}
\ No newline at end of file
diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h
index 6d229e689..c697aaacd 100644
--- a/rtgui/paramsedited.h
+++ b/rtgui/paramsedited.h
@@ -196,6 +196,15 @@ struct SharpeningParamsEdited {
bool deconvradius;
bool deconviter;
bool deconvdamping;
+};
+
+struct CaptureSharpeningParamsEdited {
+ bool enabled;
+ bool contrast;
+ bool autoContrast;
+ bool gamma;
+ bool deconvradius;
+ bool deconviter;
bool isUnchanged() const;
};
@@ -687,7 +696,7 @@ struct ParamsEdited {
ColorToningEdited colorToning;
RetinexParamsEdited retinex;
SharpeningParamsEdited sharpening;
- SharpeningParamsEdited pdsharpening;
+ CaptureSharpeningParamsEdited pdsharpening;
SharpeningParamsEdited prsharpening;
SharpenEdgeParamsEdited sharpenEdge;
SharpenMicroParamsEdited sharpenMicro;