diff --git a/rtdata/languages/default b/rtdata/languages/default index 54907f6f0..af4c031d1 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1283,6 +1283,7 @@ HISTORY_MSG_1035;Local - Nlmeans - detail HISTORY_MSG_1036;Local - Nlmeans - patch HISTORY_MSG_1037;Local - Nlmeans - radius HISTORY_MSG_1038;Local - Nlmeans - gamma +HISTORY_MSG_1039;Local - Grain - gamma HISTORY_MSG_BLSHAPE;Blur by level HISTORY_MSG_BLURCWAV;Blur chroma HISTORY_MSG_BLURWAV;Blur luminance @@ -2623,6 +2624,7 @@ TP_LOCALLAB_DETAIL;Local contrast TP_LOCALLAB_DETAILFRA;Edge detection TP_LOCALLAB_DETAILSH;Details TP_LOCALLAB_DETAILTHR;Luminance & chroma detail threshold (DCT ƒ) +TP_LOCALLAB_DIVGR;Gamma TP_LOCALLAB_DUPLSPOTNAME;Copy TP_LOCALLAB_EDGFRA;Edge sharpness TP_LOCALLAB_EDGSHOW;Show all tools @@ -2713,6 +2715,8 @@ TP_LOCALLAB_GRADSTRHUE_TOOLTIP;Adjusts hue gradient strength TP_LOCALLAB_GRADSTRLUM;Luminance gradient strength TP_LOCALLAB_GRADSTR_TOOLTIP;Filter strength in stops TP_LOCALLAB_GRAINFRA;Film Grain 1:1 +TP_LOCALLAB_GRAINFRA2;Coarseness + TP_LOCALLAB_GRAIN_TOOLTIP;Adds film-like grain to the image TP_LOCALLAB_GRALWFRA;Graduated filter (local contrast) TP_LOCALLAB_GRIDFRAME_TOOLTIP;You can use this tool as a brush. Use small spot and adapt transition and transition decay\nOnly mode NORMAL and eventually Hue, Saturation, Color, Luminosity are concerned by Merge background (ΔE) @@ -2735,7 +2739,7 @@ TP_LOCALLAB_INVBL_TOOLTIP;Alternative to ‘Inverse’ mode: use two spots\nFirs TP_LOCALLAB_INVERS;Inverse TP_LOCALLAB_INVERS_TOOLTIP;Fewer possibilities if selected (Inverse).\n\nAlternative: use two spots\nFirst Spot:\n full image - delimiter outside preview\n RT-spot shape: rectangle. Transition 100\n\nSecond spot: Excluding spot TP_LOCALLAB_INVMASK;Inverse algorithm -TP_LOCALLAB_ISOGR;Coarseness (ISO) +TP_LOCALLAB_ISOGR;Distribution (ISO) TP_LOCALLAB_LABBLURM;Blur Mask TP_LOCALLAB_LABEL;Local Adjustments TP_LOCALLAB_LABGRID;Color correction grid diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 923a5e8db..0d915cf28 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -280,7 +280,7 @@ enum class BlurType { float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope, float balance, float balanceh, float lumask); //3 functions from Alberto Griggio, adapted J.Desmis 2019 - void filmGrain(Imagefloat *rgb, int isogr, int strengr, int scalegr, int bfw, int bfh); + void filmGrain(Imagefloat *rgb, int isogr, int strengr, int scalegr,float divgr, int bfw, int bfh); void log_encode(Imagefloat *rgb, struct local_params & lp, bool multiThread, int bfw, int bfh); void getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg, float *blackev, float *whiteev, bool *Autogr, float *sourceab, int fw, int fh, float xsta, float xend, float ysta, float yend, int SCALE); diff --git a/rtengine/ipgrain.cc b/rtengine/ipgrain.cc index b9079606a..d03a3ba33 100644 --- a/rtengine/ipgrain.cc +++ b/rtengine/ipgrain.cc @@ -24,6 +24,7 @@ /* This file is part of darktable, copyright (c) 2010-2012 Henrik Andersson. + adaptation to Rawtherapee 2021 Jacques Desmis jdesmis@gmail.com darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -88,7 +89,7 @@ const int permutation[] class GrainEvaluator { public: - GrainEvaluator(int offset_x, int offset_y, int full_width, int full_height, double scale): + GrainEvaluator(int offset_x, int offset_y, int full_width, int full_height, double scale, float divgr): ox(offset_x), oy(offset_y), fw(full_width), @@ -96,18 +97,18 @@ public: scale(scale) { simplex_noise_init(); - constexpr float mb = 100.f; - evaluate_grain_lut(mb); + constexpr float mb = 100.f;// * divgr; + evaluate_grain_lut(mb, divgr); } - void operator()(int isogr, int strengr, int scalegr, Imagefloat *lab, bool multithread) + void operator()(int isogr, int strengr, int scalegr, float divgr, Imagefloat *lab, bool multithread) { const double strength = (strengr / 100.0); - const double octaves = 3; + const double octaves = 3.; const double wd = std::min(fw, fh); const double zoom = (1.0 + 8 * (double(isogr) / GRAIN_SCALE_FACTOR) / 100.0) / 800.0; const double s = std::max(scale / 3.0, 1.0) / (double(std::max(scalegr, 1)) / 100.0); - + // printf("s=%f \n", s); const int W = lab->getWidth(); const int H = lab->getHeight(); float **lab_L = lab->g.ptrs; @@ -298,29 +299,38 @@ private: return total; } - float paper_resp(float exposure, float mb, float gp) - { - const float delta = GRAIN_LUT_DELTA_MAX * expf((mb / 100.0f) * logf(GRAIN_LUT_DELTA_MIN)); + float paper_resp(float exposure, float mb, float gp, float divgr) + { + float dived = 1.f; + if(divgr > 1.8f) { + dived = 1.f + (divgr - 1.8f); + } + const float delta = dived * GRAIN_LUT_DELTA_MAX * expf((mb / 100.0f) * logf(GRAIN_LUT_DELTA_MIN / dived)); const float density = (1.0f + 2.0f * delta) / (1.0f + expf( (4.0f * gp * (0.5f - exposure)) / (1.0f + 2.0f * delta) )) - delta; return density; } - float paper_resp_inverse(float density, float mb, float gp) + float paper_resp_inverse(float density, float mb, float gp, float divgr) { - const float delta = GRAIN_LUT_DELTA_MAX * expf((mb / 100.0f) * logf(GRAIN_LUT_DELTA_MIN)); + float dived = 1.f; + if(divgr > 1.8f) { + dived = 1.f + (divgr - 1.8f); + } + const float delta = dived * GRAIN_LUT_DELTA_MAX * expf((mb / 100.0f) * logf(GRAIN_LUT_DELTA_MIN / dived)); const float exposure = -logf((1.0f + 2.0f * delta) / (density + delta) - 1.0f) * (1.0f + 2.0f * delta) / (4.0f * gp) + 0.5f; return exposure; } - void evaluate_grain_lut(const float mb) + void evaluate_grain_lut(const float mb, float divgr) { for(int i = 0; i < GRAIN_LUT_SIZE; i++) { for(int j = 0; j < GRAIN_LUT_SIZE; j++) { - const float gu = (float)i / (GRAIN_LUT_SIZE - 1) - 0.5; - const float l = (float)j / (GRAIN_LUT_SIZE - 1); - grain_lut[j * GRAIN_LUT_SIZE + i] = 32768.f * (paper_resp(gu + paper_resp_inverse(l, mb, GRAIN_LUT_PAPER_GAMMA), mb, GRAIN_LUT_PAPER_GAMMA) - l); + float gu = (float)i / (GRAIN_LUT_SIZE - 1) - 0.5; + float l = (float)j / (GRAIN_LUT_SIZE - 1); + float divg = divgr; //1.f + grain_lut[j * GRAIN_LUT_SIZE + i] = 32768.f * (paper_resp(gu + paper_resp_inverse(l, mb, divg * GRAIN_LUT_PAPER_GAMMA, divgr), mb, divg * GRAIN_LUT_PAPER_GAMMA, divgr) - l); } } } @@ -361,11 +371,14 @@ private: } // namespace -void ImProcFunctions::filmGrain(Imagefloat *rgb, int isogr, int strengr, int scalegr, int bfw, int bfh) +void ImProcFunctions::filmGrain(Imagefloat *rgb, int isogr, int strengr, int scalegr, float divgr, int bfw, int bfh) { + if (settings->verbose) { + printf("iso=%i strength=%i scale=%i gamma=%f\n", isogr, strengr, scalegr, divgr); + } - GrainEvaluator ge(0, 0, bfw, bfh, scale); - ge(isogr, strengr, scalegr, rgb, multiThread); + GrainEvaluator ge(0, 0, bfw, bfh, scale, divgr); + ge(isogr, strengr, scalegr, divgr, rgb, multiThread); } } // namespace rtengine diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 4eda9c71a..2e570c15e 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -11522,7 +11522,7 @@ void ImProcFunctions::Lab_Local( bool fft = params->locallab.spots.at(sp).fftwbl; int isogr = params->locallab.spots.at(sp).isogr; int scalegr = params->locallab.spots.at(sp).scalegr; - + float divgr = params->locallab.spots.at(sp).divgr; if (bfw >= mSP && bfh >= mSP) { @@ -11668,7 +11668,7 @@ void ImProcFunctions::Lab_Local( } - filmGrain(tmpImage, isogr, strengr, scalegr, wi, he); + filmGrain(tmpImage, isogr, strengr, scalegr, divgr, wi, he); for (int y = 0; y < he ; y++) { for (int x = 0; x < wi; x++) { diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 62dff74e3..3642b0582 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -1061,6 +1061,7 @@ enum ProcEventCode { Evlocallabnlpat = 1035, Evlocallabnlrad = 1036, Evlocallabnlgam = 1037, + Evlocallabdivgr = 1038, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index f4909cb10..0c66af8e2 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -3330,7 +3330,8 @@ LocallabParams::LocallabSpot::LocallabSpot() : decayd(2.), isogr(400), strengr(0), - scalegr(80), + scalegr(100), + divgr(1.), epsbl(0), blMethod("blur"), chroMethod("lum"), @@ -4427,6 +4428,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && isogr == other.isogr && strengr == other.strengr && scalegr == other.scalegr + && divgr == other.divgr && epsbl == other.epsbl && blMethod == other.blMethod && chroMethod == other.chroMethod @@ -6067,6 +6069,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->isogr, "Locallab", "Isogr_" + index_str, spot.isogr, keyFile); saveToKeyfile(!pedited || spot_edited->strengr, "Locallab", "Strengr_" + index_str, spot.strengr, keyFile); saveToKeyfile(!pedited || spot_edited->scalegr, "Locallab", "Scalegr_" + index_str, spot.scalegr, keyFile); + saveToKeyfile(!pedited || spot_edited->divgr, "Locallab", "Divgr_" + index_str, spot.divgr, keyFile); saveToKeyfile(!pedited || spot_edited->epsbl, "Locallab", "Epsbl_" + index_str, spot.epsbl, keyFile); saveToKeyfile(!pedited || spot_edited->blMethod, "Locallab", "BlMethod_" + index_str, spot.blMethod, keyFile); saveToKeyfile(!pedited || spot_edited->chroMethod, "Locallab", "ChroMethod_" + index_str, spot.chroMethod, keyFile); @@ -7923,6 +7926,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "Isogr_" + index_str, pedited, spot.isogr, spotEdited.isogr); assignFromKeyfile(keyFile, "Locallab", "Strengr_" + index_str, pedited, spot.strengr, spotEdited.strengr); assignFromKeyfile(keyFile, "Locallab", "Scalegr_" + index_str, pedited, spot.scalegr, spotEdited.scalegr); + assignFromKeyfile(keyFile, "Locallab", "Divgr_" + index_str, pedited, spot.divgr, spotEdited.divgr); assignFromKeyfile(keyFile, "Locallab", "Epsbl_" + index_str, pedited, spot.epsbl, spotEdited.epsbl); assignFromKeyfile(keyFile, "Locallab", "BlMethod_" + index_str, pedited, spot.blMethod, spotEdited.blMethod); assignFromKeyfile(keyFile, "Locallab", "ChroMethod_" + index_str, pedited, spot.chroMethod, spotEdited.chroMethod); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 1a215b3d0..8940b0172 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1235,6 +1235,7 @@ struct LocallabParams { int isogr; int strengr; int scalegr; + double divgr; int epsbl; Glib::ustring blMethod; // blur, med, guid Glib::ustring chroMethod; // lum, chr, all diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 1adb3853d..9f6ceb360 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -1064,7 +1064,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { AUTOEXP, // Evlocallabnldet AUTOEXP, // Evlocallabnlpat AUTOEXP, // Evlocallabnlrad - AUTOEXP // Evlocallabnlgam + AUTOEXP, // Evlocallabnlgam + AUTOEXP // Evlocallabdivgr }; diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index 15b9d2837..d7581c938 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -6215,9 +6215,11 @@ LocallabBlur::LocallabBlur(): radius(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADIUS"), MINRAD, MAXRAD, 0.1, 1.5, nullptr, nullptr, &blurSlider2radius, &blurRadius2Slider))), strength(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRENGTH"), 0, 100, 1, 0))), grainFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_GRAINFRA")))), + grainFrame2(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_GRAINFRA2")))), isogr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_ISOGR"), 20, 6400, 1, 400))), strengr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRENGR"), 0, 100, 1, 0))), - scalegr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SCALEGR"), 0, 100, 1, 80))), + scalegr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SCALEGR"), 0, 100, 1, 100))), + divgr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DIVGR"), 0.2, 3., 0.1, 1.))), medMethod(Gtk::manage(new MyComboBoxText())), itera(Gtk::manage(new Adjuster(M("TP_DIRPYRDENOISE_MEDIAN_PASSES"), 1, 4, 1, 1))), guidbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GUIDBL"), 0, 1000, 1, 0))), @@ -6337,12 +6339,14 @@ LocallabBlur::LocallabBlur(): strength->setAdjusterListener(this); grainFrame->set_label_align(0.025, 0.5); + grainFrame2->set_label_align(0.025, 0.5); isogr->setAdjusterListener(this); strengr->setAdjusterListener(this); scalegr->setAdjusterListener(this); + divgr->setAdjusterListener(this); medMethod->append(M("TP_LOCALLAB_MEDNONE")); medMethod->append(M("TP_DIRPYRDENOISE_TYPE_3X3")); @@ -6548,8 +6552,14 @@ LocallabBlur::LocallabBlur(): blnoisebox->pack_start(*fftwbl, Gtk::PACK_SHRINK, 0); blnoisebox->pack_start(*radius); blnoisebox->pack_start(*strength); + + ToolParamBlock* const grain2Box = Gtk::manage(new ToolParamBlock()); + grain2Box->pack_start(*isogr); + grain2Box->pack_start(*divgr); + grainFrame2->add(*grain2Box); + ToolParamBlock* const grainBox = Gtk::manage(new ToolParamBlock()); - grainBox->pack_start(*isogr); + grainBox->pack_start(*grainFrame2); grainBox->pack_start(*strengr); grainBox->pack_start(*scalegr); grainFrame->add(*grainBox); @@ -6957,6 +6967,7 @@ void LocallabBlur::read(const rtengine::procparams::ProcParams* pp, const Params isogr->setValue((double)spot.isogr); strengr->setValue((double)spot.strengr); scalegr->setValue((double)spot.scalegr); + divgr->setValue((double)spot.divgr); if (spot.medMethod == "none") { medMethod->set_active(0); @@ -7102,6 +7113,7 @@ void LocallabBlur::write(rtengine::procparams::ProcParams* pp, ParamsEdited* ped spot.isogr = isogr->getIntValue(); spot.strengr = strengr->getIntValue(); spot.scalegr = scalegr->getIntValue(); + spot.divgr = divgr->getValue(); if (medMethod->get_active_row_number() == 0) { spot.medMethod = "none"; @@ -7223,6 +7235,7 @@ void LocallabBlur::setDefaults(const rtengine::procparams::ProcParams* defParams isogr->setDefault((double)defSpot.isogr); strengr->setDefault((double)defSpot.strengr); scalegr->setDefault((double)defSpot.scalegr); + divgr->setDefault((double)defSpot.divgr); itera->setDefault((double)defSpot.itera); guidbl->setDefault((double)defSpot.guidbl); strbl->setDefault((double)defSpot.strbl); @@ -7311,6 +7324,13 @@ void LocallabBlur::adjusterChanged(Adjuster* a, double newval) } } + if (a == divgr) { + if (listener) { + listener->panelChanged(Evlocallabdivgr, + divgr->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + if (a == itera) { if (listener) { listener->panelChanged(Evlocallabitera, @@ -7753,7 +7773,7 @@ void LocallabBlur::convertParamToSimple() disableListener(); invmask->set_active(defSpot.invmask); invmaskd->set_active(defSpot.invmaskd); - + scalegr->setValue(defSpot.scalegr); // Set hidden specific GUI widgets in Simple mode to default spot values showmaskblMethod->set_active(0); @@ -7825,6 +7845,7 @@ void LocallabBlur::updateGUIToMode(const modeType new_type) nlpat->hide(); nlrad->hide(); nlgam->hide(); + scalegr->hide(); break; case Normal: @@ -7848,6 +7869,7 @@ void LocallabBlur::updateGUIToMode(const modeType new_type) nlpat->show(); nlrad->hide(); nlgam->show(); + scalegr->show(); if (blMethod->get_active_row_number() == 2) { expdenoise2->show(); @@ -7913,6 +7935,7 @@ void LocallabBlur::updateGUIToMode(const modeType new_type) adjblur->show(); noisechrodetail->show(); usemask->show(); + scalegr->show(); expmaskbl->show(); strumaskbl->show(); diff --git a/rtgui/locallabtools.h b/rtgui/locallabtools.h index a86626e74..1e3a1c6fa 100644 --- a/rtgui/locallabtools.h +++ b/rtgui/locallabtools.h @@ -675,9 +675,11 @@ private: Adjuster* const radius; Adjuster* const strength; Gtk::Frame* const grainFrame; + Gtk::Frame* const grainFrame2; Adjuster* const isogr; Adjuster* const strengr; Adjuster* const scalegr; + Adjuster* const divgr; MyComboBoxText* const medMethod; Adjuster* const itera; Adjuster* const guidbl; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index a75fe8562..2e67b3121 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -1308,6 +1308,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).isogr = locallab.spots.at(j).isogr && pSpot.isogr == otherSpot.isogr; locallab.spots.at(j).strengr = locallab.spots.at(j).strengr && pSpot.strengr == otherSpot.strengr; locallab.spots.at(j).scalegr = locallab.spots.at(j).scalegr && pSpot.scalegr == otherSpot.scalegr; + locallab.spots.at(j).divgr = locallab.spots.at(j).divgr && pSpot.divgr == otherSpot.divgr; locallab.spots.at(j).epsbl = locallab.spots.at(j).epsbl && pSpot.epsbl == otherSpot.epsbl; locallab.spots.at(j).blMethod = locallab.spots.at(j).blMethod && pSpot.blMethod == otherSpot.blMethod; locallab.spots.at(j).chroMethod = locallab.spots.at(j).chroMethod && pSpot.chroMethod == otherSpot.chroMethod; @@ -4200,6 +4201,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).scalegr = mods.locallab.spots.at(i).scalegr; } + if (locallab.spots.at(i).divgr) { + toEdit.locallab.spots.at(i).divgr = mods.locallab.spots.at(i).divgr; + } + if (locallab.spots.at(i).epsbl) { toEdit.locallab.spots.at(i).epsbl = mods.locallab.spots.at(i).epsbl; } @@ -6880,6 +6885,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : isogr(v), strengr(v), scalegr(v), + divgr(v), epsbl(v), blMethod(v), chroMethod(v), @@ -7451,6 +7457,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) isogr = v; strengr = v; scalegr = v; + divgr = v; epsbl = v; blMethod = v; chroMethod = v; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index ec1d9b8f4..e20f52200 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -643,6 +643,7 @@ public: bool isogr; bool strengr; bool scalegr; + bool divgr; bool epsbl; bool blMethod; bool chroMethod;