Port tone equalizer from ART
Merge with local adjustments tone equalizer image processing function for consistent results. To-do: Enable for batch editing and add pivot/colormap to the local adjustments version.
This commit is contained in:
parent
b989c271d8
commit
bd3bd809b5
@ -1520,6 +1520,11 @@ HISTORY_MSG_SPOT_ENTRY;Spot removal - Point modif.
|
|||||||
HISTORY_MSG_TEMPOUT;CAM02 automatic temperature
|
HISTORY_MSG_TEMPOUT;CAM02 automatic temperature
|
||||||
HISTORY_MSG_THRESWAV;Balance threshold
|
HISTORY_MSG_THRESWAV;Balance threshold
|
||||||
HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - Anchor
|
HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - Anchor
|
||||||
|
HISTORY_MSG_TONE_EQUALIZER_BANDS;Tone equalizer - Bands
|
||||||
|
HISTORY_MSG_TONE_EQUALIZER_ENABLED;Tone equalizer
|
||||||
|
HISTORY_MSG_TONE_EQUALIZER_PIVOT;Tone equalizer - Pivot
|
||||||
|
HISTORY_MSG_TONE_EQUALIZER_REGULARIZATION;Tone equalizer - Regularization
|
||||||
|
HISTORY_MSG_TONE_EQUALIZER_SHOW_COLOR_MAP;Tone equalizer - Tonal map
|
||||||
HISTORY_MSG_TRANS_METHOD;Geometry - Method
|
HISTORY_MSG_TRANS_METHOD;Geometry - Method
|
||||||
HISTORY_MSG_WAVBALCHROM;Equalizer chrominance
|
HISTORY_MSG_WAVBALCHROM;Equalizer chrominance
|
||||||
HISTORY_MSG_WAVBALLUM;Equalizer luminance
|
HISTORY_MSG_WAVBALLUM;Equalizer luminance
|
||||||
@ -1827,6 +1832,7 @@ PARTIALPASTE_SHARPENMICRO;Microcontrast
|
|||||||
PARTIALPASTE_SOFTLIGHT;Soft light
|
PARTIALPASTE_SOFTLIGHT;Soft light
|
||||||
PARTIALPASTE_SPOT;Spot removal
|
PARTIALPASTE_SPOT;Spot removal
|
||||||
PARTIALPASTE_TM_FATTAL;Dynamic range compression
|
PARTIALPASTE_TM_FATTAL;Dynamic range compression
|
||||||
|
PARTIALPASTE_TONE_EQUALIZER;Tone equalizer
|
||||||
PARTIALPASTE_VIBRANCE;Vibrance
|
PARTIALPASTE_VIBRANCE;Vibrance
|
||||||
PARTIALPASTE_VIGNETTING;Vignetting correction
|
PARTIALPASTE_VIGNETTING;Vignetting correction
|
||||||
PARTIALPASTE_WHITEBALANCE;White balance
|
PARTIALPASTE_WHITEBALANCE;White balance
|
||||||
@ -3837,6 +3843,15 @@ TP_TM_FATTAL_AMOUNT;Amount
|
|||||||
TP_TM_FATTAL_ANCHOR;Anchor
|
TP_TM_FATTAL_ANCHOR;Anchor
|
||||||
TP_TM_FATTAL_LABEL;Dynamic Range Compression
|
TP_TM_FATTAL_LABEL;Dynamic Range Compression
|
||||||
TP_TM_FATTAL_THRESHOLD;Detail
|
TP_TM_FATTAL_THRESHOLD;Detail
|
||||||
|
TP_TONE_EQUALIZER_BAND_0;Blacks
|
||||||
|
TP_TONE_EQUALIZER_BAND_1;Shadows
|
||||||
|
TP_TONE_EQUALIZER_BAND_2;Midtones
|
||||||
|
TP_TONE_EQUALIZER_BAND_3;Highlights
|
||||||
|
TP_TONE_EQUALIZER_BAND_4;Whites
|
||||||
|
TP_TONE_EQUALIZER_DETAIL;Regularization
|
||||||
|
TP_TONE_EQUALIZER_LABEL;Tone Equalizer
|
||||||
|
TP_TONE_EQUALIZER_PIVOT;Pivot (Ev)
|
||||||
|
TP_TONE_EQUALIZER_SHOW_COLOR_MAP;Show tonal map
|
||||||
TP_VIBRANCE_AVOIDCOLORSHIFT;Avoid color shift
|
TP_VIBRANCE_AVOIDCOLORSHIFT;Avoid color shift
|
||||||
TP_VIBRANCE_CURVEEDITOR_SKINTONES;HH
|
TP_VIBRANCE_CURVEEDITOR_SKINTONES;HH
|
||||||
TP_VIBRANCE_CURVEEDITOR_SKINTONES_LABEL;Skin-tones
|
TP_VIBRANCE_CURVEEDITOR_SKINTONES_LABEL;Skin-tones
|
||||||
|
@ -133,6 +133,7 @@ set(RTENGINESOURCEFILES
|
|||||||
ipsharpen.cc
|
ipsharpen.cc
|
||||||
ipsharpenedges.cc
|
ipsharpenedges.cc
|
||||||
ipsoftlight.cc
|
ipsoftlight.cc
|
||||||
|
iptoneequalizer.cc
|
||||||
iptransform.cc
|
iptransform.cc
|
||||||
ipvibrance.cc
|
ipvibrance.cc
|
||||||
ipwavelet.cc
|
ipwavelet.cc
|
||||||
|
@ -341,6 +341,38 @@ void Imagefloat::getStdImage (const ColorTemp &ctemp, int tran, Imagefloat* imag
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From ART.
|
||||||
|
void Imagefloat::multiply(float factor, bool multithread)
|
||||||
|
{
|
||||||
|
const int W = width;
|
||||||
|
const int H = height;
|
||||||
|
#ifdef __SSE2__
|
||||||
|
vfloat vfactor = F2V(factor);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
|
# pragma omp parallel for firstprivate(W, H) schedule(dynamic, 5) if (multithread)
|
||||||
|
#endif
|
||||||
|
for (int y = 0; y < H; y++) {
|
||||||
|
int x = 0;
|
||||||
|
#ifdef __SSE2__
|
||||||
|
for (; x < W-3; x += 4) {
|
||||||
|
vfloat rv = LVF(r(y, x));
|
||||||
|
vfloat gv = LVF(g(y, x));
|
||||||
|
vfloat bv = LVF(b(y, x));
|
||||||
|
STVF(r(y, x), rv * vfactor);
|
||||||
|
STVF(g(y, x), gv * vfactor);
|
||||||
|
STVF(b(y, x), bv * vfactor);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (; x < W; ++x) {
|
||||||
|
r(y, x) *= factor;
|
||||||
|
g(y, x) *= factor;
|
||||||
|
b(y, x) *= factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Imagefloat::normalizeFloat(float srcMinVal, float srcMaxVal)
|
void Imagefloat::normalizeFloat(float srcMinVal, float srcMaxVal)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -362,43 +394,15 @@ void Imagefloat::normalizeFloat(float srcMinVal, float srcMaxVal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convert values's range to [0;1] ; this method assumes that the input values's range is [0;65535]
|
// convert values's range to [0;1] ; this method assumes that the input values's range is [0;65535]
|
||||||
void Imagefloat::normalizeFloatTo1()
|
void Imagefloat::normalizeFloatTo1(bool multithread)
|
||||||
{
|
{
|
||||||
|
multiply(1.f/65535.f, multithread);
|
||||||
const int w = width;
|
|
||||||
const int h = height;
|
|
||||||
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#pragma omp parallel for schedule(dynamic, 5)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (int y = 0; y < h; y++) {
|
|
||||||
for (int x = 0; x < w; x++) {
|
|
||||||
r(y, x) /= 65535.f;
|
|
||||||
g(y, x) /= 65535.f;
|
|
||||||
b(y, x) /= 65535.f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert values's range to [0;65535 ; this method assumes that the input values's range is [0;1]
|
// convert values's range to [0;65535 ; this method assumes that the input values's range is [0;1]
|
||||||
void Imagefloat::normalizeFloatTo65535()
|
void Imagefloat::normalizeFloatTo65535(bool multithread)
|
||||||
{
|
{
|
||||||
|
multiply(65535.f, multithread);
|
||||||
const int w = width;
|
|
||||||
const int h = height;
|
|
||||||
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#pragma omp parallel for schedule(dynamic, 5)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (int y = 0; y < h; y++) {
|
|
||||||
for (int x = 0; x < w; x++) {
|
|
||||||
r(y, x) *= 65535.f;
|
|
||||||
g(y, x) *= 65535.f;
|
|
||||||
b(y, x) *= 65535.f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parallelized transformation; create transform with cmsFLAGS_NOCACHE!
|
// Parallelized transformation; create transform with cmsFLAGS_NOCACHE!
|
||||||
|
@ -207,9 +207,10 @@ public:
|
|||||||
return (uint32_t) ((lsign << 31) | (exponent << 23) | mantissa);
|
return (uint32_t) ((lsign << 31) | (exponent << 23) | mantissa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void multiply(float factor, bool multithread);
|
||||||
void normalizeFloat(float srcMinVal, float srcMaxVal) override;
|
void normalizeFloat(float srcMinVal, float srcMaxVal) override;
|
||||||
void normalizeFloatTo1();
|
void normalizeFloatTo1(bool multithread=true);
|
||||||
void normalizeFloatTo65535();
|
void normalizeFloatTo65535(bool multithread=true);
|
||||||
void ExecCMSTransform(cmsHTRANSFORM hTransform);
|
void ExecCMSTransform(cmsHTRANSFORM hTransform);
|
||||||
void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy);
|
void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy);
|
||||||
};
|
};
|
||||||
|
@ -2734,6 +2734,7 @@ void ImProcCoordinator::process()
|
|||||||
|| params->epd != nextParams->epd
|
|| params->epd != nextParams->epd
|
||||||
|| params->fattal != nextParams->fattal
|
|| params->fattal != nextParams->fattal
|
||||||
|| params->sh != nextParams->sh
|
|| params->sh != nextParams->sh
|
||||||
|
|| params->toneEqualizer != nextParams->toneEqualizer
|
||||||
|| params->crop != nextParams->crop
|
|| params->crop != nextParams->crop
|
||||||
|| params->coarse != nextParams->coarse
|
|| params->coarse != nextParams->coarse
|
||||||
|| params->commonTrans != nextParams->commonTrans
|
|| params->commonTrans != nextParams->commonTrans
|
||||||
|
@ -2258,6 +2258,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer
|
|||||||
// For tonecurve histogram
|
// For tonecurve histogram
|
||||||
const float lumimulf[3] = {static_cast<float>(lumimul[0]), static_cast<float>(lumimul[1]), static_cast<float>(lumimul[2])};
|
const float lumimulf[3] = {static_cast<float>(lumimul[0]), static_cast<float>(lumimul[1]), static_cast<float>(lumimul[2])};
|
||||||
|
|
||||||
|
std::unique_ptr<Imagefloat> workimg_copy;
|
||||||
|
if (params->toneEqualizer.enabled) {
|
||||||
|
working = working->copy();
|
||||||
|
workimg_copy.reset(working);
|
||||||
|
toneEqualizer(working);
|
||||||
|
}
|
||||||
|
|
||||||
#define TS 112
|
#define TS 112
|
||||||
|
|
||||||
|
@ -97,6 +97,7 @@ struct LocalContrastParams;
|
|||||||
struct LocallabParams;
|
struct LocallabParams;
|
||||||
struct SharpeningParams;
|
struct SharpeningParams;
|
||||||
struct SoftLightParams;
|
struct SoftLightParams;
|
||||||
|
struct ToneEqualizerParams;
|
||||||
struct VibranceParams;
|
struct VibranceParams;
|
||||||
struct VignettingParams;
|
struct VignettingParams;
|
||||||
struct WaveletParams;
|
struct WaveletParams;
|
||||||
@ -491,7 +492,8 @@ enum class BlurType {
|
|||||||
void colorToningLabGrid(LabImage *lab, int xstart, int xend, int ystart, int yend, bool MultiThread);
|
void colorToningLabGrid(LabImage *lab, int xstart, int xend, int ystart, int yend, bool MultiThread);
|
||||||
//void shadowsHighlights(LabImage *lab);
|
//void shadowsHighlights(LabImage *lab);
|
||||||
void shadowsHighlights(LabImage *lab, bool ena, int labmode, int hightli, int shado, int rad, int scal, int hltonal, int shtonal);
|
void shadowsHighlights(LabImage *lab, bool ena, int labmode, int hightli, int shado, int rad, int scal, int hltonal, int shtonal);
|
||||||
|
bool toneEqualizer(Imagefloat *rgb);
|
||||||
|
static void toneEqualizer(array2D<float> &R, array2D<float> &G, array2D<float> &B, const procparams::ToneEqualizerParams & params, const Glib::ustring &workingProfile, double scale, bool multithread, bool show_color_map);
|
||||||
void softLight(LabImage *lab, const procparams::SoftLightParams &softLightParams);
|
void softLight(LabImage *lab, const procparams::SoftLightParams &softLightParams);
|
||||||
void labColorCorrectionRegions(LabImage *lab);
|
void labColorCorrectionRegions(LabImage *lab);
|
||||||
|
|
||||||
|
@ -2258,230 +2258,11 @@ void ImProcFunctions::getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void tone_eq(array2D<float> &R, array2D<float> &G, array2D<float> &B, const struct local_params & lp, const Glib::ustring &workingProfile, double scale, bool multithread)
|
void tone_eq(array2D<float> &R, array2D<float> &G, array2D<float> &B, const struct local_params & lp, const Glib::ustring &workingProfile, double scale, bool multithread)
|
||||||
// adapted from the tone equalizer of darktable
|
|
||||||
/*
|
|
||||||
Copyright 2019 Alberto Griggio <alberto.griggio@gmail.com>
|
|
||||||
Small adaptation to Local Adjustment 10 2019 Jacques Desmis <jdesmis@gmail.com>
|
|
||||||
This file is part of darktable,
|
|
||||||
copyright (c) 2018 Aurelien Pierre.
|
|
||||||
|
|
||||||
darktable 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.
|
|
||||||
|
|
||||||
darktable 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 darktable. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// BENCHFUN
|
ToneEqualizerParams params;
|
||||||
|
params.regularization = lp.detailsh;
|
||||||
const int W = R.getWidth();
|
std::copy(lp.mullocsh, lp.mullocsh + params.bands.size(), params.bands.begin());
|
||||||
const int H = R.getHeight();
|
ImProcFunctions::toneEqualizer(R, G, B, params, workingProfile, scale, multithread, false);
|
||||||
array2D<float> Y(W, H);
|
|
||||||
|
|
||||||
const auto log2 =
|
|
||||||
[](float x) -> float {
|
|
||||||
static const float l2 = xlogf(2);
|
|
||||||
return xlogf(x) / l2;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto exp2 =
|
|
||||||
[](float x) -> float {
|
|
||||||
return pow_F(2.f, x);
|
|
||||||
};
|
|
||||||
// Build the luma channels: band-pass filters with gaussian windows of
|
|
||||||
// std 2 EV, spaced by 2 EV
|
|
||||||
const float centers[12] = {
|
|
||||||
-18.0f, -16.0f, -14.0f, -12.0f, -10.0f, -8.0f, -6.0f,
|
|
||||||
-4.0f, -2.0f, 0.0f, 2.0f, 4.0f
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto conv = [&](int v, float lo, float hi) -> float {
|
|
||||||
const float f = v < 0 ? lo : hi;
|
|
||||||
return exp2(float(v) / 100.f * f);
|
|
||||||
};
|
|
||||||
const float factors[12] = {
|
|
||||||
conv(lp.mullocsh[0], 2.f, 3.f), // -18 EV
|
|
||||||
conv(lp.mullocsh[0], 2.f, 3.f), // -16 EV
|
|
||||||
conv(lp.mullocsh[0], 2.f, 3.f), // -14 EV
|
|
||||||
conv(lp.mullocsh[0], 2.f, 3.f), // -12 EV
|
|
||||||
conv(lp.mullocsh[0], 2.f, 3.f), // -10 EV
|
|
||||||
conv(lp.mullocsh[0], 2.f, 3.f), // -8 EV
|
|
||||||
conv(lp.mullocsh[1], 2.f, 3.f), // -6 EV
|
|
||||||
conv(lp.mullocsh[2], 2.5f, 2.5f), // -4 EV
|
|
||||||
conv(lp.mullocsh[3], 3.f, 2.f), // -2 EV
|
|
||||||
conv(lp.mullocsh[4], 3.f, 2.f), // 0 EV
|
|
||||||
conv(lp.mullocsh[4], 3.f, 2.f), // 2 EV
|
|
||||||
conv(lp.mullocsh[4], 3.f, 2.f) // 4 EV
|
|
||||||
};
|
|
||||||
|
|
||||||
TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(workingProfile);
|
|
||||||
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#pragma omp parallel for if (multithread)
|
|
||||||
#endif
|
|
||||||
for (int y = 0; y < H; ++y) {
|
|
||||||
for (int x = 0; x < W; ++x) {
|
|
||||||
Y[y][x] = Color::rgbLuminance(R[y][x], G[y][x], B[y][x], ws);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int detail = LIM(lp.detailsh + 5, 0, 5);
|
|
||||||
int radius = detail / scale + 0.5;
|
|
||||||
float epsilon2 = 0.01f + 0.002f * rtengine::max(detail - 3, 0);
|
|
||||||
|
|
||||||
if (radius > 0) {
|
|
||||||
rtengine::guidedFilterLog(10.f, Y, radius, epsilon2, multithread);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lp.detailsh > 0) {
|
|
||||||
array2D<float> Y2(W, H);
|
|
||||||
constexpr float base_epsilon = 0.02f;
|
|
||||||
constexpr float base_posterization = 5.f;
|
|
||||||
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#pragma omp parallel for if (multithread)
|
|
||||||
#endif
|
|
||||||
for (int y = 0; y < H; ++y) {
|
|
||||||
for (int x = 0; x < W; ++x) {
|
|
||||||
float l = LIM(log2(rtengine::max(Y[y][x], 1e-9f)), centers[0], centers[11]);
|
|
||||||
float ll = round(l * base_posterization) / base_posterization;
|
|
||||||
Y2[y][x] = Y[y][x];
|
|
||||||
Y[y][x] = exp2(ll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
radius = 350.0 / scale;
|
|
||||||
epsilon2 = base_epsilon / float(6 - rtengine::min(lp.detailsh, 5));
|
|
||||||
rtengine::guidedFilter(Y2, Y, Y, radius, epsilon2, multithread);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto gauss =
|
|
||||||
[](float b, float x) -> float {
|
|
||||||
return xexpf((-SQR(x - b) / 4.0f));
|
|
||||||
};
|
|
||||||
|
|
||||||
// For every pixel luminance, the sum of the gaussian masks
|
|
||||||
float w_sum = 0.f;
|
|
||||||
|
|
||||||
for (int i = 0; i < 12; ++i) {
|
|
||||||
w_sum += gauss(centers[i], 0.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto process_pixel =
|
|
||||||
[&](float y) -> float {
|
|
||||||
// convert to log space
|
|
||||||
const float luma = rtengine::max(log2(rtengine::max(y, 0.f)), -18.0f);
|
|
||||||
|
|
||||||
// build the correction as the sum of the contribution of each
|
|
||||||
// luminance channel to current pixel
|
|
||||||
float correction = 0.0f;
|
|
||||||
|
|
||||||
for (int c = 0; c < 12; ++c)
|
|
||||||
{
|
|
||||||
correction += gauss(centers[c], luma) * factors[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
correction /= w_sum;
|
|
||||||
|
|
||||||
return correction;
|
|
||||||
};
|
|
||||||
|
|
||||||
LUTf lut(65536);
|
|
||||||
|
|
||||||
for (int i = 0; i < 65536; ++i) {
|
|
||||||
float y = float(i) / 65535.f;
|
|
||||||
float c = process_pixel(y);
|
|
||||||
lut[i] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __SSE2__
|
|
||||||
vfloat vfactors[12];
|
|
||||||
vfloat vcenters[12];
|
|
||||||
|
|
||||||
for (int i = 0; i < 12; ++i) {
|
|
||||||
vfactors[i] = F2V(factors[i]);
|
|
||||||
vcenters[i] = F2V(centers[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto vgauss =
|
|
||||||
[](vfloat b, vfloat x) -> vfloat {
|
|
||||||
static const vfloat fourv = F2V(4.f);
|
|
||||||
return xexpf((-SQR(x - b) / fourv));
|
|
||||||
};
|
|
||||||
|
|
||||||
vfloat zerov = F2V(0.f);
|
|
||||||
vfloat vw_sum = F2V(w_sum);
|
|
||||||
|
|
||||||
const vfloat noisev = F2V(-18.f);
|
|
||||||
const vfloat xlog2v = F2V(xlogf(2.f));
|
|
||||||
|
|
||||||
const auto vprocess_pixel =
|
|
||||||
[&](vfloat y) -> vfloat {
|
|
||||||
const vfloat luma = vmaxf(xlogf(vmaxf(y, zerov)) / xlog2v, noisev);
|
|
||||||
|
|
||||||
vfloat correction = zerov;
|
|
||||||
|
|
||||||
for (int c = 0; c < 12; ++c)
|
|
||||||
{
|
|
||||||
correction += vgauss(vcenters[c], luma) * vfactors[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
correction /= vw_sum;
|
|
||||||
|
|
||||||
return correction;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
vfloat v1 = F2V(1.f);
|
|
||||||
vfloat v65535 = F2V(65535.f);
|
|
||||||
#endif // __SSE2__
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#pragma omp parallel for if (multithread)
|
|
||||||
#endif
|
|
||||||
for (int y = 0; y < H; ++y) {
|
|
||||||
int x = 0;
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __SSE2__
|
|
||||||
|
|
||||||
for (; x < W - 3; x += 4) {
|
|
||||||
vfloat cY = LVFU(Y[y][x]);
|
|
||||||
vmask m = vmaskf_gt(cY, v1);
|
|
||||||
vfloat corr;
|
|
||||||
|
|
||||||
if (_mm_movemask_ps((vfloat)m)) {
|
|
||||||
corr = vprocess_pixel(cY);
|
|
||||||
} else {
|
|
||||||
corr = lut[cY * v65535];
|
|
||||||
}
|
|
||||||
|
|
||||||
STVF(R[y][x], LVF(R[y][x]) * corr);
|
|
||||||
STVF(G[y][x], LVF(G[y][x]) * corr);
|
|
||||||
STVF(B[y][x], LVF(B[y][x]) * corr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __SSE2__
|
|
||||||
|
|
||||||
for (; x < W; ++x) {
|
|
||||||
float cY = Y[y][x];
|
|
||||||
float corr = cY > 1.f ? process_pixel(cY) : lut[cY * 65535.f];
|
|
||||||
R[y][x] *= corr;
|
|
||||||
G[y][x] *= corr;
|
|
||||||
B[y][x] *= corr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
void ImProcFunctions::loccont(int bfw, int bfh, LabImage* tmp1, float rad, float stren, int sk)
|
void ImProcFunctions::loccont(int bfw, int bfh, LabImage* tmp1, float rad, float stren, int sk)
|
||||||
{
|
{
|
||||||
|
362
rtengine/iptoneequalizer.cc
Normal file
362
rtengine/iptoneequalizer.cc
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
#include "color.h"
|
||||||
|
#include "guidedfilter.h"
|
||||||
|
#include "iccstore.h"
|
||||||
|
#include "imagefloat.h"
|
||||||
|
#include "improcfun.h"
|
||||||
|
#include "sleef.h"
|
||||||
|
#include "StopWatch.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
const std::vector<std::array<float, 3>> colormap = {
|
||||||
|
{0.5f, 0.f, 0.5f},
|
||||||
|
{0.5f, 0.f, 0.5f},
|
||||||
|
{0.5f, 0.f, 0.5f},
|
||||||
|
{0.5f, 0.f, 0.5f},
|
||||||
|
{0.5f, 0.f, 0.5f},
|
||||||
|
{0.5f, 0.f, 0.5f}, // blacks
|
||||||
|
{0.f, 0.f, 1.f}, // shadows
|
||||||
|
{0.5f, 0.5f, 0.5f}, // midtones
|
||||||
|
{1.f, 1.f, 0.f}, // highlights
|
||||||
|
{1.f, 0.f, 0.f}, // whites
|
||||||
|
{1.f, 0.f, 0.f},
|
||||||
|
{1.f, 0.f, 0.f}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace rtengine
|
||||||
|
{
|
||||||
|
|
||||||
|
void ImProcFunctions::toneEqualizer(
|
||||||
|
array2D<float> &R, array2D<float> &G, array2D<float> &B,
|
||||||
|
const struct ToneEqualizerParams ¶ms,
|
||||||
|
const Glib::ustring &workingProfile,
|
||||||
|
double scale,
|
||||||
|
bool multithread,
|
||||||
|
bool show_color_map)
|
||||||
|
// adapted from the tone equalizer of darktable
|
||||||
|
/*
|
||||||
|
Copyright 2019 Alberto Griggio <alberto.griggio@gmail.com>
|
||||||
|
Small adaptation to Local Adjustment 10 2019 Jacques Desmis <jdesmis@gmail.com>
|
||||||
|
This file is part of darktable,
|
||||||
|
copyright (c) 2018 Aurelien Pierre.
|
||||||
|
|
||||||
|
darktable 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.
|
||||||
|
|
||||||
|
darktable 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 darktable. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
{
|
||||||
|
// BENCHFUN
|
||||||
|
|
||||||
|
const int W = R.getWidth();
|
||||||
|
const int H = R.getHeight();
|
||||||
|
array2D<float> Y(W, H);
|
||||||
|
|
||||||
|
const auto log2 =
|
||||||
|
[](float x) -> float {
|
||||||
|
static const float l2 = xlogf(2);
|
||||||
|
return xlogf(x) / l2;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto exp2 =
|
||||||
|
[](float x) -> float {
|
||||||
|
return pow_F(2.f, x);
|
||||||
|
};
|
||||||
|
// Build the luma channels: band-pass filters with gaussian windows of
|
||||||
|
// std 2 EV, spaced by 2 EV
|
||||||
|
const float centers[12] = {
|
||||||
|
-18.0f, -16.0f, -14.0f, -12.0f, -10.0f, -8.0f, -6.0f,
|
||||||
|
-4.0f, -2.0f, 0.0f, 2.0f, 4.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto conv = [&](int v, float lo, float hi) -> float {
|
||||||
|
const float f = v < 0 ? lo : hi;
|
||||||
|
return exp2(float(v) / 100.f * f);
|
||||||
|
};
|
||||||
|
const float factors[12] = {
|
||||||
|
conv(params.bands[0], 2.f, 3.f), // -18 EV
|
||||||
|
conv(params.bands[0], 2.f, 3.f), // -16 EV
|
||||||
|
conv(params.bands[0], 2.f, 3.f), // -14 EV
|
||||||
|
conv(params.bands[0], 2.f, 3.f), // -12 EV
|
||||||
|
conv(params.bands[0], 2.f, 3.f), // -10 EV
|
||||||
|
conv(params.bands[0], 2.f, 3.f), // -8 EV
|
||||||
|
conv(params.bands[1], 2.f, 3.f), // -6 EV
|
||||||
|
conv(params.bands[2], 2.5f, 2.5f), // -4 EV
|
||||||
|
conv(params.bands[3], 3.f, 2.f), // -2 EV
|
||||||
|
conv(params.bands[4], 3.f, 2.f), // 0 EV
|
||||||
|
conv(params.bands[4], 3.f, 2.f), // 2 EV
|
||||||
|
conv(params.bands[4], 3.f, 2.f) // 4 EV
|
||||||
|
};
|
||||||
|
|
||||||
|
TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(workingProfile);
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
|
#pragma omp parallel for if (multithread)
|
||||||
|
#endif
|
||||||
|
for (int y = 0; y < H; ++y) {
|
||||||
|
for (int x = 0; x < W; ++x) {
|
||||||
|
Y[y][x] = Color::rgbLuminance(R[y][x], G[y][x], B[y][x], ws);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int detail = LIM(params.regularization + 5, 0, 5);
|
||||||
|
int radius = detail / scale + 0.5;
|
||||||
|
float epsilon2 = 0.01f + 0.002f * rtengine::max(detail - 3, 0);
|
||||||
|
|
||||||
|
if (radius > 0) {
|
||||||
|
rtengine::guidedFilterLog(10.f, Y, radius, epsilon2, multithread);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.regularization > 0) {
|
||||||
|
array2D<float> Y2(W, H);
|
||||||
|
constexpr float base_epsilon = 0.02f;
|
||||||
|
constexpr float base_posterization = 5.f;
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
|
#pragma omp parallel for if (multithread)
|
||||||
|
#endif
|
||||||
|
for (int y = 0; y < H; ++y) {
|
||||||
|
for (int x = 0; x < W; ++x) {
|
||||||
|
float l = LIM(log2(rtengine::max(Y[y][x], 1e-9f)), centers[0], centers[11]);
|
||||||
|
float ll = round(l * base_posterization) / base_posterization;
|
||||||
|
Y2[y][x] = Y[y][x];
|
||||||
|
Y[y][x] = exp2(ll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
radius = 350.0 / scale;
|
||||||
|
epsilon2 = base_epsilon / float(6 - rtengine::min(params.regularization, 5));
|
||||||
|
rtengine::guidedFilter(Y2, Y, Y, radius, epsilon2, multithread);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto gauss =
|
||||||
|
[](float b, float x) -> float {
|
||||||
|
return xexpf((-SQR(x - b) / 4.0f));
|
||||||
|
};
|
||||||
|
|
||||||
|
// For every pixel luminance, the sum of the gaussian masks
|
||||||
|
float w_sum = 0.f;
|
||||||
|
|
||||||
|
for (int i = 0; i < 12; ++i) {
|
||||||
|
w_sum += gauss(centers[i], 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto process_pixel =
|
||||||
|
[&](float y) -> float {
|
||||||
|
// convert to log space
|
||||||
|
const float luma = rtengine::max(log2(rtengine::max(y, 0.f)), -18.0f);
|
||||||
|
|
||||||
|
// build the correction as the sum of the contribution of each
|
||||||
|
// luminance channel to current pixel
|
||||||
|
float correction = 0.0f;
|
||||||
|
|
||||||
|
for (int c = 0; c < 12; ++c)
|
||||||
|
{
|
||||||
|
correction += gauss(centers[c], luma) * factors[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
correction /= w_sum;
|
||||||
|
|
||||||
|
return correction;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::array<float, 3>> cur_colormap;
|
||||||
|
if (show_color_map) {
|
||||||
|
lcmsMutex->lock();
|
||||||
|
cmsHPROFILE in = ICCStore::getInstance()->getsRGBProfile();
|
||||||
|
cmsHPROFILE out = ICCStore::getInstance()->workingSpace(workingProfile);
|
||||||
|
cmsHTRANSFORM xform = cmsCreateTransform(in, TYPE_RGB_FLT, out, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE);
|
||||||
|
lcmsMutex->unlock();
|
||||||
|
|
||||||
|
for (auto &c : colormap) {
|
||||||
|
cur_colormap.push_back(c);
|
||||||
|
auto &cc = cur_colormap.back();
|
||||||
|
cmsDoTransform(xform, &cc[0], &cc[0], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmsDeleteTransform(xform);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto process_colormap =
|
||||||
|
[&](float y) -> std::array<float, 3>
|
||||||
|
{
|
||||||
|
std::array<float, 3> ret = { 0.f, 0.f, 0.f };
|
||||||
|
|
||||||
|
// convert to log space
|
||||||
|
const float luma = max(log2(max(y, 0.f)), -18.0f);
|
||||||
|
|
||||||
|
// build the correction as the sum of the contribution of each
|
||||||
|
// luminance channel to current pixel
|
||||||
|
for (int c = 0; c < 12; ++c) {
|
||||||
|
float w = gauss(centers[c], luma);
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
ret[i] += w * cur_colormap[c][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
ret[i] = LIM01(ret[i] / w_sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __SSE2__
|
||||||
|
vfloat vfactors[12];
|
||||||
|
vfloat vcenters[12];
|
||||||
|
|
||||||
|
for (int i = 0; i < 12; ++i) {
|
||||||
|
vfactors[i] = F2V(factors[i]);
|
||||||
|
vcenters[i] = F2V(centers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto vgauss =
|
||||||
|
[](vfloat b, vfloat x) -> vfloat {
|
||||||
|
static const vfloat fourv = F2V(4.f);
|
||||||
|
return xexpf((-SQR(x - b) / fourv));
|
||||||
|
};
|
||||||
|
|
||||||
|
vfloat zerov = F2V(0.f);
|
||||||
|
vfloat vw_sum = F2V(w_sum);
|
||||||
|
|
||||||
|
const vfloat noisev = F2V(-18.f);
|
||||||
|
const vfloat xlog2v = F2V(xlogf(2.f));
|
||||||
|
|
||||||
|
const auto vprocess_pixel =
|
||||||
|
[&](vfloat y) -> vfloat {
|
||||||
|
const vfloat luma = vmaxf(xlogf(vmaxf(y, zerov)) / xlog2v, noisev);
|
||||||
|
|
||||||
|
vfloat correction = zerov;
|
||||||
|
|
||||||
|
for (int c = 0; c < 12; ++c)
|
||||||
|
{
|
||||||
|
correction += vgauss(vcenters[c], luma) * vfactors[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
correction /= vw_sum;
|
||||||
|
|
||||||
|
return correction;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
vfloat v1 = F2V(1.f);
|
||||||
|
vfloat v65535 = F2V(65535.f);
|
||||||
|
#endif // __SSE2__
|
||||||
|
|
||||||
|
|
||||||
|
if (show_color_map) {
|
||||||
|
LUTf lut_r(65537), lut_g(65537), lut_b(65537);
|
||||||
|
for (int i = 0; i < 65536; ++i) {
|
||||||
|
float y = float(i)/65535.f;
|
||||||
|
auto rgb = process_colormap(y);
|
||||||
|
lut_r[i] = rgb[0];
|
||||||
|
lut_g[i] = rgb[1];
|
||||||
|
lut_b[i] = rgb[2];
|
||||||
|
}
|
||||||
|
lut_r[65536] = cur_colormap.back()[0];
|
||||||
|
lut_g[65536] = cur_colormap.back()[1];
|
||||||
|
lut_b[65536] = cur_colormap.back()[2];
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
|
# pragma omp parallel for if (multithread)
|
||||||
|
#endif
|
||||||
|
for (int y = 0; y < H; ++y) {
|
||||||
|
for (int x = 0; x < W; ++x) {
|
||||||
|
float cY = Y[y][x] * 65535.f;
|
||||||
|
R[y][x] = lut_r[cY];
|
||||||
|
G[y][x] = lut_g[cY];
|
||||||
|
B[y][x] = lut_b[cY];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUTf lut(65536);
|
||||||
|
|
||||||
|
for (int i = 0; i < 65536; ++i) {
|
||||||
|
float y = float(i) / 65535.f;
|
||||||
|
float c = process_pixel(y);
|
||||||
|
lut[i] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
|
#pragma omp parallel for if (multithread)
|
||||||
|
#endif
|
||||||
|
for (int y = 0; y < H; ++y) {
|
||||||
|
int x = 0;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __SSE2__
|
||||||
|
|
||||||
|
for (; x < W - 3; x += 4) {
|
||||||
|
vfloat cY = LVFU(Y[y][x]);
|
||||||
|
vmask m = vmaskf_gt(cY, v1);
|
||||||
|
vfloat corr;
|
||||||
|
|
||||||
|
if (_mm_movemask_ps((vfloat)m)) {
|
||||||
|
corr = vprocess_pixel(cY);
|
||||||
|
} else {
|
||||||
|
corr = lut[cY * v65535];
|
||||||
|
}
|
||||||
|
|
||||||
|
STVF(R[y][x], LVF(R[y][x]) * corr);
|
||||||
|
STVF(G[y][x], LVF(G[y][x]) * corr);
|
||||||
|
STVF(B[y][x], LVF(B[y][x]) * corr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __SSE2__
|
||||||
|
|
||||||
|
for (; x < W; ++x) {
|
||||||
|
float cY = Y[y][x];
|
||||||
|
float corr = cY > 1.f ? process_pixel(cY) : lut[cY * 65535.f];
|
||||||
|
R[y][x] *= corr;
|
||||||
|
G[y][x] *= corr;
|
||||||
|
B[y][x] *= corr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImProcFunctions::toneEqualizer(Imagefloat *rgb)
|
||||||
|
{
|
||||||
|
if (!params->toneEqualizer.enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHFUN
|
||||||
|
|
||||||
|
const float gain = 1.f / 65535.f * std::pow(2.f, -params->toneEqualizer.pivot);
|
||||||
|
|
||||||
|
rgb->multiply(gain, multiThread);
|
||||||
|
|
||||||
|
const int W = rgb->getWidth();
|
||||||
|
const int H = rgb->getHeight();
|
||||||
|
|
||||||
|
array2D<float> R(W, H, rgb->r.ptrs, ARRAY2D_BYREFERENCE);
|
||||||
|
array2D<float> G(W, H, rgb->g.ptrs, ARRAY2D_BYREFERENCE);
|
||||||
|
array2D<float> B(W, H, rgb->b.ptrs, ARRAY2D_BYREFERENCE);
|
||||||
|
|
||||||
|
bool show_color_map = params->toneEqualizer.show_colormap;
|
||||||
|
toneEqualizer(R, G, B, params->toneEqualizer, params->icm.workingProfile, scale, multiThread, show_color_map);
|
||||||
|
|
||||||
|
rgb->multiply(1.f/gain, multiThread);
|
||||||
|
|
||||||
|
return show_color_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1786,6 +1786,30 @@ bool SHParams::operator !=(const SHParams& other) const
|
|||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToneEqualizerParams::ToneEqualizerParams() :
|
||||||
|
enabled(false),
|
||||||
|
bands{0, 0, 0, 0, 0},
|
||||||
|
regularization(4),
|
||||||
|
show_colormap(false),
|
||||||
|
pivot(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToneEqualizerParams::operator ==(const ToneEqualizerParams &other) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
enabled == other.enabled
|
||||||
|
&& bands == other.bands
|
||||||
|
&& regularization == other.regularization
|
||||||
|
&& show_colormap == other.show_colormap
|
||||||
|
&& pivot == other.pivot;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToneEqualizerParams::operator !=(const ToneEqualizerParams &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
CropParams::CropParams() :
|
CropParams::CropParams() :
|
||||||
enabled(false),
|
enabled(false),
|
||||||
x(-1),
|
x(-1),
|
||||||
@ -5814,6 +5838,8 @@ void ProcParams::setDefaults()
|
|||||||
|
|
||||||
sh = {};
|
sh = {};
|
||||||
|
|
||||||
|
toneEqualizer = {};
|
||||||
|
|
||||||
crop = {};
|
crop = {};
|
||||||
|
|
||||||
coarse = {};
|
coarse = {};
|
||||||
@ -6241,6 +6267,14 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
|
|||||||
saveToKeyfile(!pedited || pedited->sh.radius, "Shadows & Highlights", "Radius", sh.radius, keyFile);
|
saveToKeyfile(!pedited || pedited->sh.radius, "Shadows & Highlights", "Radius", sh.radius, keyFile);
|
||||||
saveToKeyfile(!pedited || pedited->sh.lab, "Shadows & Highlights", "Lab", sh.lab, keyFile);
|
saveToKeyfile(!pedited || pedited->sh.lab, "Shadows & Highlights", "Lab", sh.lab, keyFile);
|
||||||
|
|
||||||
|
// Tone equalizer
|
||||||
|
saveToKeyfile(!pedited || pedited->toneEqualizer.enabled, "ToneEqualizer", "Enabled", toneEqualizer.enabled, keyFile);
|
||||||
|
for (size_t i = 0; i < toneEqualizer.bands.size(); ++i) {
|
||||||
|
saveToKeyfile(!pedited || pedited->toneEqualizer.bands, "ToneEqualizer", "Band" + std::to_string(i), toneEqualizer.bands[i], keyFile);
|
||||||
|
}
|
||||||
|
saveToKeyfile(!pedited || pedited->toneEqualizer.regularization, "ToneEqualizer", "Regularization", toneEqualizer.regularization, keyFile);
|
||||||
|
saveToKeyfile(!pedited || pedited->toneEqualizer.pivot, "ToneEqualizer", "Pivot", toneEqualizer.pivot, keyFile);
|
||||||
|
|
||||||
// Crop
|
// Crop
|
||||||
saveToKeyfile(!pedited || pedited->crop.enabled, "Crop", "Enabled", crop.enabled, keyFile);
|
saveToKeyfile(!pedited || pedited->crop.enabled, "Crop", "Enabled", crop.enabled, keyFile);
|
||||||
saveToKeyfile(!pedited || pedited->crop.x, "Crop", "X", crop.x, keyFile);
|
saveToKeyfile(!pedited || pedited->crop.x, "Crop", "X", crop.x, keyFile);
|
||||||
@ -8226,6 +8260,15 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (keyFile.has_group("ToneEqualizer")) {
|
||||||
|
assignFromKeyfile(keyFile, "ToneEqualizer", "Enabled", pedited, toneEqualizer.enabled, pedited->toneEqualizer.enabled);
|
||||||
|
for (size_t i = 0; i < toneEqualizer.bands.size(); ++i) {
|
||||||
|
assignFromKeyfile(keyFile, "ToneEqualizer", "Band" + std::to_string(i), pedited, toneEqualizer.bands[i], pedited->toneEqualizer.bands);
|
||||||
|
}
|
||||||
|
assignFromKeyfile(keyFile, "ToneEqualizer", "Regularization", pedited, toneEqualizer.regularization, pedited->toneEqualizer.regularization);
|
||||||
|
assignFromKeyfile(keyFile, "ToneEqualizer", "Pivot", pedited, toneEqualizer.pivot, pedited->toneEqualizer.pivot);
|
||||||
|
}
|
||||||
|
|
||||||
if (keyFile.has_group("Crop")) {
|
if (keyFile.has_group("Crop")) {
|
||||||
assignFromKeyfile(keyFile, "Crop", "Enabled", pedited, crop.enabled, pedited->crop.enabled);
|
assignFromKeyfile(keyFile, "Crop", "Enabled", pedited, crop.enabled, pedited->crop.enabled);
|
||||||
assignFromKeyfile(keyFile, "Crop", "X", pedited, crop.x, pedited->crop.x);
|
assignFromKeyfile(keyFile, "Crop", "X", pedited, crop.x, pedited->crop.x);
|
||||||
@ -10447,6 +10490,7 @@ bool ProcParams::operator ==(const ProcParams& other) const
|
|||||||
&& fattal == other.fattal
|
&& fattal == other.fattal
|
||||||
&& defringe == other.defringe
|
&& defringe == other.defringe
|
||||||
&& sh == other.sh
|
&& sh == other.sh
|
||||||
|
&& toneEqualizer == other.toneEqualizer
|
||||||
&& crop == other.crop
|
&& crop == other.crop
|
||||||
&& coarse == other.coarse
|
&& coarse == other.coarse
|
||||||
&& rotate == other.rotate
|
&& rotate == other.rotate
|
||||||
|
@ -827,6 +827,22 @@ struct SHParams {
|
|||||||
bool operator !=(const SHParams& other) const;
|
bool operator !=(const SHParams& other) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tone equalizer parameters.
|
||||||
|
*/
|
||||||
|
struct ToneEqualizerParams {
|
||||||
|
bool enabled;
|
||||||
|
std::array<int, 5> bands;
|
||||||
|
int regularization;
|
||||||
|
bool show_colormap;
|
||||||
|
double pivot;
|
||||||
|
|
||||||
|
ToneEqualizerParams();
|
||||||
|
|
||||||
|
bool operator ==(const ToneEqualizerParams &other) const;
|
||||||
|
bool operator !=(const ToneEqualizerParams &other) const;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameters of the cropping
|
* Parameters of the cropping
|
||||||
*/
|
*/
|
||||||
@ -2547,6 +2563,7 @@ public:
|
|||||||
EPDParams epd; ///< Edge Preserving Decomposition parameters
|
EPDParams epd; ///< Edge Preserving Decomposition parameters
|
||||||
FattalToneMappingParams fattal; ///< Fattal02 tone mapping
|
FattalToneMappingParams fattal; ///< Fattal02 tone mapping
|
||||||
SHParams sh; ///< Shadow/highlight enhancement parameters
|
SHParams sh; ///< Shadow/highlight enhancement parameters
|
||||||
|
ToneEqualizerParams toneEqualizer; ///< Tone equalizer parameters
|
||||||
CropParams crop; ///< Crop parameters
|
CropParams crop; ///< Crop parameters
|
||||||
CoarseTransformParams coarse; ///< Coarse transformation (90, 180, 270 deg rotation, h/v flipping) parameters
|
CoarseTransformParams coarse; ///< Coarse transformation (90, 180, 270 deg rotation, h/v flipping) parameters
|
||||||
CommonTransformParams commonTrans; ///< Common transformation parameters (autofill)
|
CommonTransformParams commonTrans; ///< Common transformation parameters (autofill)
|
||||||
|
@ -159,6 +159,7 @@ set(NONCLISOURCEFILES
|
|||||||
thumbimageupdater.cc
|
thumbimageupdater.cc
|
||||||
thumbnail.cc
|
thumbnail.cc
|
||||||
tonecurve.cc
|
tonecurve.cc
|
||||||
|
toneequalizer.cc
|
||||||
toolbar.cc
|
toolbar.cc
|
||||||
toolpanel.cc
|
toolpanel.cc
|
||||||
toolpanelcoord.cc
|
toolpanelcoord.cc
|
||||||
|
@ -51,6 +51,7 @@ Adjuster::Adjuster(
|
|||||||
grid(nullptr),
|
grid(nullptr),
|
||||||
label(nullptr),
|
label(nullptr),
|
||||||
imageIcon1(imgIcon1),
|
imageIcon1(imgIcon1),
|
||||||
|
imageIcon2(imgIcon2),
|
||||||
automatic(nullptr),
|
automatic(nullptr),
|
||||||
adjusterListener(nullptr),
|
adjusterListener(nullptr),
|
||||||
spinChange(options.adjusterMinDelay, options.adjusterMaxDelay),
|
spinChange(options.adjusterMinDelay, options.adjusterMaxDelay),
|
||||||
@ -76,8 +77,8 @@ Adjuster::Adjuster(
|
|||||||
setExpandAlignProperties(imageIcon1, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
|
setExpandAlignProperties(imageIcon1, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imgIcon2) {
|
if (imageIcon2) {
|
||||||
setExpandAlignProperties(imgIcon2, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
|
setExpandAlignProperties(imageIcon2, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_column_spacing(0);
|
set_column_spacing(0);
|
||||||
@ -120,9 +121,9 @@ Adjuster::Adjuster(
|
|||||||
attach_next_to(*imageIcon1, *slider, Gtk::POS_LEFT, 1, 1);
|
attach_next_to(*imageIcon1, *slider, Gtk::POS_LEFT, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imgIcon2) {
|
if (imageIcon2) {
|
||||||
attach_next_to(*imgIcon2, *slider, Gtk::POS_RIGHT, 1, 1);
|
attach_next_to(*imageIcon2, *slider, Gtk::POS_RIGHT, 1, 1);
|
||||||
attach_next_to(*spin, *imgIcon2, Gtk::POS_RIGHT, 1, 1);
|
attach_next_to(*spin, *imageIcon2, Gtk::POS_RIGHT, 1, 1);
|
||||||
} else {
|
} else {
|
||||||
attach_next_to(*spin, *slider, Gtk::POS_RIGHT, 1, 1);
|
attach_next_to(*spin, *slider, Gtk::POS_RIGHT, 1, 1);
|
||||||
}
|
}
|
||||||
@ -140,9 +141,9 @@ Adjuster::Adjuster(
|
|||||||
grid->attach_next_to(*imageIcon1, *slider, Gtk::POS_LEFT, 1, 1);
|
grid->attach_next_to(*imageIcon1, *slider, Gtk::POS_LEFT, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imgIcon2) {
|
if (imageIcon2) {
|
||||||
grid->attach_next_to(*imgIcon2, Gtk::POS_RIGHT, 1, 1);
|
grid->attach_next_to(*imageIcon2, Gtk::POS_RIGHT, 1, 1);
|
||||||
grid->attach_next_to(*reset, *imgIcon2, Gtk::POS_RIGHT, 1, 1);
|
grid->attach_next_to(*reset, *imageIcon2, Gtk::POS_RIGHT, 1, 1);
|
||||||
} else {
|
} else {
|
||||||
grid->attach_next_to(*reset, *slider, Gtk::POS_RIGHT, 1, 1);
|
grid->attach_next_to(*reset, *slider, Gtk::POS_RIGHT, 1, 1);
|
||||||
}
|
}
|
||||||
@ -683,3 +684,13 @@ void Adjuster::setDelay(unsigned int min_delay_ms, unsigned int max_delay_ms)
|
|||||||
spinChange.setDelay(min_delay_ms, max_delay_ms);
|
spinChange.setDelay(min_delay_ms, max_delay_ms);
|
||||||
sliderChange.setDelay(min_delay_ms, max_delay_ms);
|
sliderChange.setDelay(min_delay_ms, max_delay_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Adjuster::showIcons(bool yes)
|
||||||
|
{
|
||||||
|
if (imageIcon1) {
|
||||||
|
imageIcon1->set_visible(yes);
|
||||||
|
}
|
||||||
|
if (imageIcon2) {
|
||||||
|
imageIcon2->set_visible(yes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -41,6 +41,7 @@ protected:
|
|||||||
Gtk::Grid* grid;
|
Gtk::Grid* grid;
|
||||||
Gtk::Label* label;
|
Gtk::Label* label;
|
||||||
Gtk::Image *imageIcon1;
|
Gtk::Image *imageIcon1;
|
||||||
|
Gtk::Image *imageIcon2;
|
||||||
MyHScale* slider;
|
MyHScale* slider;
|
||||||
MySpinButton* spin;
|
MySpinButton* spin;
|
||||||
Gtk::Button* reset;
|
Gtk::Button* reset;
|
||||||
@ -133,4 +134,5 @@ public:
|
|||||||
void trimValue (int &val) const;
|
void trimValue (int &val) const;
|
||||||
void setLogScale(double base, double pivot, bool anchorMiddle = false);
|
void setLogScale(double base, double pivot, bool anchorMiddle = false);
|
||||||
void setDelay(unsigned int min_delay_ms, unsigned int max_delay_ms = 0);
|
void setDelay(unsigned int min_delay_ms, unsigned int max_delay_ms = 0);
|
||||||
|
void showIcons(bool yes);
|
||||||
};
|
};
|
||||||
|
@ -317,6 +317,11 @@ void ParamsEdited::set(bool v)
|
|||||||
sh.stonalwidth = v;
|
sh.stonalwidth = v;
|
||||||
sh.radius = v;
|
sh.radius = v;
|
||||||
sh.lab = v;
|
sh.lab = v;
|
||||||
|
toneEqualizer.enabled = v;
|
||||||
|
toneEqualizer.bands = v;
|
||||||
|
toneEqualizer.regularization = v;
|
||||||
|
toneEqualizer.show_colormap = v;
|
||||||
|
toneEqualizer.pivot = v;
|
||||||
crop.enabled = v;
|
crop.enabled = v;
|
||||||
crop.x = v;
|
crop.x = v;
|
||||||
crop.y = v;
|
crop.y = v;
|
||||||
@ -1031,6 +1036,11 @@ void ParamsEdited::initFrom(const std::vector<rtengine::procparams::ProcParams>&
|
|||||||
crop.ratio = crop.ratio && p.crop.ratio == other.crop.ratio;
|
crop.ratio = crop.ratio && p.crop.ratio == other.crop.ratio;
|
||||||
crop.orientation = crop.orientation && p.crop.orientation == other.crop.orientation;
|
crop.orientation = crop.orientation && p.crop.orientation == other.crop.orientation;
|
||||||
crop.guide = crop.guide && p.crop.guide == other.crop.guide;
|
crop.guide = crop.guide && p.crop.guide == other.crop.guide;
|
||||||
|
toneEqualizer.enabled = toneEqualizer.enabled && p.toneEqualizer.enabled == other.toneEqualizer.enabled;
|
||||||
|
toneEqualizer.bands = toneEqualizer.bands && p.toneEqualizer.bands == other.toneEqualizer.bands;
|
||||||
|
toneEqualizer.regularization = toneEqualizer.regularization && p.toneEqualizer.regularization == other.toneEqualizer.regularization;
|
||||||
|
toneEqualizer.show_colormap = toneEqualizer.show_colormap && p.toneEqualizer.show_colormap == other.toneEqualizer.show_colormap;
|
||||||
|
toneEqualizer.pivot = toneEqualizer.pivot && p.toneEqualizer.pivot == other.toneEqualizer.pivot;
|
||||||
coarse.rotate = coarse.rotate && p.coarse.rotate == other.coarse.rotate;
|
coarse.rotate = coarse.rotate && p.coarse.rotate == other.coarse.rotate;
|
||||||
coarse.hflip = coarse.hflip && p.coarse.hflip == other.coarse.hflip;
|
coarse.hflip = coarse.hflip && p.coarse.hflip == other.coarse.hflip;
|
||||||
coarse.vflip = coarse.vflip && p.coarse.vflip == other.coarse.vflip;
|
coarse.vflip = coarse.vflip && p.coarse.vflip == other.coarse.vflip;
|
||||||
@ -3194,6 +3204,26 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
|
|||||||
toEdit.sh.lab = mods.sh.lab;
|
toEdit.sh.lab = mods.sh.lab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toneEqualizer.enabled) {
|
||||||
|
toEdit.toneEqualizer.enabled = mods.toneEqualizer.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toneEqualizer.bands) {
|
||||||
|
toEdit.toneEqualizer.bands = mods.toneEqualizer.bands;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toneEqualizer.regularization) {
|
||||||
|
toEdit.toneEqualizer.regularization = mods.toneEqualizer.regularization;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toneEqualizer.show_colormap) {
|
||||||
|
toEdit.toneEqualizer.show_colormap = mods.toneEqualizer.show_colormap;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toneEqualizer.pivot) {
|
||||||
|
toEdit.toneEqualizer.pivot = mods.toneEqualizer.pivot;
|
||||||
|
}
|
||||||
|
|
||||||
if (crop.enabled) {
|
if (crop.enabled) {
|
||||||
toEdit.crop.enabled = mods.crop.enabled;
|
toEdit.crop.enabled = mods.crop.enabled;
|
||||||
}
|
}
|
||||||
|
@ -358,6 +358,14 @@ struct SHParamsEdited {
|
|||||||
bool lab;
|
bool lab;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ToneEqualizerParamsEdited {
|
||||||
|
bool enabled;
|
||||||
|
bool bands;
|
||||||
|
bool regularization;
|
||||||
|
bool show_colormap;
|
||||||
|
bool pivot;
|
||||||
|
};
|
||||||
|
|
||||||
struct CropParamsEdited {
|
struct CropParamsEdited {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool x;
|
bool x;
|
||||||
@ -1545,6 +1553,7 @@ struct ParamsEdited {
|
|||||||
FattalToneMappingParamsEdited fattal;
|
FattalToneMappingParamsEdited fattal;
|
||||||
ImpulseDenoiseParamsEdited impulseDenoise;
|
ImpulseDenoiseParamsEdited impulseDenoise;
|
||||||
SHParamsEdited sh;
|
SHParamsEdited sh;
|
||||||
|
ToneEqualizerParamsEdited toneEqualizer;
|
||||||
CropParamsEdited crop;
|
CropParamsEdited crop;
|
||||||
CoarseTransformParamsEdited coarse;
|
CoarseTransformParamsEdited coarse;
|
||||||
CommonTransformParamsEdited commonTrans;
|
CommonTransformParamsEdited commonTrans;
|
||||||
|
@ -219,6 +219,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
|
|||||||
wb = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_WHITEBALANCE")));
|
wb = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_WHITEBALANCE")));
|
||||||
exposure = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EXPOSURE")));
|
exposure = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EXPOSURE")));
|
||||||
sh = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SHADOWSHIGHLIGHTS")));
|
sh = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SHADOWSHIGHLIGHTS")));
|
||||||
|
toneEqualizer = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_TONE_EQUALIZER")));
|
||||||
epd = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EPD")));
|
epd = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EPD")));
|
||||||
fattal = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_TM_FATTAL")));
|
fattal = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_TM_FATTAL")));
|
||||||
pcvignette = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PCVIGNETTE")));
|
pcvignette = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PCVIGNETTE")));
|
||||||
@ -331,6 +332,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
|
|||||||
vboxes[0]->pack_start (*wb, Gtk::PACK_SHRINK, 2);
|
vboxes[0]->pack_start (*wb, Gtk::PACK_SHRINK, 2);
|
||||||
vboxes[0]->pack_start (*exposure, Gtk::PACK_SHRINK, 2);
|
vboxes[0]->pack_start (*exposure, Gtk::PACK_SHRINK, 2);
|
||||||
vboxes[0]->pack_start (*sh, Gtk::PACK_SHRINK, 2);
|
vboxes[0]->pack_start (*sh, Gtk::PACK_SHRINK, 2);
|
||||||
|
vboxes[0]->pack_start (*toneEqualizer, Gtk::PACK_SHRINK, 2);
|
||||||
vboxes[0]->pack_start (*epd, Gtk::PACK_SHRINK, 2);
|
vboxes[0]->pack_start (*epd, Gtk::PACK_SHRINK, 2);
|
||||||
vboxes[0]->pack_start (*fattal, Gtk::PACK_SHRINK, 2);
|
vboxes[0]->pack_start (*fattal, Gtk::PACK_SHRINK, 2);
|
||||||
vboxes[0]->pack_start (*pcvignette, Gtk::PACK_SHRINK, 2);
|
vboxes[0]->pack_start (*pcvignette, Gtk::PACK_SHRINK, 2);
|
||||||
@ -496,6 +498,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
|
|||||||
wbConn = wb->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
wbConn = wb->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
||||||
exposureConn = exposure->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
exposureConn = exposure->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
||||||
shConn = sh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
shConn = sh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
||||||
|
toneEqualizerConn = toneEqualizer->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
||||||
epdConn = epd->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
epdConn = epd->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
||||||
fattalConn = fattal->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
fattalConn = fattal->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
||||||
pcvignetteConn = pcvignette->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
pcvignetteConn = pcvignette->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
|
||||||
@ -701,6 +704,7 @@ void PartialPasteDlg::basicToggled ()
|
|||||||
ConnectionBlocker wbBlocker(wbConn);
|
ConnectionBlocker wbBlocker(wbConn);
|
||||||
ConnectionBlocker exposureBlocker(exposureConn);
|
ConnectionBlocker exposureBlocker(exposureConn);
|
||||||
ConnectionBlocker shBlocker(shConn);
|
ConnectionBlocker shBlocker(shConn);
|
||||||
|
ConnectionBlocker toneEqualizerBlocker(toneEqualizerConn);
|
||||||
ConnectionBlocker epdBlocker(epdConn);
|
ConnectionBlocker epdBlocker(epdConn);
|
||||||
ConnectionBlocker fattalBlocker(fattalConn);
|
ConnectionBlocker fattalBlocker(fattalConn);
|
||||||
ConnectionBlocker pcvignetteBlocker(pcvignetteConn);
|
ConnectionBlocker pcvignetteBlocker(pcvignetteConn);
|
||||||
@ -712,6 +716,7 @@ void PartialPasteDlg::basicToggled ()
|
|||||||
wb->set_active (basic->get_active ());
|
wb->set_active (basic->get_active ());
|
||||||
exposure->set_active (basic->get_active ());
|
exposure->set_active (basic->get_active ());
|
||||||
sh->set_active (basic->get_active ());
|
sh->set_active (basic->get_active ());
|
||||||
|
toneEqualizer->set_active (basic->get_active ());
|
||||||
epd->set_active (basic->get_active ());
|
epd->set_active (basic->get_active ());
|
||||||
fattal->set_active (basic->get_active ());
|
fattal->set_active (basic->get_active ());
|
||||||
pcvignette->set_active (basic->get_active ());
|
pcvignette->set_active (basic->get_active ());
|
||||||
@ -889,6 +894,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param
|
|||||||
filterPE.sh = falsePE.sh;
|
filterPE.sh = falsePE.sh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!toneEqualizer->get_active ()) {
|
||||||
|
filterPE.toneEqualizer = falsePE.toneEqualizer;
|
||||||
|
}
|
||||||
|
|
||||||
if (!epd->get_active ()) {
|
if (!epd->get_active ()) {
|
||||||
filterPE.epd = falsePE.epd;
|
filterPE.epd = falsePE.epd;
|
||||||
}
|
}
|
||||||
|
@ -133,6 +133,7 @@ public:
|
|||||||
Gtk::CheckButton* exposure;
|
Gtk::CheckButton* exposure;
|
||||||
Gtk::CheckButton* localcontrast;
|
Gtk::CheckButton* localcontrast;
|
||||||
Gtk::CheckButton* sh;
|
Gtk::CheckButton* sh;
|
||||||
|
Gtk::CheckButton* toneEqualizer;
|
||||||
Gtk::CheckButton* epd;
|
Gtk::CheckButton* epd;
|
||||||
Gtk::CheckButton* fattal;
|
Gtk::CheckButton* fattal;
|
||||||
Gtk::CheckButton* retinex;
|
Gtk::CheckButton* retinex;
|
||||||
@ -225,6 +226,7 @@ public:
|
|||||||
sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, advancedConn;
|
sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, advancedConn;
|
||||||
sigc::connection locallabConn;
|
sigc::connection locallabConn;
|
||||||
sigc::connection wbConn, exposureConn, localcontrastConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn;
|
sigc::connection wbConn, exposureConn, localcontrastConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn;
|
||||||
|
sigc::connection toneEqualizerConn;
|
||||||
sigc::connection spotConn, sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn, dehazeConn;
|
sigc::connection spotConn, sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn, dehazeConn;
|
||||||
sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn, chmixerbwConn, colortoningConn, filmSimulationConn, softlightConn;
|
sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn, chmixerbwConn, colortoningConn, filmSimulationConn, softlightConn;
|
||||||
sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn;
|
sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn;
|
||||||
|
@ -462,6 +462,7 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh
|
|||||||
|| pparams->epd != pp.epd
|
|| pparams->epd != pp.epd
|
||||||
|| pparams->fattal != pp.fattal
|
|| pparams->fattal != pp.fattal
|
||||||
|| pparams->sh != pp.sh
|
|| pparams->sh != pp.sh
|
||||||
|
|| pparams->toneEqualizer != pp.toneEqualizer
|
||||||
|| pparams->crop != pp.crop
|
|| pparams->crop != pp.crop
|
||||||
|| pparams->coarse != pp.coarse
|
|| pparams->coarse != pp.coarse
|
||||||
|| pparams->commonTrans != pp.commonTrans
|
|| pparams->commonTrans != pp.commonTrans
|
||||||
|
169
rtgui/toneequalizer.cc
Normal file
169
rtgui/toneequalizer.cc
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Adapted from ART.
|
||||||
|
*
|
||||||
|
* This file is part of RawTherapee.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "eventmapper.h"
|
||||||
|
#include "toneequalizer.h"
|
||||||
|
#include "rtimage.h"
|
||||||
|
|
||||||
|
using namespace rtengine;
|
||||||
|
using namespace rtengine::procparams;
|
||||||
|
|
||||||
|
|
||||||
|
ToneEqualizer::ToneEqualizer(): FoldableToolPanel(this, "toneequalizer", M("TP_TONE_EQUALIZER_LABEL"), false, true)
|
||||||
|
{
|
||||||
|
auto m = ProcEventMapper::getInstance();
|
||||||
|
EvEnabled = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_ENABLED");
|
||||||
|
EvBands = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_BANDS");
|
||||||
|
EvRegularization = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_REGULARIZATION");
|
||||||
|
EvColormap = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_SHOW_COLOR_MAP");
|
||||||
|
EvPivot = m->newEvent(RGBCURVE, "HISTORY_MSG_TONE_EQUALIZER_PIVOT");
|
||||||
|
|
||||||
|
std::array<const char *, 5> images = {
|
||||||
|
"purple",
|
||||||
|
"blue",
|
||||||
|
"gray",
|
||||||
|
"yellow",
|
||||||
|
"red"
|
||||||
|
};
|
||||||
|
for (size_t i = 0; i < bands.size(); ++i) {
|
||||||
|
bands[i] = Gtk::manage(new Adjuster(M("TP_TONE_EQUALIZER_BAND_" + std::to_string(i)), -100, 100, 1, 0, Gtk::manage(new RTImage(Glib::ustring("circle-") + images[i] + "-small.png"))));
|
||||||
|
bands[i]->setAdjusterListener(this);
|
||||||
|
pack_start(*bands[i]);
|
||||||
|
bands[i]->showIcons(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pivot = Gtk::manage(new Adjuster(M("TP_TONE_EQUALIZER_PIVOT"), -12, 12, 0.05, 0));
|
||||||
|
pivot->setLogScale(64, 0, true);
|
||||||
|
pivot->setAdjusterListener(this);
|
||||||
|
pack_start(*pivot);
|
||||||
|
|
||||||
|
pack_start(*Gtk::manage(new Gtk::HSeparator()));
|
||||||
|
regularization = Gtk::manage(new Adjuster(M("TP_TONE_EQUALIZER_DETAIL"), -5, 5, 1, 5));
|
||||||
|
regularization->setAdjusterListener(this);
|
||||||
|
pack_start(*regularization);
|
||||||
|
|
||||||
|
show_colormap = Gtk::manage(new Gtk::CheckButton(M("TP_TONE_EQUALIZER_SHOW_COLOR_MAP")));
|
||||||
|
pack_start(*show_colormap);
|
||||||
|
show_colormap->signal_toggled().connect(sigc::mem_fun(this, &ToneEqualizer::colormapToggled));
|
||||||
|
|
||||||
|
show_all_children ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ToneEqualizer::read(const ProcParams *pp, const ParamsEdited* pedited)
|
||||||
|
{
|
||||||
|
disableListener();
|
||||||
|
|
||||||
|
setEnabled(pp->toneEqualizer.enabled);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < bands.size(); ++i) {
|
||||||
|
bands[i]->setValue(pp->toneEqualizer.bands[i]);
|
||||||
|
bands[i]->showIcons(pp->toneEqualizer.show_colormap);
|
||||||
|
}
|
||||||
|
regularization->setValue(pp->toneEqualizer.regularization);
|
||||||
|
|
||||||
|
pivot->setValue(pp->toneEqualizer.pivot);
|
||||||
|
show_colormap->set_active(pp->toneEqualizer.show_colormap);
|
||||||
|
|
||||||
|
enableListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ToneEqualizer::write(ProcParams *pp, ParamsEdited* pedited)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < bands.size(); ++i) {
|
||||||
|
pp->toneEqualizer.bands[i] = bands[i]->getValue();
|
||||||
|
}
|
||||||
|
pp->toneEqualizer.enabled = getEnabled();
|
||||||
|
pp->toneEqualizer.regularization = regularization->getValue();
|
||||||
|
pp->toneEqualizer.show_colormap = show_colormap->get_active();
|
||||||
|
pp->toneEqualizer.pivot = pivot->getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ToneEqualizer::setDefaults(const ProcParams *defParams, const ParamsEdited* pedited)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < bands.size(); ++i) {
|
||||||
|
bands[i]->setDefault(defParams->toneEqualizer.bands[i]);
|
||||||
|
}
|
||||||
|
regularization->setDefault(defParams->toneEqualizer.regularization);
|
||||||
|
|
||||||
|
pivot->setDefault(defParams->toneEqualizer.pivot);
|
||||||
|
inital_params = defParams->toneEqualizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ToneEqualizer::adjusterChanged(Adjuster *a, double newval)
|
||||||
|
{
|
||||||
|
if (listener && getEnabled()) {
|
||||||
|
if (a == regularization) {
|
||||||
|
listener->panelChanged(EvRegularization, Glib::ustring::format(a->getValue()));
|
||||||
|
} else if (a == pivot) {
|
||||||
|
listener->panelChanged(EvPivot, Glib::ustring::format(a->getValue()));
|
||||||
|
} else {
|
||||||
|
Glib::ustring s;
|
||||||
|
for (size_t i = 0; i < bands.size(); ++i) {
|
||||||
|
s += Glib::ustring::format((int)bands[i]->getValue()) + " ";
|
||||||
|
}
|
||||||
|
listener->panelChanged(EvBands, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ToneEqualizer::adjusterAutoToggled(Adjuster *a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ToneEqualizer::enabledChanged()
|
||||||
|
{
|
||||||
|
if (listener) {
|
||||||
|
if (get_inconsistent()) {
|
||||||
|
listener->panelChanged(EvEnabled, M("GENERAL_UNCHANGED"));
|
||||||
|
} else if (getEnabled()) {
|
||||||
|
listener->panelChanged(EvEnabled, M("GENERAL_ENABLED"));
|
||||||
|
} else {
|
||||||
|
listener->panelChanged(EvEnabled, M("GENERAL_DISABLED"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ToneEqualizer::colormapToggled()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < bands.size(); ++i) {
|
||||||
|
bands[i]->showIcons(show_colormap->get_active());
|
||||||
|
}
|
||||||
|
if (listener && getEnabled()) {
|
||||||
|
listener->panelChanged(EvColormap, show_colormap->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ToneEqualizer::trimValues(rtengine::procparams::ProcParams *pp)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < bands.size(); ++i) {
|
||||||
|
bands[i]->trimValue(pp->toneEqualizer.bands[i]);
|
||||||
|
}
|
||||||
|
regularization->trimValue(pp->toneEqualizer.regularization);
|
||||||
|
pivot->trimValue(pp->toneEqualizer.pivot);
|
||||||
|
}
|
||||||
|
|
56
rtgui/toneequalizer.h
Normal file
56
rtgui/toneequalizer.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/* -*- C++ -*-
|
||||||
|
*
|
||||||
|
* Adapted from ART.
|
||||||
|
*
|
||||||
|
* This file is part of RawTherapee.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
||||||
|
*
|
||||||
|
* 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtkmm.h>
|
||||||
|
#include "adjuster.h"
|
||||||
|
#include "toolpanel.h"
|
||||||
|
|
||||||
|
class ToneEqualizer: public ToolParamBlock, public AdjusterListener, public FoldableToolPanel {
|
||||||
|
public:
|
||||||
|
ToneEqualizer();
|
||||||
|
|
||||||
|
void read(const rtengine::procparams::ProcParams *pp, const ParamsEdited* pedited = nullptr) override;
|
||||||
|
void write(rtengine::procparams::ProcParams *pp, ParamsEdited* pedited = nullptr) override;
|
||||||
|
void setDefaults(const rtengine::procparams::ProcParams *defParams, const ParamsEdited* pedited = nullptr) override;
|
||||||
|
void adjusterChanged(Adjuster *a, double newval) override;
|
||||||
|
void adjusterAutoToggled(Adjuster *a) override;
|
||||||
|
void enabledChanged() override;
|
||||||
|
|
||||||
|
void trimValues(rtengine::procparams::ProcParams *pp) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void colormapToggled();
|
||||||
|
|
||||||
|
std::array<Adjuster *, 5> bands;
|
||||||
|
Adjuster *regularization;
|
||||||
|
Adjuster *pivot;
|
||||||
|
Gtk::CheckButton *show_colormap;
|
||||||
|
|
||||||
|
rtengine::ProcEvent EvEnabled;
|
||||||
|
rtengine::ProcEvent EvBands;
|
||||||
|
rtengine::ProcEvent EvRegularization;
|
||||||
|
rtengine::ProcEvent EvColormap;
|
||||||
|
rtengine::ProcEvent EvPivot;
|
||||||
|
|
||||||
|
rtengine::procparams::ToneEqualizerParams inital_params;
|
||||||
|
};
|
@ -47,6 +47,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit
|
|||||||
coarse = Gtk::manage (new CoarsePanel ());
|
coarse = Gtk::manage (new CoarsePanel ());
|
||||||
toneCurve = Gtk::manage (new ToneCurve ());
|
toneCurve = Gtk::manage (new ToneCurve ());
|
||||||
shadowshighlights = Gtk::manage (new ShadowsHighlights ());
|
shadowshighlights = Gtk::manage (new ShadowsHighlights ());
|
||||||
|
toneEqualizer = Gtk::manage (new ToneEqualizer ());
|
||||||
impulsedenoise = Gtk::manage (new ImpulseDenoise ());
|
impulsedenoise = Gtk::manage (new ImpulseDenoise ());
|
||||||
defringe = Gtk::manage (new Defringe ());
|
defringe = Gtk::manage (new Defringe ());
|
||||||
spot = Gtk::manage (new Spot ());
|
spot = Gtk::manage (new Spot ());
|
||||||
@ -118,6 +119,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit
|
|||||||
addfavoritePanel (colorPanel, chmixer);
|
addfavoritePanel (colorPanel, chmixer);
|
||||||
addfavoritePanel (colorPanel, blackwhite);
|
addfavoritePanel (colorPanel, blackwhite);
|
||||||
addfavoritePanel (exposurePanel, shadowshighlights);
|
addfavoritePanel (exposurePanel, shadowshighlights);
|
||||||
|
addfavoritePanel (exposurePanel, toneEqualizer);
|
||||||
addfavoritePanel (detailsPanel, spot);
|
addfavoritePanel (detailsPanel, spot);
|
||||||
addfavoritePanel (detailsPanel, sharpening);
|
addfavoritePanel (detailsPanel, sharpening);
|
||||||
addfavoritePanel (detailsPanel, localContrast);
|
addfavoritePanel (detailsPanel, localContrast);
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
#include "softlight.h"
|
#include "softlight.h"
|
||||||
#include "spot.h"
|
#include "spot.h"
|
||||||
#include "tonecurve.h"
|
#include "tonecurve.h"
|
||||||
|
#include "toneequalizer.h"
|
||||||
#include "toolbar.h"
|
#include "toolbar.h"
|
||||||
#include "toolpanel.h"
|
#include "toolpanel.h"
|
||||||
#include "vibrance.h"
|
#include "vibrance.h"
|
||||||
@ -133,6 +134,7 @@ protected:
|
|||||||
Crop* crop;
|
Crop* crop;
|
||||||
ToneCurve* toneCurve;
|
ToneCurve* toneCurve;
|
||||||
ShadowsHighlights* shadowshighlights;
|
ShadowsHighlights* shadowshighlights;
|
||||||
|
ToneEqualizer* toneEqualizer;
|
||||||
LocalContrast *localContrast;
|
LocalContrast *localContrast;
|
||||||
Spot* spot;
|
Spot* spot;
|
||||||
Defringe* defringe;
|
Defringe* defringe;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user