diff --git a/rtdata/languages/default b/rtdata/languages/default
index 963659884..dcf626948 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -398,7 +398,7 @@ HISTORY_MSG_145;Microcontrast - Uniformity
HISTORY_MSG_146;Edge sharpening
HISTORY_MSG_147;ES - Luminance only
HISTORY_MSG_148;Microcontrast
-HISTORY_MSG_149;Microcontrast - 3×3 matrix
+HISTORY_MSG_149;Microcontrast - 33 matrix
HISTORY_MSG_150;Post-demosaic artifact/noise red.
HISTORY_MSG_151;Vibrance
HISTORY_MSG_152;Vib - Pastel tones
@@ -728,6 +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_DEHAZE_ENABLED;Haze Removal
+HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
HISTORY_MSG_DUALDEMOSAIC_CONTRAST;AMaZE+VNG4 - Contrast threshold
HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
@@ -807,7 +809,7 @@ IPTCPANEL_CITY;City
IPTCPANEL_CITYHINT;Enter the name of the city pictured in this image.
IPTCPANEL_COPYHINT;Copy IPTC settings to clipboard.
IPTCPANEL_COPYRIGHT;Copyright notice
-IPTCPANEL_COPYRIGHTHINT;Enter a Notice on the current owner of the Copyright for this image, such as ©2008 Jane Doe.
+IPTCPANEL_COPYRIGHTHINT;Enter a Notice on the current owner of the Copyright for this image, such as 2008 Jane Doe.
IPTCPANEL_COUNTRY;Country
IPTCPANEL_COUNTRYHINT;Enter the name of the country pictured in this image.
IPTCPANEL_CREATOR;Creator
@@ -954,6 +956,7 @@ PARTIALPASTE_CROP;Crop
PARTIALPASTE_DARKFRAMEAUTOSELECT;Dark-frame auto-selection
PARTIALPASTE_DARKFRAMEFILE;Dark-frame file
PARTIALPASTE_DEFRINGE;Defringe
+PARTIALPASTE_DEHAZE;Haze removal
PARTIALPASTE_DETAILGROUP;Detail Settings
PARTIALPASTE_DIALOGLABEL;Partial paste processing profile
PARTIALPASTE_DIRPYRDENOISE;Noise reduction
@@ -1366,9 +1369,9 @@ TP_COARSETRAF_TOOLTIP_ROTLEFT;Rotate left.\n\nShortcuts:\n[ - Multiple Ed
TP_COARSETRAF_TOOLTIP_ROTRIGHT;Rotate right.\n\nShortcuts:\n] - Multiple Editor Tabs Mode,\nAlt-] - Single Editor Tab Mode.
TP_COARSETRAF_TOOLTIP_VFLIP;Flip vertically.
TP_COLORAPP_ADAPTSCENE;Scene absolute luminance
-TP_COLORAPP_ADAPTSCENE_TOOLTIP;Absolute luminance of the scene environment (cd/m²).\n1) Calculated from the Exif data:\nShutter speed - ISO speed - F number - camera exposure correction.\n2) Calculated from the raw white point and RT's Exposure Compensation slider.
-TP_COLORAPP_ADAPTVIEWING;Viewing absolute luminance (cd/m²)
-TP_COLORAPP_ADAPTVIEWING_TOOLTIP;Absolute luminance of the viewing environment\n(usually 16cd/m²).
+TP_COLORAPP_ADAPTSCENE_TOOLTIP;Absolute luminance of the scene environment (cd/m).\n1) Calculated from the Exif data:\nShutter speed - ISO speed - F number - camera exposure correction.\n2) Calculated from the raw white point and RT's Exposure Compensation slider.
+TP_COLORAPP_ADAPTVIEWING;Viewing absolute luminance (cd/m)
+TP_COLORAPP_ADAPTVIEWING_TOOLTIP;Absolute luminance of the viewing environment\n(usually 16cd/m).
TP_COLORAPP_ADAP_AUTO_TOOLTIP;If the checkbox is checked (recommended) RawTherapee calculates an optimum value from the Exif data.\nTo set the value manually, uncheck the checkbox first.
TP_COLORAPP_ALGO;Algorithm
TP_COLORAPP_ALGO_ALL;All
@@ -1405,7 +1408,7 @@ TP_COLORAPP_FREE;Free temp+green + CAT02 + [output]
TP_COLORAPP_GAMUT;Gamut control (L*a*b*)
TP_COLORAPP_GAMUT_TOOLTIP;Allow gamut control in L*a*b* mode.
TP_COLORAPP_HUE;Hue (h)
-TP_COLORAPP_HUE_TOOLTIP;Hue (h) - angle between 0° and 360°.
+TP_COLORAPP_HUE_TOOLTIP;Hue (h) - angle between 0 and 360.
TP_COLORAPP_LABEL;CIE Color Appearance Model 2002
TP_COLORAPP_LABEL_CAM02;Image Adjustments
TP_COLORAPP_LABEL_SCENE;Scene Conditions
@@ -1505,6 +1508,8 @@ TP_DARKFRAME_LABEL;Dark-Frame
TP_DEFRINGE_LABEL;Defringe
TP_DEFRINGE_RADIUS;Radius
TP_DEFRINGE_THRESHOLD;Threshold
+TP_DEHAZE_LABEL;Haze Removal
+TP_DEHAZE_STRENGTH;Strength
TP_DIRPYRDENOISE_CHROMINANCE_AMZ;Auto multi-zones
TP_DIRPYRDENOISE_CHROMINANCE_AUTOGLOBAL;Automatic global
TP_DIRPYRDENOISE_CHROMINANCE_AUTOGLOBAL_TOOLTIP;Try to evaluate chroma noise\nBe careful, this calculation is average, and is quite subjective !
@@ -1552,16 +1557,16 @@ TP_DIRPYRDENOISE_MEDIAN_METHOD_RGB;RGB
TP_DIRPYRDENOISE_MEDIAN_METHOD_TOOLTIP;When using the "Luminance only" and "L*a*b*" methods, median filtering will be performed just after the wavelet step in the noise reduction pipeline.\nWhen using the "RGB" mode, it will be performed at the very end of the noise reduction pipeline.
TP_DIRPYRDENOISE_MEDIAN_METHOD_WEIGHTED;Weighted L* (little) + a*b* (normal)
TP_DIRPYRDENOISE_MEDIAN_PASSES;Median iterations
-TP_DIRPYRDENOISE_MEDIAN_PASSES_TOOLTIP;Applying three median filter iterations with a 3×3 window size often leads to better results than using one median filter iteration with a 7×7 window size.
+TP_DIRPYRDENOISE_MEDIAN_PASSES_TOOLTIP;Applying three median filter iterations with a 33 window size often leads to better results than using one median filter iteration with a 77 window size.
TP_DIRPYRDENOISE_MEDIAN_TYPE;Median type
-TP_DIRPYRDENOISE_MEDIAN_TYPE_TOOLTIP;Apply a median filter of the desired window size. The larger the window's size, the longer it takes.\n\n3×3 soft: treats 5 pixels in a 3×3 pixel window.\n3×3: treats 9 pixels in a 3×3 pixel window.\n5×5 soft: treats 13 pixels in a 5×5 pixel window.\n5×5: treats 25 pixels in a 5×5 pixel window.\n7×7: treats 49 pixels in a 7×7 pixel window.\n9×9: treats 81 pixels in a 9×9 pixel window.\n\nSometimes it is possible to achieve higher quality running several iterations with a smaller window size than one iteration with a larger one.
+TP_DIRPYRDENOISE_MEDIAN_TYPE_TOOLTIP;Apply a median filter of the desired window size. The larger the window's size, the longer it takes.\n\n33 soft: treats 5 pixels in a 33 pixel window.\n33: treats 9 pixels in a 33 pixel window.\n55 soft: treats 13 pixels in a 55 pixel window.\n55: treats 25 pixels in a 55 pixel window.\n77: treats 49 pixels in a 77 pixel window.\n99: treats 81 pixels in a 99 pixel window.\n\nSometimes it is possible to achieve higher quality running several iterations with a smaller window size than one iteration with a larger one.
TP_DIRPYRDENOISE_SLI;Slider
-TP_DIRPYRDENOISE_TYPE_3X3;3×3
-TP_DIRPYRDENOISE_TYPE_3X3SOFT;3×3 soft
-TP_DIRPYRDENOISE_TYPE_5X5;5×5
-TP_DIRPYRDENOISE_TYPE_5X5SOFT;5×5 soft
-TP_DIRPYRDENOISE_TYPE_7X7;7×7
-TP_DIRPYRDENOISE_TYPE_9X9;9×9
+TP_DIRPYRDENOISE_TYPE_3X3;33
+TP_DIRPYRDENOISE_TYPE_3X3SOFT;33 soft
+TP_DIRPYRDENOISE_TYPE_5X5;55
+TP_DIRPYRDENOISE_TYPE_5X5SOFT;55 soft
+TP_DIRPYRDENOISE_TYPE_7X7;77
+TP_DIRPYRDENOISE_TYPE_9X9;99
TP_DIRPYREQUALIZER_ALGO;Skin Color Range
TP_DIRPYREQUALIZER_ALGO_TOOLTIP;Fine: closer to the colors of the skin, minimizing the action on other colors\nLarge: avoid more artifacts.
TP_DIRPYREQUALIZER_ARTIF;Reduce artifacts
@@ -2005,7 +2010,7 @@ TP_SHARPENING_USM;Unsharp Mask
TP_SHARPENMICRO_AMOUNT;Quantity
TP_SHARPENMICRO_CONTRAST;Contrast threshold
TP_SHARPENMICRO_LABEL;Microcontrast
-TP_SHARPENMICRO_MATRIX;3×3 matrix instead of 5×5
+TP_SHARPENMICRO_MATRIX;33 matrix instead of 55
TP_SHARPENMICRO_UNIFORMITY;Uniformity
TP_SOFTLIGHT_LABEL;Soft Light
TP_SOFTLIGHT_STRENGTH;Strength
diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt
index 759316e33..f610cc8b0 100644
--- a/rtengine/CMakeLists.txt
+++ b/rtengine/CMakeLists.txt
@@ -128,6 +128,7 @@ set(RTENGINESOURCEFILES
vng4_demosaic_RT.cc
ipsoftlight.cc
guidedfilter.cc
+ ipdehaze.cc
)
if(LENSFUN_HAS_LOAD_DIRECTORY)
diff --git a/rtengine/color.h b/rtengine/color.h
index 1e6eef578..b6459adc4 100644
--- a/rtengine/color.h
+++ b/rtengine/color.h
@@ -205,6 +205,10 @@ public:
return r * 0.2126729 + g * 0.7151521 + b * 0.0721750;
}
+ static float rgbLuminance(float r, float g, float b, const double workingspace[3][3])
+ {
+ return r * workingspace[1][0] + g * workingspace[1][1] + b * workingspace[1][2];
+ }
/**
* @brief Convert red/green/blue to L*a*b
diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc
index 002747070..d72b7389c 100644
--- a/rtengine/dcrop.cc
+++ b/rtengine/dcrop.cc
@@ -692,7 +692,7 @@ void Crop::update(int todo)
std::unique_ptr fattalCrop;
- if ((todo & M_HDR) && params.fattal.enabled) {
+ if ((todo & M_HDR) && (params.fattal.enabled || params.dehaze.enabled)) {
Imagefloat *f = origCrop;
int fw = skips(parent->fw, skip);
int fh = skips(parent->fh, skip);
@@ -741,6 +741,7 @@ void Crop::update(int todo)
}
if (need_fattal) {
+ parent->ipf.dehaze(f);
parent->ipf.ToneMapFattal02(f);
}
diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc
index 298c3fc58..dec7fef91 100644
--- a/rtengine/improccoordinator.cc
+++ b/rtengine/improccoordinator.cc
@@ -413,12 +413,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
readyphase++;
- if ((todo & M_HDR) && params.fattal.enabled) {
+ if ((todo & M_HDR) && (params.fattal.enabled || params.dehaze.enabled)) {
if (fattal_11_dcrop_cache) {
delete fattal_11_dcrop_cache;
fattal_11_dcrop_cache = nullptr;
}
+ ipf.dehaze(orig_prev);
ipf.ToneMapFattal02(orig_prev);
if (oprevi != orig_prev) {
diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h
index a97ecef40..216641a45 100644
--- a/rtengine/improcfun.h
+++ b/rtengine/improcfun.h
@@ -339,6 +339,7 @@ public:
void Badpixelscam(CieImage * ncie, double radius, int thresh, int mode, float chrom, bool hotbad);
void BadpixelsLab(LabImage * lab, double radius, int thresh, float chrom);
+ void dehaze(Imagefloat *rgb);
void ToneMapFattal02(Imagefloat *rgb);
void localContrast(LabImage *lab);
void colorToningLabGrid(LabImage *lab, int xstart, int xend, int ystart, int yend, bool MultiThread);
diff --git a/rtengine/ipdehaze.cc b/rtengine/ipdehaze.cc
new file mode 100644
index 000000000..aed647417
--- /dev/null
+++ b/rtengine/ipdehaze.cc
@@ -0,0 +1,335 @@
+/* -*- C++ -*-
+ *
+ * This file is part of RawTherapee.
+ *
+ * Copyright (c) 2018 Alberto Griggio
+ *
+ * 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 .
+ */
+
+/*
+ * Haze removal using the algorithm described in the paper:
+ *
+ * Single Image Haze Removal Using Dark Channel Prior
+ * by He, Sun and Tang
+ *
+ * using a guided filter for the "soft matting" of the transmission map
+ *
+ */
+
+#include "improcfun.h"
+#include "guidedfilter.h"
+#include "rt_math.h"
+#include "rt_algo.h"
+#include
+#include
+
+extern Options options;
+
+namespace rtengine {
+
+namespace {
+
+#if 0
+# define DEBUG_DUMP(arr) \
+ do { \
+ Imagefloat im(arr.width(), arr.height()); \
+ const char *out = "/tmp/" #arr ".tif"; \
+ for (int y = 0; y < im.getHeight(); ++y) { \
+ for (int x = 0; x < im.getWidth(); ++x) { \
+ im.r(y, x) = im.g(y, x) = im.b(y, x) = arr[y][x] * 65535.f; \
+ } \
+ } \
+ im.saveTIFF(out, 16); \
+ } while (false)
+#else
+# define DEBUG_DUMP(arr)
+#endif
+
+
+int get_dark_channel(const Imagefloat &src, array2D &dst,
+ int patchsize, float *ambient, bool multithread)
+{
+ const int w = src.getWidth();
+ const int h = src.getHeight();
+
+ int npatches = 0;
+
+#ifdef _OPENMP
+ #pragma omp parallel for if (multithread)
+#endif
+ for (int y = 0; y < src.getHeight(); y += patchsize) {
+ int pH = std::min(y+patchsize, h);
+ for (int x = 0; x < src.getWidth(); x += patchsize, ++npatches) {
+ float val = RT_INFINITY_F;
+ int pW = std::min(x+patchsize, w);
+ for (int yy = y; yy < pH; ++yy) {
+ float yval = RT_INFINITY_F;
+ for (int xx = x; xx < pW; ++xx) {
+ float r = src.r(yy, xx);
+ float g = src.g(yy, xx);
+ float b = src.b(yy, xx);
+ if (ambient) {
+ r /= ambient[0];
+ g /= ambient[1];
+ b /= ambient[2];
+ }
+ yval = min(yval, r, g, b);
+ }
+ val = min(val, yval);
+ }
+ for (int yy = y; yy < pH; ++yy) {
+ std::fill(dst[yy]+x, dst[yy]+pW, val);
+ }
+ for (int yy = y; yy < pH; ++yy) {
+ for (int xx = x; xx < pW; ++xx) {
+ float r = src.r(yy, xx);
+ float g = src.g(yy, xx);
+ float b = src.b(yy, xx);
+ if (ambient) {
+ r /= ambient[0];
+ g /= ambient[1];
+ b /= ambient[2];
+ }
+ float l = min(r, g, b);
+ if (l >= 2.f * val) {
+ dst[yy][xx] = l;
+ }
+ }
+ }
+ }
+ }
+
+ return npatches;
+}
+
+
+int estimate_ambient_light(const Imagefloat *img, const array2D &dark, const array2D &Y, int patchsize, int npatches, float ambient[3])
+{
+ const int W = img->getWidth();
+ const int H = img->getHeight();
+
+ const auto get_percentile =
+ [](std::priority_queue &q, float prcnt) -> float
+ {
+ size_t n = LIM(q.size() * prcnt, 1, q.size());
+ while (q.size() > n) {
+ q.pop();
+ }
+ return q.top();
+ };
+
+ float lim = RT_INFINITY_F;
+ {
+ std::priority_queue p;
+ for (int y = 0; y < H; y += patchsize) {
+ for (int x = 0; x < W; x += patchsize) {
+ p.push(dark[y][x]);
+ }
+ }
+ lim = get_percentile(p, 0.95);
+ }
+
+ std::vector> patches;
+ patches.reserve(npatches);
+
+ for (int y = 0; y < H; y += patchsize) {
+ for (int x = 0; x < W; x += patchsize) {
+ if (dark[y][x] >= lim) {
+ patches.push_back(std::make_pair(x, y));
+ }
+ }
+ }
+
+ if (options.rtSettings.verbose) {
+ std::cout << "dehaze: computing ambient light from " << patches.size()
+ << " patches" << std::endl;
+ }
+
+ {
+ std::priority_queue l;
+
+ for (auto &p : patches) {
+ const int pW = std::min(p.first+patchsize, W);
+ const int pH = std::min(p.second+patchsize, H);
+
+ for (int y = p.second; y < pH; ++y) {
+ for (int x = p.first; x < pW; ++x) {
+ l.push(Y[y][x]);
+ }
+ }
+ }
+
+ lim = get_percentile(l, 0.95);
+ }
+
+ double rr = 0, gg = 0, bb = 0;
+ int n = 0;
+ for (auto &p : patches) {
+ const int pW = std::min(p.first+patchsize, W);
+ const int pH = std::min(p.second+patchsize, H);
+
+ for (int y = p.second; y < pH; ++y) {
+ for (int x = p.first; x < pW; ++x) {
+ if (Y[y][x] >= lim) {
+ float r = img->r(y, x);
+ float g = img->g(y, x);
+ float b = img->b(y, x);
+ rr += r;
+ gg += g;
+ bb += b;
+ ++n;
+ }
+ }
+ }
+ }
+ ambient[0] = rr / n;
+ ambient[1] = gg / n;
+ ambient[2] = bb / n;
+
+ return n;
+}
+
+
+void get_luminance(Imagefloat *img, array2D &Y, TMatrix ws, bool multithread)
+{
+ const int W = img->getWidth();
+ const int H = img->getHeight();
+
+#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(img->r(y, x), img->g(y, x), img->b(y, x), ws);
+ }
+ }
+}
+
+
+} // namespace
+
+
+void ImProcFunctions::dehaze(Imagefloat *img)
+{
+ if (!params->dehaze.enabled) {
+ return;
+ }
+
+ img->normalizeFloatTo1();
+
+ const int W = img->getWidth();
+ const int H = img->getHeight();
+ const float strength = LIM01(float(params->dehaze.strength) / 100.f * 0.9f);
+
+ if (options.rtSettings.verbose) {
+ std::cout << "dehaze: strength = " << strength << std::endl;
+ }
+
+ array2D dark(W, H);
+ const int patchsize = std::max(W / 200, 2);
+ int npatches = get_dark_channel(*img, dark, patchsize, nullptr, multiThread);
+ DEBUG_DUMP(dark);
+
+ TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile);
+ array2D Y(W, H);
+ get_luminance(img, Y, ws, multiThread);
+
+ float ambient[3];
+ int n = estimate_ambient_light(img, dark, Y, patchsize, npatches, ambient);
+ float ambient_Y = Color::rgbLuminance(ambient[0], ambient[1], ambient[2], ws);
+
+ if (options.rtSettings.verbose) {
+ std::cout << "dehaze: ambient light is "
+ << ambient[0] << ", " << ambient[1] << ", " << ambient[2]
+ << " (average of " << n << ")"
+ << std::endl;
+ std::cout << " ambient luminance is " << ambient_Y << std::endl;
+ }
+
+ if (min(ambient[0], ambient[1], ambient[2]) < 0.01f) {
+ if (options.rtSettings.verbose) {
+ std::cout << "dehaze: no haze detected" << std::endl;
+ }
+ img->normalizeFloatTo65535();
+ return; // probably no haze at all
+ }
+
+ array2D &t_tilde = dark;
+ get_dark_channel(*img, dark, patchsize, ambient, multiThread);
+ DEBUG_DUMP(t_tilde);
+
+#ifdef _OPENMP
+ #pragma omp parallel for if (multiThread)
+#endif
+ for (int y = 0; y < H; ++y) {
+ for (int x = 0; x < W; ++x) {
+ dark[y][x] = 1.f - strength * dark[y][x];
+ }
+ }
+
+ const int radius = patchsize * 2;
+ const float epsilon = 2.5e-4;
+ array2D &t = t_tilde;
+
+ guidedFilter(Y, t_tilde, t, radius, epsilon, multiThread);
+
+ DEBUG_DUMP(t);
+
+ const float t0 = 0.01;
+#ifdef _OPENMP
+ #pragma omp parallel for if (multiThread)
+#endif
+ for (int y = 0; y < H; ++y) {
+ for (int x = 0; x < W; ++x) {
+ float mt = std::max(t[y][x], t0);
+ float r = (img->r(y, x) - ambient[0]) / mt + ambient[0];
+ float g = (img->g(y, x) - ambient[1]) / mt + ambient[1];
+ float b = (img->b(y, x) - ambient[2]) / mt + ambient[2];
+ img->r(y, x) = r;
+ img->g(y, x) = g;
+ img->b(y, x) = b;
+ }
+ }
+
+ float oldmed;
+ findMinMaxPercentile(Y, Y.width() * Y.height(), 0.5, oldmed, 0.5, oldmed, multiThread);
+
+ get_luminance(img, Y, ws, multiThread);
+ float newmed;
+
+ findMinMaxPercentile(Y, Y.width() * Y.height(), 0.5, newmed, 0.5, newmed, multiThread);
+
+ if (newmed > 1e-5f) {
+ const float f1 = oldmed / newmed;
+ const float f = f1 * 65535.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 r = img->r(y, x);
+ float g = img->g(y, x);
+ float b = img->b(y, x);
+ float h, s, l;
+ Color::rgb2hslfloat(r * f, g * f, b * f, h, s, l);
+ s = LIM01(s / f1);
+ Color::hsl2rgbfloat(h, s, l, img->r(y, x), img->g(y, x), img->b(y, x));
+ }
+ }
+ }
+}
+
+
+} // namespace rtengine
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index 4d0c7aed0..ceace7c3b 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -2373,6 +2373,26 @@ bool SoftLightParams::operator !=(const SoftLightParams& other) const
return !(*this == other);
}
+
+DehazeParams::DehazeParams() :
+ enabled(false),
+ strength(50)
+{
+}
+
+bool DehazeParams::operator ==(const DehazeParams& other) const
+{
+ return
+ enabled == other.enabled
+ && strength == other.strength;
+}
+
+bool DehazeParams::operator !=(const DehazeParams& other) const
+{
+ return !(*this == other);
+}
+
+
RAWParams::BayerSensor::BayerSensor() :
method(getMethodString(Method::AMAZE)),
border(4),
@@ -2727,6 +2747,8 @@ void ProcParams::setDefaults()
softlight = SoftLightParams();
+ dehaze = DehazeParams();
+
raw = RAWParams();
metadata = MetaDataParams();
@@ -3037,6 +3059,10 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
saveToKeyfile(!pedited || pedited->defringe.threshold, "Defringing", "Threshold", defringe.threshold, keyFile);
saveToKeyfile(!pedited || pedited->defringe.huecurve, "Defringing", "HueCurve", defringe.huecurve, keyFile);
+// Dehaze
+ saveToKeyfile(!pedited || pedited->dehaze.enabled, "Dehaze", "Enabled", dehaze.enabled, keyFile);
+ saveToKeyfile(!pedited || pedited->dehaze.strength, "Dehaze", "Strength", dehaze.strength, keyFile);
+
// Directional pyramid denoising
saveToKeyfile(!pedited || pedited->dirpyrDenoise.enabled, "Directional Pyramid Denoising", "Enabled", dirpyrDenoise.enabled, keyFile);
saveToKeyfile(!pedited || pedited->dirpyrDenoise.enhance, "Directional Pyramid Denoising", "Enhance", dirpyrDenoise.enhance, keyFile);
@@ -4618,6 +4644,11 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
assignFromKeyfile(keyFile, "SoftLight", "Strength", pedited, softlight.strength, pedited->softlight.strength);
}
+ if (keyFile.has_group("Dehaze")) {
+ assignFromKeyfile(keyFile, "Dehaze", "Enabled", pedited, dehaze.enabled, pedited->dehaze.enabled);
+ assignFromKeyfile(keyFile, "Dehaze", "Strength", pedited, dehaze.strength, pedited->dehaze.strength);
+ }
+
if (keyFile.has_group("Film Simulation")) {
assignFromKeyfile(keyFile, "Film Simulation", "Enabled", pedited, filmSimulation.enabled, pedited->filmSimulation.enabled);
assignFromKeyfile(keyFile, "Film Simulation", "ClutFilename", pedited, filmSimulation.clutFilename, pedited->filmSimulation.clutFilename);
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index 700c6271c..19fe0a376 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -1227,6 +1227,17 @@ struct SoftLightParams {
};
+struct DehazeParams {
+ bool enabled;
+ int strength;
+
+ DehazeParams();
+
+ bool operator==(const DehazeParams &other) const;
+ bool operator!=(const DehazeParams &other) const;
+};
+
+
/**
* Parameters for RAW demosaicing, common to all sensor type
*/
@@ -1438,6 +1449,7 @@ public:
HSVEqualizerParams hsvequalizer; ///< hsv wavelet parameters
FilmSimulationParams filmSimulation; ///< film simulation parameters
SoftLightParams softlight; ///< softlight parameters
+ DehazeParams dehaze; ///< dehaze parameters
int rank; ///< Custom image quality ranking
int colorlabel; ///< Custom color label
bool inTrash; ///< Marks deleted image
diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc
index 79dee36bf..bb710ee83 100644
--- a/rtengine/rtthumbnail.cc
+++ b/rtengine/rtthumbnail.cc
@@ -1200,6 +1200,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT
ipf.firstAnalysis (baseImg, params, hist16);
+ ipf.dehaze(baseImg);
if (params.fattal.enabled) {
ipf.ToneMapFattal02(baseImg);
}
diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc
index fbee20f44..0846eacbd 100644
--- a/rtengine/simpleprocess.cc
+++ b/rtengine/simpleprocess.cc
@@ -854,6 +854,7 @@ private:
ipf.firstAnalysis (baseImg, params, hist16);
+ ipf.dehaze(baseImg);
if (params.fattal.enabled) {
ipf.ToneMapFattal02(baseImg);
}
diff --git a/rtengine/tmo_fattal02.cc b/rtengine/tmo_fattal02.cc
index dc7826501..351d60bc9 100644
--- a/rtengine/tmo_fattal02.cc
+++ b/rtengine/tmo_fattal02.cc
@@ -952,7 +952,7 @@ inline void rescale_nearest (const Array2Df &src, Array2Df &dst, bool multithrea
inline float luminance (float r, float g, float b, TMatrix ws)
{
- return r * ws[1][0] + g * ws[1][1] + b * ws[1][2];
+ return Color::rgbLuminance(r, g, b, ws);
}
diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt
index 8150fbce3..434e8187e 100644
--- a/rtgui/CMakeLists.txt
+++ b/rtgui/CMakeLists.txt
@@ -156,6 +156,7 @@ set(NONCLISOURCEFILES
metadatapanel.cc
labgrid.cc
softlight.cc
+ dehaze.cc
)
include_directories(BEFORE "${CMAKE_CURRENT_BINARY_DIR}")
diff --git a/rtgui/addsetids.h b/rtgui/addsetids.h
index 8cf39aa29..1d9c621eb 100644
--- a/rtgui/addsetids.h
+++ b/rtgui/addsetids.h
@@ -142,6 +142,7 @@ enum {
ADDSET_BAYER_DUALDEMOZCONTRAST,
ADDSET_XTRANS_FALSE_COLOR_SUPPRESSION,
ADDSET_SOFTLIGHT_STRENGTH,
+ ADDSET_DEHAZE_STRENGTH,
ADDSET_PARAM_NUM // THIS IS USED AS A DELIMITER!!
};
diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc
index b31f41e4f..13b1f6677 100644
--- a/rtgui/batchtoolpanelcoord.cc
+++ b/rtgui/batchtoolpanelcoord.cc
@@ -202,6 +202,7 @@ void BatchToolPanelCoordinator::initSession ()
colortoning->setAdjusterBehavior (options.baBehav[ADDSET_COLORTONING_SPLIT], options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD], options.baBehav[ADDSET_COLORTONING_SATOPACITY], options.baBehav[ADDSET_COLORTONING_STRENGTH], options.baBehav[ADDSET_COLORTONING_BALANCE]);
filmSimulation->setAdjusterBehavior(options.baBehav[ADDSET_FILMSIMULATION_STRENGTH]);
softlight->setAdjusterBehavior(options.baBehav[ADDSET_SOFTLIGHT_STRENGTH]);
+ dehaze->setAdjusterBehavior(options.baBehav[ADDSET_DEHAZE_STRENGTH]);
retinex->setAdjusterBehavior (options.baBehav[ADDSET_RETI_STR], options.baBehav[ADDSET_RETI_NEIGH], options.baBehav[ADDSET_RETI_LIMD], options.baBehav[ADDSET_RETI_OFFS], options.baBehav[ADDSET_RETI_VART], options.baBehav[ADDSET_RETI_GAM], options.baBehav[ADDSET_RETI_SLO]);
chmixer->setAdjusterBehavior (options.baBehav[ADDSET_CHMIXER] );
@@ -292,6 +293,7 @@ void BatchToolPanelCoordinator::initSession ()
if (options.baBehav[ADDSET_COLORTONING_STRENGTH]) { pparams.colorToning.strength = 0; }
if (options.baBehav[ADDSET_FILMSIMULATION_STRENGTH]) { pparams.filmSimulation.strength = 0; }
if (options.baBehav[ADDSET_SOFTLIGHT_STRENGTH]) { pparams.softlight.strength = 0; }
+ if (options.baBehav[ADDSET_DEHAZE_STRENGTH]) { pparams.dehaze.strength = 0; }
if (options.baBehav[ADDSET_ROTATE_DEGREE]) { pparams.rotate.degree = 0; }
if (options.baBehav[ADDSET_RESIZE_SCALE]) { pparams.resize.scale = 0; }
if (options.baBehav[ADDSET_DIST_AMOUNT]) { pparams.distortion.amount = 0; }
diff --git a/rtgui/dehaze.cc b/rtgui/dehaze.cc
new file mode 100644
index 000000000..6f4814e55
--- /dev/null
+++ b/rtgui/dehaze.cc
@@ -0,0 +1,115 @@
+/** -*- C++ -*-
+ *
+ * This file is part of RawTherapee.
+ *
+ * Copyright (c) 2018 Alberto Griggio
+ *
+ * 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 "dehaze.h"
+#include "eventmapper.h"
+#include
+#include
+
+using namespace rtengine;
+using namespace rtengine::procparams;
+
+Dehaze::Dehaze(): FoldableToolPanel(this, "dehaze", M("TP_DEHAZE_LABEL"), false, true)
+{
+ auto m = ProcEventMapper::getInstance();
+ EvDehazeEnabled = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_ENABLED");
+ EvDehazeStrength = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_STRENGTH");
+
+ strength = Gtk::manage(new Adjuster(M("TP_DEHAZE_STRENGTH"), 0., 100., 1., 50.));
+ strength->setAdjusterListener(this);
+ strength->show();
+
+ pack_start(*strength);
+}
+
+
+void Dehaze::read(const ProcParams *pp, const ParamsEdited *pedited)
+{
+ disableListener();
+
+ if (pedited) {
+ strength->setEditedState(pedited->dehaze.strength ? Edited : UnEdited);
+ set_inconsistent(multiImage && !pedited->dehaze.enabled);
+ }
+
+ setEnabled(pp->dehaze.enabled);
+ strength->setValue(pp->dehaze.strength);
+
+ enableListener();
+}
+
+
+void Dehaze::write(ProcParams *pp, ParamsEdited *pedited)
+{
+ pp->dehaze.strength = strength->getValue();
+ pp->dehaze.enabled = getEnabled();
+
+ if (pedited) {
+ pedited->dehaze.strength = strength->getEditedState();
+ pedited->dehaze.enabled = !get_inconsistent();
+ }
+}
+
+void Dehaze::setDefaults(const ProcParams *defParams, const ParamsEdited *pedited)
+{
+ strength->setDefault(defParams->dehaze.strength);
+
+ if (pedited) {
+ strength->setDefaultEditedState(pedited->dehaze.strength ? Edited : UnEdited);
+ } else {
+ strength->setDefaultEditedState(Irrelevant);
+ }
+}
+
+
+void Dehaze::adjusterChanged(Adjuster* a, double newval)
+{
+ if (listener && getEnabled()) {
+ listener->panelChanged(EvDehazeStrength, a->getTextValue());
+ }
+}
+
+
+void Dehaze::enabledChanged ()
+{
+ if (listener) {
+ if (get_inconsistent()) {
+ listener->panelChanged(EvDehazeEnabled, M("GENERAL_UNCHANGED"));
+ } else if (getEnabled()) {
+ listener->panelChanged(EvDehazeEnabled, M("GENERAL_ENABLED"));
+ } else {
+ listener->panelChanged(EvDehazeEnabled, M("GENERAL_DISABLED"));
+ }
+ }
+}
+
+
+void Dehaze::setBatchMode(bool batchMode)
+{
+ ToolPanel::setBatchMode(batchMode);
+
+ strength->showEditedCB();
+}
+
+
+void Dehaze::setAdjusterBehavior(bool strengthAdd)
+{
+ strength->setAddMode(strengthAdd);
+}
+
diff --git a/rtgui/dehaze.h b/rtgui/dehaze.h
new file mode 100644
index 000000000..3617f13ea
--- /dev/null
+++ b/rtgui/dehaze.h
@@ -0,0 +1,47 @@
+/** -*- C++ -*-
+ *
+ * This file is part of RawTherapee.
+ *
+ * Copyright (c) 2018 Alberto Griggio
+ *
+ * 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 .
+ */
+#pragma once
+
+#include
+#include "adjuster.h"
+#include "toolpanel.h"
+
+class Dehaze: public ToolParamBlock, public AdjusterListener, public FoldableToolPanel
+{
+private:
+ Adjuster *strength;
+
+ rtengine::ProcEvent EvDehazeEnabled;
+ rtengine::ProcEvent EvDehazeStrength;
+
+public:
+
+ Dehaze();
+
+ void read(const rtengine::procparams::ProcParams *pp, const ParamsEdited *pedited=nullptr);
+ void write(rtengine::procparams::ProcParams *pp, ParamsEdited *pedited=nullptr);
+ void setDefaults(const rtengine::procparams::ProcParams *defParams, const ParamsEdited *pedited=nullptr);
+ void setBatchMode(bool batchMode);
+
+ void adjusterChanged(Adjuster *a, double newval);
+ void enabledChanged();
+ void setAdjusterBehavior(bool strengthAdd);
+};
+
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index 342d9adf9..fef8da8e6 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -566,6 +566,8 @@ void ParamsEdited::set(bool v)
filmSimulation.strength = v;
softlight.enabled = v;
softlight.strength = v;
+ dehaze.enabled = v;
+ dehaze.strength = v;
metadata.mode = v;
exif = v;
@@ -1119,6 +1121,8 @@ void ParamsEdited::initFrom(const std::vector&
filmSimulation.strength = filmSimulation.strength && p.filmSimulation.strength == other.filmSimulation.strength;
softlight.enabled = softlight.enabled && p.softlight.enabled == other.softlight.enabled;
softlight.strength = softlight.strength && p.softlight.strength == other.softlight.strength;
+ dehaze.enabled = dehaze.enabled && p.dehaze.enabled == other.dehaze.enabled;
+ dehaze.strength = dehaze.strength && p.dehaze.strength == other.dehaze.strength;
metadata.mode = metadata.mode && p.metadata.mode == other.metadata.mode;
// How the hell can we handle that???
@@ -3112,6 +3116,14 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
if (softlight.strength) {
toEdit.softlight.strength = dontforceSet && options.baBehav[ADDSET_SOFTLIGHT_STRENGTH] ? toEdit.softlight.strength + mods.softlight.strength : mods.softlight.strength;
}
+
+ if (dehaze.enabled) {
+ toEdit.dehaze.enabled = mods.dehaze.enabled;
+ }
+
+ if (dehaze.strength) {
+ toEdit.dehaze.strength = dontforceSet && options.baBehav[ADDSET_DEHAZE_STRENGTH] ? toEdit.dehaze.strength + mods.dehaze.strength : mods.dehaze.strength;
+ }
if (metadata.mode) {
toEdit.metadata.mode = mods.metadata.mode;
diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h
index 177b05d85..6a2076032 100644
--- a/rtgui/paramsedited.h
+++ b/rtgui/paramsedited.h
@@ -724,6 +724,14 @@ public:
bool strength;
};
+class DehazeParamsEdited
+{
+public:
+ bool enabled;
+ bool strength;
+};
+
+
class RAWParamsEdited
{
@@ -865,6 +873,7 @@ public:
HSVEqualizerParamsEdited hsvequalizer;
FilmSimulationParamsEdited filmSimulation;
SoftLightParamsEdited softlight;
+ DehazeParamsEdited dehaze;
MetaDataParamsEdited metadata;
bool exif;
bool iptc;
diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc
index 6b192dba9..065deef6a 100644
--- a/rtgui/partialpastedlg.cc
+++ b/rtgui/partialpastedlg.cc
@@ -65,6 +65,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
dirpyrden = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DIRPYRDENOISE")));
defringe = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DEFRINGE")));
dirpyreq = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DIRPYREQUALIZER")));
+ dehaze = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DEHAZE")) );
// Advanced Settings:
retinex = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RETINEX")));
@@ -168,6 +169,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
vboxes[1]->pack_start (*dirpyrden, Gtk::PACK_SHRINK, 2);
vboxes[1]->pack_start (*defringe, Gtk::PACK_SHRINK, 2);
vboxes[1]->pack_start (*dirpyreq, Gtk::PACK_SHRINK, 2);
+ vboxes[1]->pack_start (*dehaze, Gtk::PACK_SHRINK, 2);
//COLOR
vboxes[2]->pack_start (*color, Gtk::PACK_SHRINK, 2);
@@ -327,6 +329,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
dirpyrdenConn = dirpyrden->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true));
defringeConn = defringe->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true));
dirpyreqConn = dirpyreq->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true));
+ dehazeConn = dehaze->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true));
// Advanced Settings:
retinexConn = retinex->signal_toggled().connect (sigc::bind (sigc::mem_fun(*advanced, &Gtk::CheckButton::set_inconsistent), true));
@@ -534,6 +537,7 @@ void PartialPasteDlg::detailToggled ()
ConnectionBlocker dirpyrdenBlocker(dirpyrdenConn);
ConnectionBlocker defringeBlocker(defringeConn);
ConnectionBlocker dirpyreqBlocker(dirpyreqConn);
+ ConnectionBlocker dehazeBlocker(dehazeConn);
detail->set_inconsistent (false);
@@ -545,6 +549,7 @@ void PartialPasteDlg::detailToggled ()
dirpyrden->set_active (detail->get_active ());
defringe->set_active (detail->get_active ());
dirpyreq->set_active (detail->get_active ());
+ dehaze->set_active (detail->get_active ());
}
void PartialPasteDlg::advancedToggled ()
@@ -762,6 +767,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param
filterPE.softlight = falsePE.softlight;
}
+ if (!dehaze->get_active ()) {
+ filterPE.dehaze = falsePE.dehaze;
+ }
+
if (!rgbcurves->get_active ()) {
filterPE.rgbCurves = falsePE.rgbCurves;
}
diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h
index 5195d0756..f551ac134 100644
--- a/rtgui/partialpastedlg.h
+++ b/rtgui/partialpastedlg.h
@@ -63,6 +63,7 @@ public:
Gtk::CheckButton* dirpyrden;
Gtk::CheckButton* defringe;
Gtk::CheckButton* dirpyreq;
+ Gtk::CheckButton* dehaze;
// options in wavelet
Gtk::CheckButton* wavelet;
@@ -131,7 +132,7 @@ public:
sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, advancedConn;
sigc::connection wbConn, exposureConn, localcontrastConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn;
- sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn;
+ sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn, dehazeConn;
sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn, chmixerbwConn, colortoningConn, filmSimulationConn, softlightConn;
sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn;
sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, prsharpeningConn, perspectiveConn, commonTransConn;
diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc
index a7b45c902..33d8489f7 100644
--- a/rtgui/preferences.cc
+++ b/rtgui/preferences.cc
@@ -255,6 +255,10 @@ Gtk::Widget* Preferences::getBatchProcPanel ()
appendBehavList (mi, M ("TP_DIRPYRDENOISE_MAIN_GAMMA"), ADDSET_DIRPYRDN_GAMMA, true);
appendBehavList (mi, M ("TP_DIRPYRDENOISE_MEDIAN_PASSES"), ADDSET_DIRPYRDN_PASSES, true);
+ mi = behModel->append ();
+ mi->set_value ( behavColumns.label, M ("TP_DEHAZE_LABEL") );
+ appendBehavList ( mi, M ( "TP_DEHAZE_STRENGTH" ), ADDSET_DEHAZE_STRENGTH, true );
+
mi = behModel->append ();
mi->set_value (behavColumns.label, M ("TP_WBALANCE_LABEL"));
appendBehavList (mi, M ("TP_WBALANCE_TEMPERATURE"), ADDSET_WB_TEMPERATURE, true);
diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc
index deecb7682..99367999c 100644
--- a/rtgui/toolpanelcoord.cc
+++ b/rtgui/toolpanelcoord.cc
@@ -77,6 +77,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan
hsvequalizer = Gtk::manage (new HSVEqualizer ());
filmSimulation = Gtk::manage (new FilmSimulation ());
softlight = Gtk::manage(new SoftLight());
+ dehaze = Gtk::manage(new Dehaze());
sensorbayer = Gtk::manage (new SensorBayer ());
sensorxtrans = Gtk::manage (new SensorXTrans ());
bayerprocess = Gtk::manage (new BayerProcess ());
@@ -126,6 +127,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan
addPanel (detailsPanel, dirpyrdenoise);
addPanel (detailsPanel, defringe);
addPanel (detailsPanel, dirpyrequalizer);
+ addPanel (detailsPanel, dehaze);
addPanel (advancedPanel, wavelet);
addPanel (transformPanel, crop);
addPanel (transformPanel, resize);
diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h
index 1c46ee54e..ca5c5fac4 100644
--- a/rtgui/toolpanelcoord.h
+++ b/rtgui/toolpanelcoord.h
@@ -80,6 +80,7 @@
#include "fattaltonemap.h"
#include "localcontrast.h"
#include "softlight.h"
+#include "dehaze.h"
#include "guiutils.h"
class ImageEditorCoordinator;
@@ -136,6 +137,7 @@ protected:
DirPyrEqualizer* dirpyrequalizer;
HSVEqualizer* hsvequalizer;
SoftLight *softlight;
+ Dehaze *dehaze;
FilmSimulation *filmSimulation;
SensorBayer * sensorbayer;
SensorXTrans * sensorxtrans;