From 3c2e30dbccad414198822006f206cb75e2350137 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 14 Jan 2018 21:36:25 +0100 Subject: [PATCH 01/19] renamed Wavelet tab to Advanced and moved more tools there (see #4298) --- rtdata/languages/default | 6 +++--- rtgui/partialpastedlg.cc | 40 ++++++++++++++++++++-------------------- rtgui/partialpastedlg.h | 6 +++--- rtgui/toolpanelcoord.cc | 26 +++++++++++++------------- rtgui/toolpanelcoord.h | 4 ++-- 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index ec93fd41e..ccadda440 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -815,6 +815,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 @@ -833,8 +835,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 @@ -869,6 +869,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 @@ -940,7 +941,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 diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 898b6dad5..392da6db3 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"); // options in basic: wb = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_WHITEBALANCE"))); @@ -147,11 +147,9 @@ 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 (*colorappearance, Gtk::PACK_SHRINK, 2); //DETAIL vboxes[1]->pack_start (*detail, Gtk::PACK_SHRINK, 2); @@ -170,7 +168,6 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[2]->pack_start (*icm, Gtk::PACK_SHRINK, 2); //vboxes[2]->pack_start (*gam, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*vibrance, Gtk::PACK_SHRINK, 2); - vboxes[2]->pack_start (*chmixer, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*blackwhite, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*hsveq, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*filmSimulation, Gtk::PACK_SHRINK, 2); @@ -197,8 +194,11 @@ 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 (*chmixer, 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); //RAW @@ -296,7 +296,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)); wbConn = wb->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); exposureConn = exposure->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); @@ -318,7 +318,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren dirpyreqConn = dirpyreq->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)); - 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)); @@ -389,7 +389,7 @@ void PartialPasteDlg::everythingToggled () ConnectionBlocker compositionBlocker(compositionConn); ConnectionBlocker metaBlocker(metaConn); ConnectionBlocker rawBlocker(rawConn); - ConnectionBlocker wavBlocker(wavConn); + ConnectionBlocker advancedBlocker(advancedConn); everything->set_inconsistent (false); @@ -401,7 +401,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()); //toggle group children PartialPasteDlg::basicToggled (); @@ -411,7 +411,7 @@ void PartialPasteDlg::everythingToggled () PartialPasteDlg::compositionToggled (); PartialPasteDlg::metaToggled (); PartialPasteDlg::rawToggled (); - PartialPasteDlg::wavToggled (); + PartialPasteDlg::advancedToggled (); } void PartialPasteDlg::rawToggled () @@ -481,9 +481,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); @@ -495,9 +493,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 ()); } void PartialPasteDlg::detailToggled () @@ -522,13 +518,19 @@ void PartialPasteDlg::detailToggled () dirpyreq->set_active (detail->get_active ()); } -void PartialPasteDlg::wavToggled () +void PartialPasteDlg::advancedToggled () { ConnectionBlocker waveletBlocker(waveletConn); + ConnectionBlocker chmixerBlocker(chmixerConn); + 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 ()); + chmixer->set_active (color->get_active ()); + retinex->set_active (basic->get_active ()); + colorappearance->set_active (basic->get_active ()); } void PartialPasteDlg::colorToggled () @@ -536,7 +538,6 @@ void PartialPasteDlg::colorToggled () ConnectionBlocker icmBlocker(icmConn); ConnectionBlocker vibranceBlocker(vibranceConn); - ConnectionBlocker chmixerBlocker(chmixerConn); ConnectionBlocker chmixerbwBlocker(chmixerbwConn); ConnectionBlocker hsveqBlocker(hsveqConn); ConnectionBlocker filmSimulationBlocker(filmSimulationConn); @@ -549,7 +550,6 @@ void PartialPasteDlg::colorToggled () icm->set_active (color->get_active ()); //gam->set_active (color->get_active ()); vibrance->set_active (color->get_active ()); - chmixer->set_active (color->get_active ()); blackwhite->set_active (color->get_active ()); hsveq->set_active (color->get_active ()); filmSimulation->set_active (color->get_active ()); diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index d1ae056c3..08e8ed81e 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; // options in basic: Gtk::CheckButton* wb; @@ -123,7 +123,7 @@ public: Gtk::CheckButton* ff_BlurType; Gtk::CheckButton* ff_ClipControl; - sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, wavConn; + 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; @@ -147,7 +147,7 @@ public: void compositionToggled (); void metaToggled (); void rawToggled (); - void wavToggled (); + void advancedToggled (); }; #endif diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 7726f9a5e..464aea25b 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -36,7 +36,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan 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 ()); coarse = Gtk::manage (new CoarsePanel ()); toneCurve = Gtk::manage (new ToneCurve ()); @@ -102,7 +102,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan addPanel (colorPanel, whitebalance); addPanel (exposurePanel, toneCurve); addPanel (colorPanel, vibrance); - addPanel (colorPanel, chmixer); + addPanel (advancedPanel, chmixer); addPanel (colorPanel, blackwhite); addPanel (exposurePanel, localContrast); addPanel (exposurePanel, shadowshighlights); @@ -115,16 +115,16 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan 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 (transformPanel, crop); addPanel (transformPanel, resize); addPanel (resize->getPackBox(), prsharpening, 2); @@ -161,7 +161,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan 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 ()); updateVScrollbars (options.hideTPVScrollbar); // load panel endings @@ -185,9 +185,9 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan 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); transformPanelSW->add (*transformPanel); transformPanel->pack_start (*Gtk::manage (new Gtk::HSeparator), Gtk::PACK_SHRINK, 0); @@ -204,7 +204,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan 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 ("wavelet.png", M ("MAIN_TAB_ADVANCED"), M ("MAIN_TAB_ADVANCED_TOOLTIP"), type)); toiT = Gtk::manage (new TextOrIcon ("transform.png", M ("MAIN_TAB_TRANSFORM"), M ("MAIN_TAB_TRANSFORM_TOOLTIP"), type)); toiR = Gtk::manage (new TextOrIcon ("raw.png", M ("MAIN_TAB_RAW"), M ("MAIN_TAB_RAW_TOOLTIP"), type)); toiM = Gtk::manage (new TextOrIcon ("meta.png", M ("MAIN_TAB_METADATA"), M ("MAIN_TAB_METADATA_TOOLTIP"), type)); @@ -212,7 +212,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan 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 (*transformPanelSW, *toiT); toolPanelNotebook->append_page (*rawPanelSW, *toiR); toolPanelNotebook->append_page (*metadata, *toiM); @@ -801,7 +801,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_m: @@ -822,7 +822,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); for (auto currExp : expList) { currExp->updateVScrollbars (hide); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 11f6dfc0a..c6d2e6380 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -160,7 +160,7 @@ protected: ToolVBox* colorPanel; ToolVBox* transformPanel; ToolVBox* rawPanel; - ToolVBox* waveletPanel; + ToolVBox* advancedPanel; ToolBar* toolBar; TextOrIcon* toiE; @@ -179,7 +179,7 @@ protected: Gtk::ScrolledWindow* colorPanelSW; Gtk::ScrolledWindow* transformPanelSW; Gtk::ScrolledWindow* rawPanelSW; - Gtk::ScrolledWindow* waveletPanelSW; + Gtk::ScrolledWindow* advancedPanelSW; std::vector expList; From bb56d73cc8999fac29e61a2914b3bad1f4b18412 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 17 Jan 2018 01:12:13 +0100 Subject: [PATCH 02/19] started working on proof-of-concept histogram matching --- rtdata/languages/default | 2 + rtengine/CMakeLists.txt | 1 + rtengine/histmatching.cc | 159 ++++++++++++++++++++++++++++++++++ rtengine/iccstore.cc | 1 + rtengine/imagesource.h | 7 ++ rtengine/improccoordinator.cc | 14 +++ rtengine/procparams.cc | 8 +- rtengine/procparams.h | 1 + rtengine/rawimagesource.h | 1 + rtengine/rtengine.h | 2 + rtengine/simpleprocess.cc | 12 ++- rtgui/paramsedited.cc | 6 ++ rtgui/paramsedited.h | 1 + rtgui/tonecurve.cc | 99 +++++++++++++++++++++ rtgui/tonecurve.h | 12 +++ 15 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 rtengine/histmatching.cc 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 (); From 52957e9eabc9c56c47e965cdfee0cfd6a4f38a02 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 17 Jan 2018 01:41:28 +0100 Subject: [PATCH 03/19] further experiments with histogram matching --- rtengine/histmatching.cc | 13 ++++++++++--- rtengine/rtthumbnail.cc | 11 ++++++++--- rtengine/rtthumbnail.h | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index a38ad4687..6d8856958 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -79,7 +79,7 @@ void mappingToCurve(const std::vector &mapping, std::vector &curve) { curve.clear(); - const int npoints = 20; + const int npoints = 8; int idx = 1; for (; idx < int(mapping.size()); ++idx) { if (mapping[idx] >= idx) { @@ -133,10 +133,17 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) source.reset(thumb->quickProcessImage(neutral, rheight, TI_Nearest)); } std::unique_ptr target; - { + if (true) { + neutral.icm.working = "RT_sRGB"; + // faster, but has problems likely due to color space transformations that I do not properly understand... 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)); + target.reset(thumb->processImage(neutral, sensor_type, rheight, TI_Nearest, getMetaData(), scale, false)); + } else { + ProcessingJob *job = ProcessingJob::create(this, neutral, true); + int err = 0; + std::unique_ptr tmp(processImage(job, err, nullptr, false)); + target.reset(static_cast(tmp.get())->to8()); } if (target->getWidth() != source->getWidth() || target->getHeight() != source->getHeight()) { Image8 *tmp = new Image8(source->getWidth(), source->getHeight()); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index e84214bd4..59d19cc15 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) { @@ -1293,8 +1293,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); From bc89e24ab7e1f467448a21c795bc67e6495a0c39 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 17 Jan 2018 21:16:22 +0100 Subject: [PATCH 04/19] working version -- yay! --- rtengine/histmatching.cc | 49 ++++++++++++++++++++++------------- rtengine/improccoordinator.cc | 3 ++- rtengine/simpleprocess.cc | 3 ++- rtgui/tonecurve.cc | 14 +++++++--- rtgui/tonecurve.h | 1 + 5 files changed, 46 insertions(+), 24 deletions(-) diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 6d8856958..8b506432d 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -25,6 +25,7 @@ #include "rt_math.h" #include "iccstore.h" #include "../rtgui/mydiagonalcurve.h" +#include "improcfun.h" namespace rtengine { @@ -54,7 +55,7 @@ std::vector getCdf(const IImage8 &img) int findMatch(int val, const std::vector &cdf, int j) { if (cdf[j] <= val) { - for (; j < cdf.size(); ++j) { + for (; j < int(cdf.size()); ++j) { if (cdf[j] == val) { return j; } else if (cdf[j] > val) { @@ -123,27 +124,39 @@ void mappingToCurve(const std::vector &mapping, std::vector &curve) void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) { const int rheight = 200; - RawMetaDataLocation rml; - eSensorType sensor_type; - int w, h; ProcParams neutral; + std::unique_ptr target; + { + int tr = TR_NONE; + int fw, fh; + getFullSize(fw, fh, tr); + int skip = fh / rheight; + PreviewProps pp(0, 0, fw, fh, skip); + ColorTemp currWB = getWB(); + std::unique_ptr image(new Imagefloat(int(fw / skip), int(fh / skip))); + neutral.raw.bayersensor.method = procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::FAST); + neutral.raw.xtranssensor.method = procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::FAST); + getImage(currWB, tr, 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()); + } 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)); - source.reset(thumb->quickProcessImage(neutral, rheight, TI_Nearest)); - } - std::unique_ptr target; - if (true) { - neutral.icm.working = "RT_sRGB"; - // faster, but has problems likely due to color space transformations that I do not properly understand... - 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, false)); - } else { - ProcessingJob *job = ProcessingJob::create(this, neutral, true); - int err = 0; - std::unique_ptr tmp(processImage(job, err, nullptr, false)); - target.reset(static_cast(tmp.get())->to8()); + source.reset(thumb->quickProcessImage(neutral, target->getHeight(), TI_Nearest)); } if (target->getWidth() != source->getWidth() || target->getHeight() != source->getHeight()) { Image8 *tmp = new Image8(source->getWidth(), source->getHeight()); diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index c3f00300b..b4edab549 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -466,7 +466,8 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.hrenabled); } else if (params.toneCurve.histmatching) { imgsrc->getAutoMatchedToneCurve(params.toneCurve.curve); - + + params.toneCurve.histmatching = false; params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; params.toneCurve.curve2 = { 0 }; params.toneCurve.expcomp = 0.0; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 01d4922f5..7b636797e 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -751,7 +751,8 @@ private: 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.histmatching = false; params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; params.toneCurve.curve2 = { 0 }; params.toneCurve.expcomp = 0.0; diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index 7b07fbb58..0d753dcbf 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -31,6 +31,7 @@ ToneCurve::ToneCurve () : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LA { auto m = ProcEventMapper::getInstance(); EvHistMatching = m->newEvent(AUTOEXP, "HISTORY_MSG_HISTMATCHING"); + EvHistMatchingBatch = m->newEvent(M_VOID, "HISTORY_MSG_HISTMATCHING"); CurveListener::setMulti(true); @@ -901,11 +902,15 @@ void ToneCurve::setHistmatching(bool enabled) void ToneCurve::histmatchingToggled() { if (listener) { - if (histmatching->get_active()) { - listener->panelChanged(EvHistMatching, M("GENERAL_ENABLED")); - waitForAutoExp(); + if (!batchMode) { + if (histmatching->get_active()) { + listener->panelChanged(EvHistMatching, M("GENERAL_ENABLED")); + waitForAutoExp(); + } else { + listener->panelChanged(EvHistMatching, M("GENERAL_DISABLED")); + } } else { - listener->panelChanged(EvHistMatching, M("GENERAL_DISABLED")); + listener->panelChanged(EvHistMatchingBatch, histmatching->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); } } } @@ -948,6 +953,7 @@ bool ToneCurve::histmatchingComputed() autolevels->set_inconsistent(false); } + histmatching->set_active(false); toneCurveMode->set_active(rtengine::toUnderlying(nextToneCurveMode)); shape->setCurve(nextToneCurve); shape2->setCurve({ DCT_Linear }); diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h index 5aae5f015..e85fefa39 100644 --- a/rtgui/tonecurve.h +++ b/rtgui/tonecurve.h @@ -68,6 +68,7 @@ protected: DiagonalCurveEditor* shape2; rtengine::ProcEvent EvHistMatching; + rtengine::ProcEvent EvHistMatchingBatch; // used temporarily in eventing double nextExpcomp; From 942da71ef099327235236a12a3bde983a67de87c Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 17 Jan 2018 22:02:12 +0100 Subject: [PATCH 05/19] added some verbosity in RawImageSource::getAutoMatchedToneCurve --- rtengine/histmatching.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 8b506432d..4be81ad8a 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -26,10 +26,15 @@ #include "iccstore.h" #include "../rtgui/mydiagonalcurve.h" #include "improcfun.h" +#define BENCHMARK +#include "StopWatch.h" +#include namespace rtengine { +extern const Settings *settings; + namespace { std::vector getCdf(const IImage8 &img) @@ -123,6 +128,12 @@ void mappingToCurve(const std::vector &mapping, std::vector &curve) void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) { + BENCHFUN + + if (settings->verbose) { + std::cout << "performing histogram matching for " << getFileName() << " on the embedded thumbnail" << std::endl; + } + const int rheight = 200; ProcParams neutral; std::unique_ptr target; @@ -149,6 +160,10 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) 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; + } } std::unique_ptr source; { @@ -157,6 +172,10 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) int w, h; std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, true)); source.reset(thumb->quickProcessImage(neutral, target->getHeight(), TI_Nearest)); + + if (settings->verbose) { + std::cout << "histogram matching: extracted embedded thumbnail" << std::endl; + } } if (target->getWidth() != source->getWidth() || target->getHeight() != source->getHeight()) { Image8 *tmp = new Image8(source->getWidth(), source->getHeight()); @@ -174,6 +193,10 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) } mappingToCurve(mapping, outCurve); + + if (settings->verbose) { + std::cout << "histogram matching: generated curve with " << outCurve.size()/2 << " control points" << std::endl; + } } } // namespace rtengine From 7bcc8ae2369b6b07149a69b001dbc328a7824989 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 17 Jan 2018 22:25:32 +0100 Subject: [PATCH 06/19] removed useless lines --- rtengine/histmatching.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 4be81ad8a..43f73b811 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -145,8 +145,6 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) PreviewProps pp(0, 0, fw, fh, skip); ColorTemp currWB = getWB(); std::unique_ptr image(new Imagefloat(int(fw / skip), int(fh / skip))); - neutral.raw.bayersensor.method = procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::FAST); - neutral.raw.xtranssensor.method = procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::FAST); getImage(currWB, tr, image.get(), pp, neutral.toneCurve, neutral.raw); // this could probably be made faster -- ideally we would need to just From 931ee9562049496e8fd8b32ca8a573461d3ed033 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Wed, 17 Jan 2018 23:09:49 +0100 Subject: [PATCH 07/19] use a relative height (10% of the full height) instead of an absolute one in histogram matching --- rtengine/histmatching.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 43f73b811..2aea9f3c8 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -134,14 +134,13 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) std::cout << "performing histogram matching for " << getFileName() << " on the embedded thumbnail" << std::endl; } - const int rheight = 200; ProcParams neutral; std::unique_ptr target; { int tr = TR_NONE; int fw, fh; getFullSize(fw, fh, tr); - int skip = fh / rheight; + int skip = 10; PreviewProps pp(0, 0, fw, fh, skip); ColorTemp currWB = getWB(); std::unique_ptr image(new Imagefloat(int(fw / skip), int(fh / skip))); From abfeb4ca1d01312ffbaacf141350d0d3e59404e6 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 18 Jan 2018 14:17:51 +0100 Subject: [PATCH 08/19] fixed crashes in histogram matching --- rtengine/histmatching.cc | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 2aea9f3c8..cd7352980 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -96,31 +96,35 @@ void mappingToCurve(const std::vector &mapping, std::vector &curve) auto coord = [](int v) -> double { return double(v)/255.0; }; auto doit = - [&](int start, int stop, int step) -> void + [&](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.emplace_back(coord(i)); - curve.emplace_back(coord(v)); + curve.push_back(coord(i)); + curve.push_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()))) { + 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(coord(mapping.back())); } - curve.insert(curve.begin(), DCT_Spline); + if (curve.size() < 4) { + curve = { DCT_Linear }; // not enough points, fall back to linear + } else { + curve.insert(curve.begin(), DCT_Spline); + } } } // namespace @@ -133,6 +137,8 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) if (settings->verbose) { std::cout << "performing histogram matching for " << getFileName() << " on the embedded thumbnail" << std::endl; } + + outCurve = { DCT_Linear }; ProcParams neutral; std::unique_ptr target; @@ -168,6 +174,12 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) 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; + } + return; + } source.reset(thumb->quickProcessImage(neutral, target->getHeight(), TI_Nearest)); if (settings->verbose) { @@ -186,7 +198,7 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) int j = 0; for (size_t i = 0; i < tcdf.size(); ++i) { j = findMatch(tcdf[i], scdf, j); - mapping.emplace_back(j); + mapping.push_back(j); } mappingToCurve(mapping, outCurve); From 7b3e9f7b7a0ff7cbc4999fa6c8d0809d0aedbee1 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 18 Jan 2018 17:55:14 +0100 Subject: [PATCH 09/19] fixed bad interaction between auto levels and histogram matching --- rtengine/improccoordinator.cc | 3 ++- rtengine/simpleprocess.cc | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 37241bbe0..75fc81e9f 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -445,7 +445,8 @@ 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) { + } + if (params.toneCurve.histmatching) { imgsrc->getAutoMatchedToneCurve(params.toneCurve.curve); params.toneCurve.histmatching = false; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 2910b6b43..0bd784e45 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -739,7 +739,8 @@ 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) { + } + if (params.toneCurve.histmatching) { imgsrc->getAutoMatchedToneCurve(params.toneCurve.curve); params.toneCurve.histmatching = false; From 4feb663f633bb3becc23704c0414aa2bd74c7d01 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Thu, 18 Jan 2018 23:36:03 +0100 Subject: [PATCH 10/19] histogram matching: handle the case in which the thumbnail and the raw have different aspect ratios --- rtengine/histmatching.cc | 77 +++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index cd7352980..71bdffc58 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -29,6 +29,7 @@ #define BENCHMARK #include "StopWatch.h" #include +#include namespace rtengine { @@ -139,18 +140,62 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) } 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; + } + 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 tr = TR_NONE; - int fw, fh; - getFullSize(fw, fh, tr); - int skip = 10; + { + 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, image.get(), pp, neutral.toneCurve, neutral.raw); + 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 @@ -168,24 +213,6 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) std::cout << "histogram matching: generated neutral rendering" << std::endl; } } - 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; - } - return; - } - source.reset(thumb->quickProcessImage(neutral, target->getHeight(), TI_Nearest)); - - if (settings->verbose) { - std::cout << "histogram matching: extracted embedded thumbnail" << 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); From 8f7639288598b444f5ec38bf11bf4f8dbb39295c Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Fri, 19 Jan 2018 21:43:55 +0100 Subject: [PATCH 11/19] histogram matching: cache the computed tone curve in RawImageSource --- rtengine/histmatching.cc | 11 +++++++++++ rtengine/improccoordinator.cc | 2 +- rtengine/rawimagesource.h | 1 + rtengine/simpleprocess.cc | 2 +- rtgui/tonecurve.cc | 1 - 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 71bdffc58..5b7647f49 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -139,6 +139,14 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) 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; @@ -161,6 +169,7 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &outCurve) 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)); @@ -233,6 +242,8 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector &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/improccoordinator.cc b/rtengine/improccoordinator.cc index 75fc81e9f..d390d94ca 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -449,7 +449,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) if (params.toneCurve.histmatching) { imgsrc->getAutoMatchedToneCurve(params.toneCurve.curve); - params.toneCurve.histmatching = false; + params.toneCurve.autoexp = false; params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; params.toneCurve.curve2 = { 0 }; params.toneCurve.expcomp = 0.0; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index a199eb13a..59316eccf 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); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 0bd784e45..0cc223da1 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -743,7 +743,7 @@ private: if (params.toneCurve.histmatching) { imgsrc->getAutoMatchedToneCurve(params.toneCurve.curve); - params.toneCurve.histmatching = false; + params.toneCurve.autoexp = false; params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; params.toneCurve.curve2 = { 0 }; params.toneCurve.expcomp = 0.0; diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index 0d753dcbf..4a25794ff 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -953,7 +953,6 @@ bool ToneCurve::histmatchingComputed() autolevels->set_inconsistent(false); } - histmatching->set_active(false); toneCurveMode->set_active(rtengine::toUnderlying(nextToneCurveMode)); shape->setCurve(nextToneCurve); shape2->setCurve({ DCT_Linear }); From 1ec4ff64632e612b7424ce5885a7396e42dd54cb Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 20 Jan 2018 18:41:17 +0100 Subject: [PATCH 12/19] bumped pp3 version number as requested by Floessie and Hombre57 --- rtgui/ppversion.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 From 466efd3993c66912a6bf27e88121b75f3e7268a5 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sun, 21 Jan 2018 19:11:21 +0100 Subject: [PATCH 13/19] Added "Advanced" tab icon. Added equalizer and atom icons, and set the Advanced tab to use the atom icon. #4298 --- rtdata/images/Dark/actions/atom.png | Bin 0 -> 1325 bytes .../images/Dark/actions/equalizer-narrow.png | Bin 0 -> 1038 bytes rtdata/images/Dark/actions/equalizer-wide.png | Bin 0 -> 918 bytes rtdata/images/Light/actions/atom.png | Bin 0 -> 1312 bytes .../images/Light/actions/equalizer-narrow.png | Bin 0 -> 1017 bytes .../images/Light/actions/equalizer-wide.png | Bin 0 -> 927 bytes rtgui/toolpanelcoord.cc | 2 +- tools/source_icons/scalable/atom.file | 1 + tools/source_icons/scalable/atom.svg | 121 +++++++++ .../scalable/equalizer-narrow.file | 1 + .../scalable/equalizer-narrow.svg | 201 ++++++++++++++ .../source_icons/scalable/equalizer-wide.file | 1 + .../source_icons/scalable/equalizer-wide.svg | 256 ++++++++++++++++++ 13 files changed, 582 insertions(+), 1 deletion(-) create mode 100644 rtdata/images/Dark/actions/atom.png create mode 100644 rtdata/images/Dark/actions/equalizer-narrow.png create mode 100644 rtdata/images/Dark/actions/equalizer-wide.png create mode 100644 rtdata/images/Light/actions/atom.png create mode 100644 rtdata/images/Light/actions/equalizer-narrow.png create mode 100644 rtdata/images/Light/actions/equalizer-wide.png create mode 100644 tools/source_icons/scalable/atom.file create mode 100644 tools/source_icons/scalable/atom.svg create mode 100644 tools/source_icons/scalable/equalizer-narrow.file create mode 100644 tools/source_icons/scalable/equalizer-narrow.svg create mode 100644 tools/source_icons/scalable/equalizer-wide.file create mode 100644 tools/source_icons/scalable/equalizer-wide.svg diff --git a/rtdata/images/Dark/actions/atom.png b/rtdata/images/Dark/actions/atom.png new file mode 100644 index 0000000000000000000000000000000000000000..1e7ce3da01bcd1af1fce3eb1f18c90b01697c981 GIT binary patch literal 1325 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 IM6N<$g3Q**wEzGB literal 0 HcmV?d00001 diff --git a/rtdata/images/Dark/actions/equalizer-wide.png b/rtdata/images/Dark/actions/equalizer-wide.png new file mode 100644 index 0000000000000000000000000000000000000000..50cfed8fa8b4fbb59fbb363664d20cc1e0660f0b GIT binary patch literal 918 zcmV;H18Mw;P)(^b8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H1055b!SaeirbZlh+Nn>wrb0B7Kav*eQWgsF&cyMKMbRr;hVPYU@ zZXi-&cT{L)a$#^~WeEx?i~s-t7IZ~ebU}4=Xm4@=O>c5%VQwHuVRB@5Z*OE^P<7b= z002^SMObu0Z*X~XX=iA307F9{L3DI-X<~JBX>V>VQ)ppwWkGCdYh@s4baZe!FE3+q zWnpw_c4cF4ZEbIEb1rXkXD@7NV`Xl0WpgiLc`b8cFElPNFT+$~1poj7SV=@dR5*>b z)v;?7Q4j|3Z|1$rMFh>ANfWS5qsS2y6$>Q?v9U6h7NUY+r@?=~^acbGB~`$}N>R%T z9I*`;7Su+OAd&+$IZm@jNN(SZ&2E^@7AFaL&AxB<&2MLyw=8f#gR)7Z(HI4AILpqt z?RvfbeXp=L^C!%FA`2me4uEs}hE?@N2;q2^iD+Z5XbvW#8$@)dnqDI zSr(B${fZYB7H$#I5mU1=IXU?*2aCv*s*Y!wnb!b3>to*$k>M;5(K3KMOhio)`DOBY zzmAD$NmY-T{4tx`U9srBkFpR#*zO05NR@~xS!U*=1z1(DtLhnZ_n!c6_vv^{z)&NZRdcB(W{;q|S zB>4g0n~27Ns`3O+|DvH{{?_jsT73}<}6$)m7;V_M^(id zg^rndLqseb13Q{3vH$=8 literal 0 HcmV?d00001 diff --git a/rtdata/images/Light/actions/atom.png b/rtdata/images/Light/actions/atom.png new file mode 100644 index 0000000000000000000000000000000000000000..55feaf8d7659c568fb3412db6b7b78eb2a4995ab GIT binary patch literal 1312 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 + + + + Icons for the "Expert" tab in RawTherapee + + + + + + + + image/svg+xml + + Icons for the "Expert" tab in RawTherapee + + + Morgan Hardwood + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + Icons for the "Expert" tab in RawTherapee + + + + + + + + image/svg+xml + + Icons for the "Expert" tab in RawTherapee + + + Morgan Hardwood + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + Icons for the "Expert" tab in RawTherapee + + + + + + + + image/svg+xml + + Icons for the "Expert" tab in RawTherapee + + + Morgan Hardwood + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2aea7aa97cb4c1464528687b6b79c463cca18d91 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 20 Jan 2018 18:50:01 +0100 Subject: [PATCH 14/19] moved channel mixer back to the color tab --- rtgui/partialpastedlg.cc | 6 +++--- rtgui/toolpanelcoord.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 392da6db3..9271ccb58 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -168,6 +168,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[2]->pack_start (*icm, Gtk::PACK_SHRINK, 2); //vboxes[2]->pack_start (*gam, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*vibrance, Gtk::PACK_SHRINK, 2); + vboxes[2]->pack_start (*chmixer, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*blackwhite, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*hsveq, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*filmSimulation, Gtk::PACK_SHRINK, 2); @@ -196,7 +197,6 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren //WAVELET vboxes[5]->pack_start (*advanced, Gtk::PACK_SHRINK, 2); vboxes[5]->pack_start (*hseps[5], Gtk::PACK_SHRINK, 2); - vboxes[5]->pack_start (*chmixer, 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); @@ -522,13 +522,11 @@ void PartialPasteDlg::advancedToggled () { ConnectionBlocker waveletBlocker(waveletConn); - ConnectionBlocker chmixerBlocker(chmixerConn); ConnectionBlocker retinexBlocker(retinexConn); ConnectionBlocker colorappearanceBlocker(colorappearanceConn); advanced->set_inconsistent (false); wavelet->set_active (advanced->get_active ()); - chmixer->set_active (color->get_active ()); retinex->set_active (basic->get_active ()); colorappearance->set_active (basic->get_active ()); } @@ -538,6 +536,7 @@ void PartialPasteDlg::colorToggled () ConnectionBlocker icmBlocker(icmConn); ConnectionBlocker vibranceBlocker(vibranceConn); + ConnectionBlocker chmixerBlocker(chmixerConn); ConnectionBlocker chmixerbwBlocker(chmixerbwConn); ConnectionBlocker hsveqBlocker(hsveqConn); ConnectionBlocker filmSimulationBlocker(filmSimulationConn); @@ -550,6 +549,7 @@ void PartialPasteDlg::colorToggled () icm->set_active (color->get_active ()); //gam->set_active (color->get_active ()); vibrance->set_active (color->get_active ()); + chmixer->set_active (color->get_active ()); blackwhite->set_active (color->get_active ()); hsveq->set_active (color->get_active ()); filmSimulation->set_active (color->get_active ()); diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index fcdf9a0e4..e9cb3ea43 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -102,7 +102,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan addPanel (colorPanel, whitebalance); addPanel (exposurePanel, toneCurve); addPanel (colorPanel, vibrance); - addPanel (advancedPanel, chmixer); + addPanel (colorPanel, chmixer); addPanel (colorPanel, blackwhite); addPanel (exposurePanel, localContrast); addPanel (exposurePanel, shadowshighlights); From 88123cdd146bc73d314fb0312030af013217996f Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 21 Jan 2018 18:01:07 +0100 Subject: [PATCH 15/19] Set last curve point of auto matched curve always to 1;1 --- rtengine/histmatching.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 5b7647f49..be618d4d7 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -119,7 +119,7 @@ void mappingToCurve(const std::vector &mapping, std::vector &curve) 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(coord(mapping.back())); + curve.emplace_back(1.0); } if (curve.size() < 4) { curve = { DCT_Linear }; // not enough points, fall back to linear From 44984a911b397548e5f58927e0ac23cd5924a227 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 21 Jan 2018 18:03:51 +0100 Subject: [PATCH 16/19] Don't set exposure to zero when 'auto levels' is disabled and 'auto matched tone curve' is enabled --- rtengine/improccoordinator.cc | 5 ++++- rtengine/simpleprocess.cc | 6 +++++- rtgui/tonecurve.cc | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index d390d94ca..d3a32140a 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -449,10 +449,13 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) 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.expcomp = 0.0; params.toneCurve.brightness = 0; params.toneCurve.contrast = 0; params.toneCurve.black = 0; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 0cc223da1..45956f262 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -743,14 +743,18 @@ private: 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.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 diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index 4a25794ff..fd4c0827d 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -936,7 +936,6 @@ bool ToneCurve::histmatchingComputed() GThreadLock lock; disableListener(); enableAll(); - expcomp->setValue(0); brightness->setValue(0); contrast->setValue(0); black->setValue(0); @@ -947,6 +946,7 @@ bool ToneCurve::histmatchingComputed() } if (autolevels->get_active() ) { + expcomp->setValue(0); autoconn.block(true); autolevels->set_active(false); autoconn.block(false); From d44a3b8bb3fba4226fd8581797b4775a1dfefdc8 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 21 Jan 2018 19:00:40 +0100 Subject: [PATCH 17/19] added tooltip to the hisogram matching button --- rtdata/languages/default | 1 + rtgui/tonecurve.cc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/rtdata/languages/default b/rtdata/languages/default index acf03e48b..503600e28 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1554,6 +1554,7 @@ 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/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index fd4c0827d..ce938178e 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -127,6 +127,7 @@ ToneCurve::ToneCurve () : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LA 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); @@ -448,6 +449,7 @@ void ToneCurve::setRaw (bool raw) disableListener (); method->set_sensitive (raw); hrenabled->set_sensitive (raw); + histmatching->set_sensitive(raw); enableListener (); } From 5ae12d6d7cc5aed4a982eb84ddd6b23c3dc11813 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sun, 21 Jan 2018 19:14:49 +0100 Subject: [PATCH 18/19] Added wildcard to build* folders in .gitignore --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From b13db578eb2335432c1ef083eb76a55314c4e807 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 21 Jan 2018 19:21:41 +0100 Subject: [PATCH 19/19] do not reset highlight compression when doing histogram matching --- rtengine/improccoordinator.cc | 1 - rtengine/simpleprocess.cc | 1 - rtgui/tonecurve.cc | 4 +++- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index d3a32140a..62891a03f 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -459,7 +459,6 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) 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/simpleprocess.cc b/rtengine/simpleprocess.cc index 45956f262..685e1d53e 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -753,7 +753,6 @@ private: params.toneCurve.brightness = 0; params.toneCurve.contrast = 0; params.toneCurve.black = 0; - params.toneCurve.hlcompr = 0; } diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index ce938178e..07822f857 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -567,7 +567,9 @@ void ToneCurve::adjusterChanged (Adjuster* a, double newval) return; } - setHistmatching(false); + if (a != expcomp && a != hlcompr && a != hlcomprthresh) { + setHistmatching(false); + } Glib::ustring costr;