diff --git a/rtdata/languages/default b/rtdata/languages/default index 38f357d5a..acf03e48b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -724,6 +724,7 @@ HISTORY_MSG_491;White Balance HISTORY_MSG_492;RGB Curves HISTORY_MSG_493;L*a*b* Adjustments 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 @@ -1552,6 +1553,7 @@ 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_LABEL;Exposure TP_EXPOSURE_SATURATION;Saturation TP_EXPOSURE_TCMODE_FILMLIKE;Film-like diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 0ed91f23f..080a76410 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -116,6 +116,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..a38ad4687 --- /dev/null +++ b/rtengine/histmatching.cc @@ -0,0 +1,159 @@ +/* -*- 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" + + +namespace rtengine { + +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 < 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 = 20; + 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) -> void + { + int prev = 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.emplace_back(coord(i)); + curve.emplace_back(coord(v)); + prev = i; + } + } + }; + doit(0, idx, idx > step ? step : idx / 2); + doit(idx, int(mapping.size()), step); + if (curve[1] > 0.01) { + curve.insert(curve.begin(), 0.0); + curve.insert(curve.begin(), 0.0); + } + if (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(coord(mapping.back())); + } + curve.insert(curve.begin(), DCT_Spline); +} + +} // namespace + + +void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) +{ + const int rheight = 200; + RawMetaDataLocation rml; + eSensorType sensor_type; + int w, h; + ProcParams neutral; + std::unique_ptr source; + { + std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, true)); + source.reset(thumb->quickProcessImage(neutral, rheight, TI_Nearest)); + } + std::unique_ptr target; + { + double scale; + std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, 0.0, false)); + target.reset(thumb->processImage(neutral, sensor_type, rheight, TI_Nearest, getMetaData(), scale)); + } + 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.emplace_back(j); + } + + mappingToCurve(mapping, 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 765c4b704..c3f00300b 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -464,6 +464,20 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) if (aeListener) aeListener->autoExpChanged (params.toneCurve.expcomp, params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.hrenabled); + } else if (params.toneCurve.histmatching) { + imgsrc->getAutoMatchedToneCurve(params.toneCurve.curve); + + params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; + params.toneCurve.curve2 = { 0 }; + params.toneCurve.expcomp = 0.0; + params.toneCurve.brightness = 0; + params.toneCurve.contrast = 0; + params.toneCurve.black = 0; + params.toneCurve.hlcompr = 0; + + if (aeListener) { + aeListener->autoMatchedToneCurveChanged(params.toneCurve.curveMode, params.toneCurve.curve); + } } } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 80041e706..dfce03797 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -327,7 +327,8 @@ ToneCurveParams::ToneCurveParams() : saturation(0), shcompr(50), hlcompr(0), - hlcomprthresh(33) + hlcomprthresh(33), + histmatching(false) { } @@ -349,7 +350,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 @@ -2760,6 +2762,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); @@ -3534,6 +3537,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 7cc80b313..7cabc3aef 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -280,6 +280,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 a374ef06e..a199eb13a 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -185,6 +185,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 873cfd9bc..eea15c7a3 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -294,6 +294,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/simpleprocess.cc b/rtengine/simpleprocess.cc index 027600302..01d4922f5 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -749,7 +749,17 @@ private: int aehistcompr; imgsrc->getAutoExpHistogram (aehist, aehistcompr); ipf.getAutoExp (aehist, aehistcompr, params.toneCurve.clip, expcomp, bright, contr, black, hlcompr, hlcomprthresh); - } + } else if (params.toneCurve.histmatching) { + imgsrc->getAutoMatchedToneCurve(params.toneCurve.curve); + + params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; + params.toneCurve.curve2 = { 0 }; + params.toneCurve.expcomp = 0.0; + params.toneCurve.brightness = 0; + params.toneCurve.contrast = 0; + params.toneCurve.black = 0; + params.toneCurve.hlcompr = 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 b124eddfc..13afc6faa 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; @@ -605,6 +606,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; @@ -1198,6 +1200,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten 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 6de5d52e4..dfb85d54b 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/tonecurve.cc b/rtgui/tonecurve.cc index a9dd35466..7b07fbb58 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -22,12 +22,15 @@ #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"); CurveListener::setMulti(true); @@ -122,6 +125,10 @@ 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"))); + 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 +233,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 +257,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 +354,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 +373,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 +422,8 @@ void ToneCurve::hrenabledChanged () autolevels->set_inconsistent (false); } + setHistmatching(false); + if (hrenabled->get_active ()) { listener->panelChanged (EvHREnabled, M("GENERAL_ENABLED")); } else { @@ -419,6 +435,7 @@ void ToneCurve::methodChanged () { if (listener) { + setHistmatching(false); if (hrenabled->get_active ()) { listener->panelChanged (EvHRMethod, method->get_active_text ()); } @@ -471,6 +488,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 +501,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 +519,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 +564,8 @@ void ToneCurve::adjusterChanged (Adjuster* a, double newval) return; } + setHistmatching(false); + Glib::ustring costr; if (a == expcomp) { @@ -580,6 +602,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 +641,7 @@ void ToneCurve::neutral_pressed () } void ToneCurve::autolevels_toggled () { + setHistmatching(false); if (batchMode) { if (autolevels->get_inconsistent()) { @@ -727,6 +752,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 +792,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 +885,75 @@ 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 (histmatching->get_active()) { + listener->panelChanged(EvHistMatching, M("GENERAL_ENABLED")); + waitForAutoExp(); + } else { + listener->panelChanged(EvHistMatching, 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(); + expcomp->setValue(0); + 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() ) { + 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..5aae5f015 100644 --- a/rtgui/tonecurve.h +++ b/rtgui/tonecurve.h @@ -57,14 +57,18 @@ 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; + // used temporarily in eventing double nextExpcomp; int nextBrightness; @@ -73,6 +77,10 @@ protected: int nextHlcompr; int nextHlcomprthresh; bool nextHLRecons; + rtengine::procparams::ToneCurveParams::TcMode nextToneCurveMode; + std::vector nextToneCurve; + + void setHistmatching(bool enabled); public: ToneCurve (); @@ -107,6 +115,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 ();