diff --git a/.gitignore b/.gitignore
index 7141ec92d..21ebf986a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,8 +13,8 @@ Makefile
cmake_install.cmake
install_manifest.txt
-build
-Build
+build*
+Build*
Debug
RelWithDebInfo
MinSizeRel
diff --git a/rtdata/images/Dark/actions/atom.png b/rtdata/images/Dark/actions/atom.png
new file mode 100644
index 000000000..1e7ce3da0
Binary files /dev/null and b/rtdata/images/Dark/actions/atom.png differ
diff --git a/rtdata/images/Dark/actions/equalizer-narrow.png b/rtdata/images/Dark/actions/equalizer-narrow.png
new file mode 100644
index 000000000..dcf484ea7
Binary files /dev/null and b/rtdata/images/Dark/actions/equalizer-narrow.png differ
diff --git a/rtdata/images/Dark/actions/equalizer-wide.png b/rtdata/images/Dark/actions/equalizer-wide.png
new file mode 100644
index 000000000..50cfed8fa
Binary files /dev/null and b/rtdata/images/Dark/actions/equalizer-wide.png differ
diff --git a/rtdata/images/Light/actions/atom.png b/rtdata/images/Light/actions/atom.png
new file mode 100644
index 000000000..55feaf8d7
Binary files /dev/null and b/rtdata/images/Light/actions/atom.png differ
diff --git a/rtdata/images/Light/actions/equalizer-narrow.png b/rtdata/images/Light/actions/equalizer-narrow.png
new file mode 100644
index 000000000..c9e2c5b26
Binary files /dev/null and b/rtdata/images/Light/actions/equalizer-narrow.png differ
diff --git a/rtdata/images/Light/actions/equalizer-wide.png b/rtdata/images/Light/actions/equalizer-wide.png
new file mode 100644
index 000000000..f5b0aca68
Binary files /dev/null and b/rtdata/images/Light/actions/equalizer-wide.png differ
diff --git a/rtdata/languages/default b/rtdata/languages/default
index 46783f2ce..c6b6c98a8 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -845,6 +845,7 @@ HISTORY_MSG_599;Local - Noise bilateral
HISTORY_MSG_600;Local - Noise Equal. Black-White
HISTORY_MSG_601;Local - Shape Rt-spot method
HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction
+HISTORY_MSG_HISTMATCHING;Auto-matched Tone Curve
HISTORY_MSG_LOCALCONTRAST_AMOUNT;Local Contrast - Amount
HISTORY_MSG_LOCALCONTRAST_DARKNESS;Local Contrast - Darkness
HISTORY_MSG_LOCALCONTRAST_ENABLED;Local Contrast
@@ -936,6 +937,8 @@ MAIN_MSG_QOVERWRITE;Do you want to overwrite it?
MAIN_MSG_SETPATHFIRST;You first have to set a target path in Preferences in order to use this function!
MAIN_MSG_TOOMANYOPENEDITORS;Too many open editors.\nPlease close an editor to continue.
MAIN_MSG_WRITEFAILED;Failed to write\n"%1"\n\nMake sure that the folder exists and that you have write permission to it.
+MAIN_TAB_ADVANCED;Advanced
+MAIN_TAB_ADVANCED_TOOLTIP;Shortcut: Alt-w
MAIN_TAB_COLOR;Color
MAIN_TAB_COLOR_TOOLTIP;Shortcut: Alt-c
MAIN_TAB_DETAIL;Detail
@@ -956,8 +959,6 @@ MAIN_TAB_RAW;Raw
MAIN_TAB_RAW_TOOLTIP;Shortcut: Alt-r
MAIN_TAB_TRANSFORM;Transform
MAIN_TAB_TRANSFORM_TOOLTIP;Shortcut: Alt-t
-MAIN_TAB_WAVELET;Wavelet
-MAIN_TAB_WAVELET_TOOLTIP;Shortcut: Alt-w
MAIN_TOOLTIP_BACKCOLOR0;Background color of the preview: Theme-based\nShortcut: 9
MAIN_TOOLTIP_BACKCOLOR1;Background color of the preview: Black\nShortcut: 9
MAIN_TOOLTIP_BACKCOLOR2;Background color of the preview: White\nShortcut: 9
@@ -992,6 +993,7 @@ NAVIGATOR_XY_FULL;Width: %1, Height: %2
NAVIGATOR_XY_NA;x: --, y: --
OPTIONS_DEFIMG_MISSING;The default profile for non-raw photos could not be found or is not set.\n\nPlease check your profiles' directory, it may be missing or damaged.\n\nDefault internal values will be used.
OPTIONS_DEFRAW_MISSING;The default profile for raw photos could not be found or is not set.\n\nPlease check your profiles' directory, it may be missing or damaged.\n\nDefault internal values will be used.
+PARTIALPASTE_ADVANCEDGROUP;Advanced Settings
PARTIALPASTE_BASICGROUP;Basic Settings
PARTIALPASTE_CACORRECTION;Chromatic aberration correction
PARTIALPASTE_CHANNELMIXER;Channel mixer
@@ -1065,7 +1067,6 @@ PARTIALPASTE_SHARPENMICRO;Microcontrast
PARTIALPASTE_TM_FATTAL;HDR Tone mapping
PARTIALPASTE_VIBRANCE;Vibrance
PARTIALPASTE_VIGNETTING;Vignetting correction
-PARTIALPASTE_WAVELETGROUP;Wavelet Levels
PARTIALPASTE_WHITEBALANCE;White balance
PREFERENCES_ADD;Add
PREFERENCES_APPLNEXTSTARTUP;restart required
@@ -1689,6 +1690,8 @@ TP_EXPOSURE_CURVEEDITOR1;Tone curve 1
TP_EXPOSURE_CURVEEDITOR2;Tone curve 2
TP_EXPOSURE_CURVEEDITOR2_TOOLTIP;Please refer to the "Exposure > Tone Curves" RawPedia article to learn how to achieve the best results by using two tone curves.
TP_EXPOSURE_EXPCOMP;Exposure compensation
+TP_EXPOSURE_HISTMATCHING;Auto-matched Tone Curve
+TP_EXPOSURE_HISTMATCHING_TOOLTIP;Automatically adjust sliders and curves (except exposure compensation) to match the look of the embedded JPEG thumbnail.
TP_EXPOSURE_LABEL;Exposure
TP_EXPOSURE_SATURATION;Saturation
TP_EXPOSURE_TCMODE_FILMLIKE;Film-like
diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt
index f2023e88b..c12ade822 100644
--- a/rtengine/CMakeLists.txt
+++ b/rtengine/CMakeLists.txt
@@ -117,6 +117,7 @@ set(RTENGINESOURCEFILES
rtlensfun.cc
tmo_fattal02.cc
iplocalcontrast.cc
+ histmatching.cc
)
if(LENSFUN_HAS_LOAD_DIRECTORY)
diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc
new file mode 100644
index 000000000..be618d4d7
--- /dev/null
+++ b/rtengine/histmatching.cc
@@ -0,0 +1,249 @@
+/* -*- 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 "rawimagesource.h"
+#include "rtthumbnail.h"
+#include "curves.h"
+#include "color.h"
+#include "rt_math.h"
+#include "iccstore.h"
+#include "../rtgui/mydiagonalcurve.h"
+#include "improcfun.h"
+#define BENCHMARK
+#include "StopWatch.h"
+#include
+#include
+
+
+namespace rtengine {
+
+extern const Settings *settings;
+
+namespace {
+
+std::vector getCdf(const IImage8 &img)
+{
+ std::vector ret(256);
+ for (int y = 0; y < img.getHeight(); ++y) {
+ for (int x = 0; x < img.getWidth(); ++x) {
+ int lum = LIM(0, int(Color::rgbLuminance(float(img.r(y, x)), float(img.g(y, x)), float(img.b(y, x)))), 255);
+ ++ret[lum];
+ }
+ }
+
+ int sum = 0;
+ for (size_t i = 0; i < ret.size(); ++i) {
+ sum += ret[i];
+ ret[i] = sum;
+ }
+
+ return ret;
+}
+
+
+int findMatch(int val, const std::vector &cdf, int j)
+{
+ if (cdf[j] <= val) {
+ for (; j < int(cdf.size()); ++j) {
+ if (cdf[j] == val) {
+ return j;
+ } else if (cdf[j] > val) {
+ return (cdf[j] - val <= val - cdf[j-1] ? j : j-1);
+ }
+ }
+ return 255;
+ } else {
+ for (; j >= 0; --j) {
+ if (cdf[j] == val) {
+ return j;
+ } else if (cdf[j] < val) {
+ return (val - cdf[j] <= cdf[j+1] - val ? j : j+1);
+ }
+ }
+ return 0;
+ }
+}
+
+
+void mappingToCurve(const std::vector &mapping, std::vector &curve)
+{
+ curve.clear();
+
+ const int npoints = 8;
+ int idx = 1;
+ for (; idx < int(mapping.size()); ++idx) {
+ if (mapping[idx] >= idx) {
+ break;
+ }
+ }
+ int step = max(int(mapping.size())/npoints, 1);
+
+ auto coord = [](int v) -> double { return double(v)/255.0; };
+ auto doit =
+ [&](int start, int stop, int step, bool addstart) -> void
+ {
+ int prev = start;
+ if (addstart) {
+ curve.push_back(coord(start));
+ curve.push_back(coord(mapping[start]));
+ }
+ for (int i = start; i < stop; ++i) {
+ int v = mapping[i];
+ bool change = i > 0 && v != mapping[i-1];
+ int diff = i - prev;
+ if (change && std::abs(diff - step) <= 1) {
+ curve.push_back(coord(i));
+ curve.push_back(coord(v));
+ prev = i;
+ }
+ }
+ };
+ doit(0, idx, idx > step ? step : idx / 2, true);
+ doit(idx, int(mapping.size()), step, idx - step > step / 2);
+ if (curve.size() <= 2 || curve.back() < 0.99 || (1 - curve[curve.size()-2] > step / 512.0 && curve.back() < coord(mapping.back()))) {
+ curve.emplace_back(1.0);
+ curve.emplace_back(1.0);
+ }
+ if (curve.size() < 4) {
+ curve = { DCT_Linear }; // not enough points, fall back to linear
+ } else {
+ curve.insert(curve.begin(), DCT_Spline);
+ }
+}
+
+} // namespace
+
+
+void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve)
+{
+ BENCHFUN
+
+ if (settings->verbose) {
+ std::cout << "performing histogram matching for " << getFileName() << " on the embedded thumbnail" << std::endl;
+ }
+
+ if (!histMatchingCache.empty()) {
+ if (settings->verbose) {
+ std::cout << "tone curve found in cache" << std::endl;
+ outCurve = histMatchingCache;
+ return;
+ }
+ }
+
+ outCurve = { DCT_Linear };
+
+ int fw, fh;
+ getFullSize(fw, fh, TR_NONE);
+ int skip = 10;
+
+ if (settings->verbose) {
+ std::cout << "histogram matching: full raw image size is " << fw << "x" << fh << std::endl;
+ }
+
+ ProcParams neutral;
+
+ std::unique_ptr source;
+ {
+ RawMetaDataLocation rml;
+ eSensorType sensor_type;
+ int w, h;
+ std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, true));
+ if (!thumb) {
+ if (settings->verbose) {
+ std::cout << "histogram matching: no thumbnail found, generating a neutral curve" << std::endl;
+ }
+ histMatchingCache = outCurve;
+ return;
+ }
+ source.reset(thumb->quickProcessImage(neutral, fh / skip, TI_Nearest));
+
+ if (settings->verbose) {
+ std::cout << "histogram matching: extracted embedded thumbnail" << std::endl;
+ }
+ }
+
+ std::unique_ptr target;
+ {
+ int tw = source->getWidth(), th = source->getHeight();
+ float thumb_ratio = float(std::max(tw, th)) / float(std::min(tw, th));
+ float target_ratio = float(std::max(fw, fh)) / float(std::min(fw, fh));
+ int cx = 0, cy = 0;
+ if (std::abs(thumb_ratio - target_ratio) > 0.01) {
+ if (thumb_ratio > target_ratio) {
+ // crop the height
+ int ch = fh - (fw * float(th) / float(tw));
+ cy += ch / 2;
+ fh -= ch;
+ } else {
+ // crop the width
+ int cw = fw - (fh * float(tw) / float(th));
+ cx += cw / 2;
+ fw -= cw;
+ }
+ if (settings->verbose) {
+ std::cout << "histogram matching: cropping target to get an aspect ratio of " << std::fixed << std::setprecision(2) << thumb_ratio << ":1, new full size is " << fw << "x" << fh << std::endl;
+ }
+ }
+ PreviewProps pp(0, 0, fw, fh, skip);
+ ColorTemp currWB = getWB();
+ std::unique_ptr image(new Imagefloat(int(fw / skip), int(fh / skip)));
+ getImage(currWB, TR_NONE, image.get(), pp, neutral.toneCurve, neutral.raw);
+
+ // this could probably be made faster -- ideally we would need to just
+ // perform the transformation from camera space to the output space
+ // (taking gamma into account), but I couldn't find anything
+ // ready-made, so for now this will do. Remember the famous quote:
+ // "premature optimization is the root of all evil" :-)
+ convertColorSpace(image.get(), neutral.icm, currWB);
+ ImProcFunctions ipf(&neutral);
+ LabImage tmplab(image->getWidth(), image->getHeight());
+ ipf.rgb2lab(*image, tmplab, neutral.icm.working);
+ image.reset(ipf.lab2rgbOut(&tmplab, 0, 0, tmplab.W, tmplab.H, neutral.icm));
+ target.reset(image->to8());
+
+ if (settings->verbose) {
+ std::cout << "histogram matching: generated neutral rendering" << std::endl;
+ }
+ }
+ if (target->getWidth() != source->getWidth() || target->getHeight() != source->getHeight()) {
+ Image8 *tmp = new Image8(source->getWidth(), source->getHeight());
+ target->resizeImgTo(source->getWidth(), source->getHeight(), TI_Nearest, tmp);
+ target.reset(tmp);
+ }
+ std::vector scdf = getCdf(*source);
+ std::vector tcdf = getCdf(*target);
+
+ std::vector mapping;
+ int j = 0;
+ for (size_t i = 0; i < tcdf.size(); ++i) {
+ j = findMatch(tcdf[i], scdf, j);
+ mapping.push_back(j);
+ }
+
+ mappingToCurve(mapping, outCurve);
+
+ if (settings->verbose) {
+ std::cout << "histogram matching: generated curve with " << outCurve.size()/2 << " control points" << std::endl;
+ }
+
+ histMatchingCache = outCurve;
+}
+
+} // namespace rtengine
diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc
index 891fb1600..81d0583ac 100644
--- a/rtengine/iccstore.cc
+++ b/rtengine/iccstore.cc
@@ -574,6 +574,7 @@ public:
void setDefaultMonitorProfileName(const Glib::ustring &name)
{
+ MyMutex::MyLock lock(mutex);
defaultMonitorProfile = name;
}
diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h
index 5a71bb532..675243b65 100644
--- a/rtengine/imagesource.h
+++ b/rtengine/imagesource.h
@@ -137,6 +137,13 @@ public:
histGreenRaw.clear();
histBlueRaw.clear(); // only some sources will supply this
}
+
+ // for RAW files, compute a tone curve using histogram matching on the embedded thumbnail
+ virtual void getAutoMatchedToneCurve(std::vector &outCurve)
+ {
+ outCurve = { 0.0 };
+ }
+
double getDirPyrDenoiseExpComp ( )
{
return dirpyrdenoiseExpComp;
diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc
index 6004a676a..09aa8ae41 100644
--- a/rtengine/improccoordinator.cc
+++ b/rtengine/improccoordinator.cc
@@ -596,6 +596,24 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall)
aeListener->autoExpChanged(params.toneCurve.expcomp, params.toneCurve.brightness, params.toneCurve.contrast,
params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.hrenabled);
}
+ if (params.toneCurve.histmatching) {
+ imgsrc->getAutoMatchedToneCurve(params.toneCurve.curve);
+
+ if (params.toneCurve.autoexp) {
+ params.toneCurve.expcomp = 0.0;
+ }
+
+ params.toneCurve.autoexp = false;
+ params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE;
+ params.toneCurve.curve2 = { 0 };
+ params.toneCurve.brightness = 0;
+ params.toneCurve.contrast = 0;
+ params.toneCurve.black = 0;
+
+ if (aeListener) {
+ aeListener->autoMatchedToneCurveChanged(params.toneCurve.curveMode, params.toneCurve.curve);
+ }
+ }
}
progress("Exposure curve & CIELAB conversion...", 100 * readyphase / numofphases);
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index 1162af84f..92cbda443 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -331,7 +331,8 @@ curveMode(ToneCurveParams::TcMode::STD),
saturation(0),
shcompr(50),
hlcompr(0),
- hlcomprthresh(33)
+ hlcomprthresh(33),
+ histmatching(false)
{
}
@@ -353,7 +354,8 @@ bool ToneCurveParams::operator ==(const ToneCurveParams& other) const
&& saturation == other.saturation
&& shcompr == other.shcompr
&& hlcompr == other.hlcompr
- && hlcomprthresh == other.hlcomprthresh;
+ && hlcomprthresh == other.hlcomprthresh
+ && histmatching == other.histmatching;
}
bool ToneCurveParams::operator !=(const ToneCurveParams& other) const
@@ -3120,6 +3122,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
saveToKeyfile(!pedited || pedited->toneCurve.hlcompr, "Exposure", "HighlightCompr", toneCurve.hlcompr, keyFile);
saveToKeyfile(!pedited || pedited->toneCurve.hlcomprthresh, "Exposure", "HighlightComprThreshold", toneCurve.hlcomprthresh, keyFile);
saveToKeyfile(!pedited || pedited->toneCurve.shcompr, "Exposure", "ShadowCompr", toneCurve.shcompr, keyFile);
+ saveToKeyfile(!pedited || pedited->toneCurve.histmatching, "Exposure", "HistogramMatching", toneCurve.histmatching, keyFile);
// Highlight recovery
saveToKeyfile(!pedited || pedited->toneCurve.hrenabled, "HLRecovery", "Enabled", toneCurve.hrenabled, keyFile);
@@ -4018,6 +4021,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
assignFromKeyfile(keyFile, "Exposure", "Curve", pedited, toneCurve.curve, pedited->toneCurve.curve);
assignFromKeyfile(keyFile, "Exposure", "Curve2", pedited, toneCurve.curve2, pedited->toneCurve.curve2);
}
+ assignFromKeyfile(keyFile, "Exposure", "HistogramMatching", pedited, toneCurve.histmatching, pedited->toneCurve.histmatching);
}
if (keyFile.has_group("HLRecovery")) {
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index 041a1fe5b..c2e124dde 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -285,6 +285,7 @@ struct ToneCurveParams {
int shcompr;
int hlcompr; // Highlight Recovery's compression
int hlcomprthresh; // Highlight Recovery's threshold
+ bool histmatching; // histogram matching
ToneCurveParams();
diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h
index beaefc9dd..76737e948 100644
--- a/rtengine/rawimagesource.h
+++ b/rtengine/rawimagesource.h
@@ -95,6 +95,7 @@ protected:
float psGreenBrightness[4];
float psBlueBrightness[4];
+ std::vector histMatchingCache;
void hphd_vertical(float** hpmap, int col_from, int col_to);
void hphd_horizontal(float** hpmap, int row_from, int row_to);
@@ -185,6 +186,7 @@ public:
}
void getAutoExpHistogram(LUTu & histogram, int& histcompr);
void getRAWHistogram(LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw);
+ void getAutoMatchedToneCurve(std::vector &outCurve);
DCPProfile *getDCP(const ColorManagementParams &cmp, DCPProfile::ApplyState &as);
void convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb);
diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h
index 7ee7e7dba..e7b9efe4e 100644
--- a/rtengine/rtengine.h
+++ b/rtengine/rtengine.h
@@ -295,6 +295,8 @@ public:
* @param hlcomprthresh is the new threshold for hlcompr
* @param hlrecons set to true if HighLight Reconstruction is enabled */
virtual void autoExpChanged (double brightness, int bright, int contrast, int black, int hlcompr, int hlcomprthresh, bool hlrecons) {}
+
+ virtual void autoMatchedToneCurveChanged(procparams::ToneCurveParams::TcMode curveMode, const std::vector &curve) {}
};
class AutoCamListener
diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc
index 348b91031..1edbc6e09 100644
--- a/rtengine/rtthumbnail.cc
+++ b/rtengine/rtthumbnail.cc
@@ -915,7 +915,7 @@ IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int
}
// Full thumbnail processing, second stage if complete profile exists
-IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorType sensorType, int rheight, TypeInterpolation interp, const FramesMetaData *metadata, double& myscale)
+IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorType sensorType, int rheight, TypeInterpolation interp, const FramesMetaData *metadata, double& myscale, bool forMonitor)
{
unsigned int imgNum = 0;
if (isRaw) {
@@ -1294,8 +1294,13 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT
//ipf.colorCurve (labView, labView);
// obtain final image
- Image8* readyImg = new Image8 (fw, fh);
- ipf.lab2monitorRgb (labView, readyImg);
+ Image8* readyImg = nullptr;
+ if (forMonitor) {
+ readyImg = new Image8 (fw, fh);
+ ipf.lab2monitorRgb (labView, readyImg);
+ } else {
+ readyImg = ipf.lab2rgb(labView, 0, 0, fw, fh, params.icm);
+ }
delete labView;
delete baseImg;
diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h
index 2ee08de50..902f264fc 100644
--- a/rtengine/rtthumbnail.h
+++ b/rtengine/rtthumbnail.h
@@ -71,7 +71,7 @@ public:
void init ();
- IImage8* processImage (const procparams::ProcParams& pparams, eSensorType sensorType, int rheight, TypeInterpolation interp, const FramesMetaData *metadata, double& scale);
+ IImage8* processImage (const procparams::ProcParams& pparams, eSensorType sensorType, int rheight, TypeInterpolation interp, const FramesMetaData *metadata, double& scale, bool forMonitor=true);
IImage8* quickProcessImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp);
int getImageWidth (const procparams::ProcParams& pparams, int rheight, float &ratio);
void getDimensions (int& w, int& h, double& scaleFac);
diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc
index 6e1209d91..f7121a234 100644
--- a/rtengine/simpleprocess.cc
+++ b/rtengine/simpleprocess.cc
@@ -747,6 +747,21 @@ private:
imgsrc->getAutoExpHistogram(aehist, aehistcompr);
ipf.getAutoExp(aehist, aehistcompr, params.toneCurve.clip, expcomp, bright, contr, black, hlcompr, hlcomprthresh);
}
+ if (params.toneCurve.histmatching) {
+ imgsrc->getAutoMatchedToneCurve(params.toneCurve.curve);
+
+ if (params.toneCurve.autoexp) {
+ params.toneCurve.expcomp = 0.0;
+ }
+
+ params.toneCurve.autoexp = false;
+ params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE;
+ params.toneCurve.curve2 = { 0 };
+ params.toneCurve.brightness = 0;
+ params.toneCurve.contrast = 0;
+ params.toneCurve.black = 0;
+
+ }
// at this stage, we can flush the raw data to free up quite an important amount of memory
// commented out because it makes the application crash when batch processing...
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index c0be121a1..a61808bd9 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -49,6 +49,7 @@ void ParamsEdited::set(bool v)
toneCurve.expcomp = v;
toneCurve.hrenabled = v;
toneCurve.method = v;
+ toneCurve.histmatching = v;
retinex.cdcurve = v;
retinex.mapcurve = v;
retinex.cdHcurve = v;
@@ -721,6 +722,7 @@ void ParamsEdited::initFrom(const std::vector&
toneCurve.expcomp = toneCurve.expcomp && p.toneCurve.expcomp == other.toneCurve.expcomp;
toneCurve.hrenabled = toneCurve.hrenabled && p.toneCurve.hrenabled == other.toneCurve.hrenabled;
toneCurve.method = toneCurve.method && p.toneCurve.method == other.toneCurve.method;
+ toneCurve.histmatching = toneCurve.histmatching && p.toneCurve.histmatching == other.toneCurve.histmatching;
retinex.cdcurve = retinex.cdcurve && p.retinex.cdcurve == other.retinex.cdcurve;
retinex.mapcurve = retinex.mapcurve && p.retinex.mapcurve == other.retinex.mapcurve;
retinex.cdHcurve = retinex.cdHcurve && p.retinex.cdHcurve == other.retinex.cdHcurve;
@@ -1429,6 +1431,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
toEdit.toneCurve.method = mods.toneCurve.method;
}
+ if (toneCurve.histmatching) {
+ toEdit.toneCurve.histmatching = mods.toneCurve.histmatching;
+ }
+
if (retinex.enabled) {
toEdit.retinex.enabled = mods.retinex.enabled;
}
diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h
index 07f90a90e..f6f5d31e5 100644
--- a/rtgui/paramsedited.h
+++ b/rtgui/paramsedited.h
@@ -53,6 +53,7 @@ public:
bool expcomp;
bool hrenabled;
bool method;
+ bool histmatching;
};
class RetinexParamsEdited
diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc
index e03fec91d..f8fbd0383 100644
--- a/rtgui/partialpastedlg.cc
+++ b/rtgui/partialpastedlg.cc
@@ -43,8 +43,8 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
meta ->set_name ("PartialPasteHeader");
raw = Gtk::manage (new Gtk::CheckButton (M ("PARTIALPASTE_RAWGROUP")));
raw ->set_name ("PartialPasteHeader");
- wav = Gtk::manage (new Gtk::CheckButton (M ("PARTIALPASTE_WAVELETGROUP")));
- wav ->set_name ("PartialPasteHeader");
+ advanced = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_ADVANCEDGROUP")));
+ advanced ->set_name("PartialPasteHeader");
loc = Gtk::manage (new Gtk::CheckButton (M ("PARTIALPASTE_LOCGROUP")));
loc ->set_name ("PartialPasteHeader");
@@ -151,12 +151,10 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
vboxes[0]->pack_start (*sh, 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 (*retinex, Gtk::PACK_SHRINK, 2);
vboxes[0]->pack_start (*pcvignette, Gtk::PACK_SHRINK, 2);
vboxes[0]->pack_start (*gradient, Gtk::PACK_SHRINK, 2);
vboxes[0]->pack_start (*labcurve, Gtk::PACK_SHRINK, 2);
// vboxes[0]->pack_start (*locallab, Gtk::PACK_SHRINK, 2);
- vboxes[0]->pack_start (*colorappearance, Gtk::PACK_SHRINK, 2);
//DETAIL
vboxes[1]->pack_start (*detail, Gtk::PACK_SHRINK, 2);
@@ -202,8 +200,10 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
vboxes[4]->pack_start (*commonTrans, Gtk::PACK_SHRINK, 2);
//WAVELET
- vboxes[5]->pack_start (*wav, Gtk::PACK_SHRINK, 2);
+ vboxes[5]->pack_start (*advanced, Gtk::PACK_SHRINK, 2);
vboxes[5]->pack_start (*hseps[5], Gtk::PACK_SHRINK, 2);
+ vboxes[5]->pack_start (*retinex, Gtk::PACK_SHRINK, 2);
+ vboxes[5]->pack_start (*colorappearance, Gtk::PACK_SHRINK, 2);
vboxes[5]->pack_start (*wavelet, Gtk::PACK_SHRINK, 2);
//LOC
@@ -306,7 +306,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
compositionConn = composition->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::compositionToggled));
metaConn = meta->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::metaToggled));
rawConn = raw->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::rawToggled));
- wavConn = wav->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::wavToggled));
+ advancedConn = advanced->signal_toggled().connect (sigc::mem_fun(*this, &PartialPasteDlg::advancedToggled));
// locConn = loc->signal_toggled().connect (sigc::mem_fun (*this, &PartialPasteDlg::locToggled));
wbConn = wb->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true));
@@ -330,7 +330,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren
defringeConn = defringe->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true));
// locallabConn = locallab->signal_toggled().connect (sigc::bind (sigc::mem_fun (*basic, &Gtk::CheckButton::set_inconsistent), true));
- waveletConn = wavelet->signal_toggled().connect (sigc::bind (sigc::mem_fun(*wav, &Gtk::CheckButton::set_inconsistent), true));
+ waveletConn = wavelet->signal_toggled().connect (sigc::bind (sigc::mem_fun(*advanced, &Gtk::CheckButton::set_inconsistent), true));
icmConn = icm->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true));
//gamcsconn = gam->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true));
@@ -401,7 +401,7 @@ void PartialPasteDlg::everythingToggled ()
ConnectionBlocker compositionBlocker(compositionConn);
ConnectionBlocker metaBlocker(metaConn);
ConnectionBlocker rawBlocker(rawConn);
- ConnectionBlocker wavBlocker(wavConn);
+ ConnectionBlocker advancedBlocker(advancedConn);
everything->set_inconsistent (false);
@@ -414,7 +414,7 @@ void PartialPasteDlg::everythingToggled ()
composition->set_active (everything->get_active());
meta->set_active (everything->get_active());
raw->set_active (everything->get_active());
- wav->set_active (everything->get_active());
+ advanced->set_active(everything->get_active());
loc->set_active (everything->get_active());
//toggle group children
@@ -425,7 +425,7 @@ void PartialPasteDlg::everythingToggled ()
PartialPasteDlg::compositionToggled ();
PartialPasteDlg::metaToggled ();
PartialPasteDlg::rawToggled ();
- PartialPasteDlg::wavToggled ();
+ PartialPasteDlg::advancedToggled ();
// PartialPasteDlg::locToggled ();
}
@@ -498,9 +498,7 @@ void PartialPasteDlg::basicToggled ()
ConnectionBlocker fattalBlocker(fattalConn);
ConnectionBlocker pcvignetteBlocker(pcvignetteConn);
ConnectionBlocker gradientBlocker(gradientConn);
- ConnectionBlocker retinexBlocker(retinexConn);
ConnectionBlocker labcurveBlocker(labcurveConn);
- ConnectionBlocker colorappearanceBlocker(colorappearanceConn);
basic->set_inconsistent (false);
@@ -513,9 +511,7 @@ void PartialPasteDlg::basicToggled ()
fattal->set_active (basic->get_active ());
pcvignette->set_active (basic->get_active ());
gradient->set_active (basic->get_active ());
- retinex->set_active (basic->get_active ());
labcurve->set_active (basic->get_active ());
- colorappearance->set_active (basic->get_active ());
/*
locallab->set_active (basic->get_active ());
@@ -555,13 +551,17 @@ void PartialPasteDlg::detailToggled ()
dirpyreq->set_active (detail->get_active ());
}
-void PartialPasteDlg::wavToggled ()
+void PartialPasteDlg::advancedToggled ()
{
ConnectionBlocker waveletBlocker(waveletConn);
+ ConnectionBlocker retinexBlocker(retinexConn);
+ ConnectionBlocker colorappearanceBlocker(colorappearanceConn);
- wav->set_inconsistent (false);
- wavelet->set_active (wav->get_active ());
+ advanced->set_inconsistent (false);
+ wavelet->set_active (advanced->get_active ());
+ retinex->set_active (basic->get_active ());
+ colorappearance->set_active (basic->get_active ());
}
/*
void PartialPasteDlg::locToggled ()
diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h
index 45500237e..7308e0784 100644
--- a/rtgui/partialpastedlg.h
+++ b/rtgui/partialpastedlg.h
@@ -39,7 +39,7 @@ public:
Gtk::CheckButton* composition;
Gtk::CheckButton* meta;
Gtk::CheckButton* raw;
- Gtk::CheckButton* wav;
+ Gtk::CheckButton* advanced;
Gtk::CheckButton* loc;
// options in basic:
@@ -127,7 +127,7 @@ public:
Gtk::CheckButton* ff_BlurType;
Gtk::CheckButton* ff_ClipControl;
- sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, wavConn, locConn;
+ sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, advancedConn, locConn;
sigc::connection wbConn, exposureConn, localcontrastConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn, locallabConn;
sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn;
@@ -151,7 +151,7 @@ public:
void compositionToggled ();
void metaToggled ();
void rawToggled ();
- void wavToggled ();
+ void advancedToggled ();
void locToggled ();
};
diff --git a/rtgui/ppversion.h b/rtgui/ppversion.h
index c6f2598b0..1eb54d68b 100644
--- a/rtgui/ppversion.h
+++ b/rtgui/ppversion.h
@@ -1,13 +1,15 @@
#pragma once
// This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes
-#define PPVERSION 329
+#define PPVERSION 330
#define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified
/*
Log of version changes
+ 330 2018-20-01
+ Added 'Auto-matched Tone Curve' button, performing histogram matching
329 2017-12-09
- Added 'Enabled' flag for Channel Mixer, RGB Curves and HSV Equalizer
+ Added 'Enabled' flag for Channel Mixer, RGB Curves, HSV Equalizer and L*a*b* Adjustments
328 2017-11-22
Fix wrong type of ff_clipControl
327 2017-09-15
diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc
index a9dd35466..07822f857 100644
--- a/rtgui/tonecurve.cc
+++ b/rtgui/tonecurve.cc
@@ -22,12 +22,16 @@
#include
#include "ppversion.h"
#include "edit.h"
+#include "eventmapper.h"
using namespace rtengine;
using namespace rtengine::procparams;
ToneCurve::ToneCurve () : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LABEL"))
{
+ auto m = ProcEventMapper::getInstance();
+ EvHistMatching = m->newEvent(AUTOEXP, "HISTORY_MSG_HISTMATCHING");
+ EvHistMatchingBatch = m->newEvent(M_VOID, "HISTORY_MSG_HISTMATCHING");
CurveListener::setMulti(true);
@@ -122,6 +126,11 @@ ToneCurve::ToneCurve () : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LA
//----------- Curve 1 ------------------------------
pack_start (*Gtk::manage (new Gtk::HSeparator()));
+ histmatching = Gtk::manage(new Gtk::ToggleButton(M("TP_EXPOSURE_HISTMATCHING")));
+ histmatching->set_tooltip_markup(M("TP_EXPOSURE_HISTMATCHING_TOOLTIP"));
+ histmatchconn = histmatching->signal_toggled().connect(sigc::mem_fun(*this, &ToneCurve::histmatchingToggled));
+ pack_start(*histmatching, true, true, 2);
+
toneCurveMode = Gtk::manage (new MyComboBoxText ());
toneCurveMode->append (M("TP_EXPOSURE_TCMODE_STANDARD"));
toneCurveMode->append (M("TP_EXPOSURE_TCMODE_WEIGHTEDSTD"));
@@ -226,6 +235,8 @@ void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited)
toneCurveMode->set_active(rtengine::toUnderlying(pp->toneCurve.curveMode));
toneCurveMode2->set_active(rtengine::toUnderlying(pp->toneCurve.curveMode2));
+ histmatching->set_active(pp->toneCurve.histmatching);
+
if (pedited) {
expcomp->setEditedState (pedited->toneCurve.expcomp ? Edited : UnEdited);
black->setEditedState (pedited->toneCurve.black ? Edited : UnEdited);
@@ -248,6 +259,8 @@ void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited)
if (!pedited->toneCurve.curveMode2) {
toneCurveMode2->set_active(6);
}
+
+ histmatching->set_inconsistent(!pedited->toneCurve.histmatching);
}
enaconn.block (true);
@@ -343,6 +356,8 @@ void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited)
pp->toneCurve.curveMode2 = ToneCurveParams::TcMode::PERCEPTUAL;
}
+ pp->toneCurve.histmatching = histmatching->get_active();
+
if (pedited) {
pedited->toneCurve.expcomp = expcomp->getEditedState ();
pedited->toneCurve.black = black->getEditedState ();
@@ -360,6 +375,7 @@ void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited)
pedited->toneCurve.curveMode2 = toneCurveMode2->get_active_row_number() != 6;
pedited->toneCurve.method = method->get_active_row_number() != 4;
pedited->toneCurve.hrenabled = !hrenabled->get_inconsistent();
+ pedited->toneCurve.histmatching = !histmatching->get_inconsistent();
}
pp->toneCurve.hrenabled = hrenabled->get_active();
@@ -408,6 +424,8 @@ void ToneCurve::hrenabledChanged ()
autolevels->set_inconsistent (false);
}
+ setHistmatching(false);
+
if (hrenabled->get_active ()) {
listener->panelChanged (EvHREnabled, M("GENERAL_ENABLED"));
} else {
@@ -419,6 +437,7 @@ void ToneCurve::methodChanged ()
{
if (listener) {
+ setHistmatching(false);
if (hrenabled->get_active ()) {
listener->panelChanged (EvHRMethod, method->get_active_text ());
}
@@ -430,6 +449,7 @@ void ToneCurve::setRaw (bool raw)
disableListener ();
method->set_sensitive (raw);
hrenabled->set_sensitive (raw);
+ histmatching->set_sensitive(raw);
enableListener ();
}
@@ -471,6 +491,7 @@ void ToneCurve::curveChanged (CurveEditor* ce)
{
if (listener) {
+ setHistmatching(false);
if (ce == shape) {
listener->panelChanged (EvToneCurve1, M("HISTORY_CUSTOMCURVE"));
} else if (ce == shape2) {
@@ -483,6 +504,7 @@ void ToneCurve::curveMode1Changed ()
{
//if (listener) listener->panelChanged (EvToneCurveMode, toneCurveMode->get_active_text());
if (listener) {
+ setHistmatching(false);
Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::curveMode1Changed_));
}
}
@@ -500,6 +522,7 @@ void ToneCurve::curveMode2Changed ()
{
//if (listener) listener->panelChanged (EvToneCurveMode, toneCurveMode->get_active_text());
if (listener) {
+ setHistmatching(false);
Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::curveMode2Changed_));
}
}
@@ -544,6 +567,10 @@ void ToneCurve::adjusterChanged (Adjuster* a, double newval)
return;
}
+ if (a != expcomp && a != hlcompr && a != hlcomprthresh) {
+ setHistmatching(false);
+ }
+
Glib::ustring costr;
if (a == expcomp) {
@@ -580,6 +607,8 @@ void ToneCurve::neutral_pressed ()
// This method deselects auto levels and HL reconstruction auto
// and sets neutral values to params in exposure panel
+ setHistmatching(false);
+
if (batchMode) {
autolevels->set_inconsistent (false);
autoconn.block (true);
@@ -617,6 +646,7 @@ void ToneCurve::neutral_pressed ()
}
void ToneCurve::autolevels_toggled ()
{
+ setHistmatching(false);
if (batchMode) {
if (autolevels->get_inconsistent()) {
@@ -727,6 +757,7 @@ void ToneCurve::waitForAutoExp ()
toneCurveMode2->set_sensitive (false);
hrenabled->set_sensitive(false);
method->set_sensitive(false);
+ histmatching->set_sensitive(false);
}
void ToneCurve::autoExpChanged (double expcomp, int bright, int contr, int black, int hlcompr, int hlcomprthresh, bool hlrecons)
@@ -766,6 +797,7 @@ void ToneCurve::enableAll ()
toneCurveMode2->set_sensitive (true);
hrenabled->set_sensitive(true);
method->set_sensitive(true);
+ histmatching->set_sensitive(true);
}
bool ToneCurve::autoExpComputed_ ()
@@ -858,3 +890,79 @@ void ToneCurve::updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & his
shape->updateBackgroundHistogram (histToneCurve);
}
+
+
+void ToneCurve::setHistmatching(bool enabled)
+{
+ if (histmatching->get_active()) {
+ histmatchconn.block(true);
+ histmatching->set_active(enabled);
+ histmatchconn.block(false);
+ histmatching->set_inconsistent(false);
+ }
+}
+
+
+void ToneCurve::histmatchingToggled()
+{
+ if (listener) {
+ if (!batchMode) {
+ if (histmatching->get_active()) {
+ listener->panelChanged(EvHistMatching, M("GENERAL_ENABLED"));
+ waitForAutoExp();
+ } else {
+ listener->panelChanged(EvHistMatching, M("GENERAL_DISABLED"));
+ }
+ } else {
+ listener->panelChanged(EvHistMatchingBatch, histmatching->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED"));
+ }
+ }
+}
+
+
+void ToneCurve::autoMatchedToneCurveChanged(rtengine::procparams::ToneCurveParams::TcMode curveMode, const std::vector &curve)
+{
+ nextToneCurveMode = curveMode;
+ nextToneCurve = curve;
+
+ const auto func = [](gpointer data) -> gboolean {
+ static_cast(data)->histmatchingComputed();
+
+ return FALSE;
+ };
+
+ idle_register.add(func, this);
+}
+
+
+bool ToneCurve::histmatchingComputed()
+{
+ GThreadLock lock;
+ disableListener();
+ enableAll();
+ brightness->setValue(0);
+ contrast->setValue(0);
+ black->setValue(0);
+ hlcompr->setValue(0);
+
+ if (!black->getAddMode()) {
+ shcompr->set_sensitive(!((int)black->getValue() == 0));
+ }
+
+ if (autolevels->get_active() ) {
+ expcomp->setValue(0);
+ autoconn.block(true);
+ autolevels->set_active(false);
+ autoconn.block(false);
+ autolevels->set_inconsistent(false);
+ }
+
+ toneCurveMode->set_active(rtengine::toUnderlying(nextToneCurveMode));
+ shape->setCurve(nextToneCurve);
+ shape2->setCurve({ DCT_Linear });
+ shape->openIfNonlinear();
+
+ enableListener();
+
+ return false;
+}
diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h
index 11ec64b96..e85fefa39 100644
--- a/rtgui/tonecurve.h
+++ b/rtgui/tonecurve.h
@@ -57,14 +57,19 @@ protected:
Adjuster* saturation;
MyComboBoxText* toneCurveMode;
MyComboBoxText* toneCurveMode2;
+ Gtk::ToggleButton *histmatching;
bool clipDirty, lastAuto;
sigc::connection autoconn, neutralconn, tcmodeconn, tcmode2conn;
+ sigc::connection histmatchconn;
CurveEditorGroup* curveEditorG;
CurveEditorGroup* curveEditorG2;
DiagonalCurveEditor* shape;
DiagonalCurveEditor* shape2;
+ rtengine::ProcEvent EvHistMatching;
+ rtengine::ProcEvent EvHistMatchingBatch;
+
// used temporarily in eventing
double nextExpcomp;
int nextBrightness;
@@ -73,6 +78,10 @@ protected:
int nextHlcompr;
int nextHlcomprthresh;
bool nextHLRecons;
+ rtengine::procparams::ToneCurveParams::TcMode nextToneCurveMode;
+ std::vector nextToneCurve;
+
+ void setHistmatching(bool enabled);
public:
ToneCurve ();
@@ -107,6 +116,10 @@ public:
bool isCurveExpanded ();
void updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve,/* LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histLRETI);
+ void histmatchingToggled();
+ void autoMatchedToneCurveChanged(rtengine::procparams::ToneCurveParams::TcMode curveMode, const std::vector &curve);
+ bool histmatchingComputed();
+
void setRaw (bool raw);
void hrenabledChanged ();
diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc
index b321bcc8d..10bdac2a4 100644
--- a/rtgui/toolpanelcoord.cc
+++ b/rtgui/toolpanelcoord.cc
@@ -36,7 +36,7 @@ ToolPanelCoordinator::ToolPanelCoordinator(bool batch) : ipc(nullptr), hasChange
colorPanel = Gtk::manage(new ToolVBox());
transformPanel = Gtk::manage(new ToolVBox());
rawPanel = Gtk::manage(new ToolVBox());
- waveletPanel = Gtk::manage(new ToolVBox());
+ advancedPanel = Gtk::manage (new ToolVBox ());
locallabPanel = Gtk::manage(new ToolVBox());
coarse = Gtk::manage(new CoarsePanel());
@@ -116,16 +116,16 @@ ToolPanelCoordinator::ToolPanelCoordinator(bool batch) : ipc(nullptr), hasChange
addPanel(colorPanel, colortoning);
addPanel(exposurePanel, epd);
addPanel(exposurePanel, fattal);
- addPanel(exposurePanel, retinex);
+ addPanel (advancedPanel, retinex);
addPanel(exposurePanel, pcvignette);
addPanel(exposurePanel, gradient);
addPanel(exposurePanel, lcurve);
- addPanel(exposurePanel, colorappearance);
+ addPanel (advancedPanel, colorappearance);
addPanel(detailsPanel, impulsedenoise);
addPanel(detailsPanel, dirpyrdenoise);
addPanel(detailsPanel, defringe);
addPanel(detailsPanel, dirpyrequalizer);
- addPanel(waveletPanel, wavelet);
+ addPanel (advancedPanel, wavelet);
addPanel(locallabPanel, locallab);
addPanel(transformPanel, crop);
addPanel(transformPanel, resize);
@@ -166,7 +166,7 @@ ToolPanelCoordinator::ToolPanelCoordinator(bool batch) : ipc(nullptr), hasChange
colorPanelSW = Gtk::manage(new MyScrolledWindow());
transformPanelSW = Gtk::manage(new MyScrolledWindow());
rawPanelSW = Gtk::manage(new MyScrolledWindow());
- waveletPanelSW = Gtk::manage(new MyScrolledWindow());
+ advancedPanelSW = Gtk::manage (new MyScrolledWindow ());
locallabPanelSW = Gtk::manage(new MyScrolledWindow());
updateVScrollbars(options.hideTPVScrollbar);
@@ -191,9 +191,9 @@ ToolPanelCoordinator::ToolPanelCoordinator(bool batch) : ipc(nullptr), hasChange
colorPanel->pack_start(*Gtk::manage(new Gtk::HSeparator), Gtk::PACK_SHRINK, 0);
colorPanel->pack_start(*vbPanelEnd[2], Gtk::PACK_SHRINK, 4);
- waveletPanelSW->add(*waveletPanel);
- waveletPanel->pack_start(*Gtk::manage(new Gtk::HSeparator), Gtk::PACK_SHRINK, 0);
- waveletPanel->pack_start(*vbPanelEnd[5], Gtk::PACK_SHRINK, 0);
+ advancedPanelSW->add (*advancedPanel);
+ advancedPanel->pack_start (*Gtk::manage (new Gtk::HSeparator), Gtk::PACK_SHRINK, 0);
+ advancedPanel->pack_start (*vbPanelEnd[5], Gtk::PACK_SHRINK, 0);
locallabPanelSW->add(*locallabPanel);
locallabPanel->pack_start(*Gtk::manage(new Gtk::HSeparator), Gtk::PACK_SHRINK, 0);
@@ -213,7 +213,7 @@ ToolPanelCoordinator::ToolPanelCoordinator(bool batch) : ipc(nullptr), hasChange
toiE = Gtk::manage(new TextOrIcon("exposure.png", M("MAIN_TAB_EXPOSURE"), M("MAIN_TAB_EXPOSURE_TOOLTIP"), type));
toiD = Gtk::manage(new TextOrIcon("detail.png", M("MAIN_TAB_DETAIL"), M("MAIN_TAB_DETAIL_TOOLTIP"), type));
toiC = Gtk::manage(new TextOrIcon("colour.png", M("MAIN_TAB_COLOR"), M("MAIN_TAB_COLOR_TOOLTIP"), type));
- toiW = Gtk::manage(new TextOrIcon("wavelet.png", M("MAIN_TAB_WAVELET"), M("MAIN_TAB_WAVELET_TOOLTIP"), type));
+ toiW = Gtk::manage (new TextOrIcon ("atom.png", M ("MAIN_TAB_ADVANCED"), M ("MAIN_TAB_ADVANCED_TOOLTIP"), type));
toiL = Gtk::manage(new TextOrIcon("openhand.png", M("MAIN_TAB_LOCALLAB"), M("MAIN_TAB_LOCALLAB_TOOLTIP"), type));
toiT = Gtk::manage(new TextOrIcon("transform.png", M("MAIN_TAB_TRANSFORM"), M("MAIN_TAB_TRANSFORM_TOOLTIP"), type));
@@ -223,7 +223,7 @@ ToolPanelCoordinator::ToolPanelCoordinator(bool batch) : ipc(nullptr), hasChange
toolPanelNotebook->append_page(*exposurePanelSW, *toiE);
toolPanelNotebook->append_page(*detailsPanelSW, *toiD);
toolPanelNotebook->append_page(*colorPanelSW, *toiC);
- toolPanelNotebook->append_page(*waveletPanelSW, *toiW);
+ toolPanelNotebook->append_page (*advancedPanelSW, *toiW);
toolPanelNotebook->append_page(*locallabPanelSW, *toiL);
toolPanelNotebook->append_page(*transformPanelSW, *toiT);
toolPanelNotebook->append_page(*rawPanelSW, *toiR);
@@ -825,7 +825,7 @@ bool ToolPanelCoordinator::handleShortcutKey(GdkEventKey* event)
return true;
case GDK_KEY_w:
- toolPanelNotebook->set_current_page(toolPanelNotebook->page_num(*waveletPanelSW));
+ toolPanelNotebook->set_current_page (toolPanelNotebook->page_num (*advancedPanelSW));
return true;
case GDK_KEY_o:
@@ -850,7 +850,7 @@ void ToolPanelCoordinator::updateVScrollbars(bool hide)
colorPanelSW->set_policy(Gtk::POLICY_AUTOMATIC, policy);
transformPanelSW->set_policy(Gtk::POLICY_AUTOMATIC, policy);
rawPanelSW->set_policy(Gtk::POLICY_AUTOMATIC, policy);
- waveletPanelSW->set_policy(Gtk::POLICY_AUTOMATIC, policy);
+ advancedPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy);
locallabPanelSW->set_policy(Gtk::POLICY_AUTOMATIC, policy);
for (auto currExp : expList) {
diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h
index 6aef40aed..c02fe29d0 100644
--- a/rtgui/toolpanelcoord.h
+++ b/rtgui/toolpanelcoord.h
@@ -162,7 +162,7 @@ protected:
ToolVBox* colorPanel;
ToolVBox* transformPanel;
ToolVBox* rawPanel;
- ToolVBox* waveletPanel;
+ ToolVBox* advancedPanel;
//<<<<<<< HEAD
ToolVBox* locallabPanel;
// Gtk::Notebook* metadataPanel;
@@ -189,7 +189,7 @@ protected:
Gtk::ScrolledWindow* colorPanelSW;
Gtk::ScrolledWindow* transformPanelSW;
Gtk::ScrolledWindow* rawPanelSW;
- Gtk::ScrolledWindow* waveletPanelSW;
+ Gtk::ScrolledWindow* advancedPanelSW;
Gtk::ScrolledWindow* locallabPanelSW;
std::vector expList;
diff --git a/tools/source_icons/scalable/atom.file b/tools/source_icons/scalable/atom.file
new file mode 100644
index 000000000..8c7faa135
--- /dev/null
+++ b/tools/source_icons/scalable/atom.file
@@ -0,0 +1 @@
+atom.png,w22,actions
diff --git a/tools/source_icons/scalable/atom.svg b/tools/source_icons/scalable/atom.svg
new file mode 100644
index 000000000..33eb0a7e5
--- /dev/null
+++ b/tools/source_icons/scalable/atom.svg
@@ -0,0 +1,121 @@
+
+
+
+
diff --git a/tools/source_icons/scalable/equalizer-narrow.file b/tools/source_icons/scalable/equalizer-narrow.file
new file mode 100644
index 000000000..c922b3554
--- /dev/null
+++ b/tools/source_icons/scalable/equalizer-narrow.file
@@ -0,0 +1 @@
+equalizer-narrow.png,w22,actions
diff --git a/tools/source_icons/scalable/equalizer-narrow.svg b/tools/source_icons/scalable/equalizer-narrow.svg
new file mode 100644
index 000000000..b31128b36
--- /dev/null
+++ b/tools/source_icons/scalable/equalizer-narrow.svg
@@ -0,0 +1,201 @@
+
+
+
+
diff --git a/tools/source_icons/scalable/equalizer-wide.file b/tools/source_icons/scalable/equalizer-wide.file
new file mode 100644
index 000000000..22ee0b4b9
--- /dev/null
+++ b/tools/source_icons/scalable/equalizer-wide.file
@@ -0,0 +1 @@
+equalizer-wide.png,w22,actions
diff --git a/tools/source_icons/scalable/equalizer-wide.svg b/tools/source_icons/scalable/equalizer-wide.svg
new file mode 100644
index 000000000..dcf184f56
--- /dev/null
+++ b/tools/source_icons/scalable/equalizer-wide.svg
@@ -0,0 +1,256 @@
+
+
+
+