From b449e0827b26671409f5cd5173041f66ecd48bab Mon Sep 17 00:00:00 2001 From: Desmis Date: Thu, 11 Feb 2016 18:21:56 +0100 Subject: [PATCH 01/18] Init new process gain with curve --- rtdata/languages/default | 6 +++- rtengine/curves.cc | 33 ++++++++++++++++++ rtengine/curves.h | 24 +++++++++++++ rtengine/imagesource.h | 6 ++-- rtengine/improccoordinator.cc | 7 ++-- rtengine/improccoordinator.h | 1 + rtengine/ipretinex.cc | 63 +++++++++++++++++++++++++++++---- rtengine/procevents.h | 1 + rtengine/procparams.cc | 38 +++++++++++++++++++- rtengine/procparams.h | 6 +++- rtengine/rawimagesource.cc | 10 +++--- rtengine/rawimagesource.h | 6 ++-- rtengine/refreshmap.cc | 4 ++- rtengine/simpleprocess.cc | 5 +-- rtgui/paramsedited.cc | 6 ++++ rtgui/paramsedited.h | 1 + rtgui/retinex.cc | 66 +++++++++++++++++++++++++++-------- rtgui/retinex.h | 3 ++ 18 files changed, 244 insertions(+), 42 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 6bedd3443..ae3a81050 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -670,6 +670,7 @@ HISTORY_MSG_436;Retinex - M - Radius HISTORY_MSG_437;Retinex - M - Method HISTORY_MSG_438;Retinex - M - Equalizer HISTORY_MSG_439;Retinex - Preview +HISTORY_MSG_440;Retinex - Gain transmission HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1667,6 +1668,7 @@ TP_RETINEX_CURVEEDITOR_MAP_TOOLTIP;This curve can be applied alone or with a Gau TP_RETINEX_FREEGAMMA;Free gamma TP_RETINEX_GAIN;Gain TP_RETINEX_GAIN_TOOLTIP;Acts on the restored image.\n\nThis is very different from the others settings. Used for black or white pixels, and to help balance the histogram. +TP_RETINEX_GAINOFFS;Gain and Brightness (offset) TP_RETINEX_GAMMA;Gamma TP_RETINEX_GAMMA_FREE;Free TP_RETINEX_GAMMA_HIGH;High @@ -1705,7 +1707,7 @@ TP_RETINEX_MLABEL_TOOLTIP;Should be near min=0 max=32768\nRestored image with no TP_RETINEX_NEIGHBOR;Radius TP_RETINEX_NEUTRAL;Reset TP_RETINEX_NEUTRAL_TIP;Reset all sliders and curves to their default values. -TP_RETINEX_OFFSET;Brightness +TP_RETINEX_OFFSET;Brightness (offset) TP_RETINEX_SCALES;Gaussian gradient TP_RETINEX_SCALES_TOOLTIP;If slider at 0, all iterations are identical.\nIf > 0 Scale and radius are reduced when iterations increase, and conversely. TP_RETINEX_SETTINGS;Settings @@ -1717,6 +1719,8 @@ TP_RETINEX_TLABEL;TM Min=%1 Max=%2 Mean=%3 Sigma=%4 TP_RETINEX_TLABEL2;TM Tm=%1 TM=%2 TP_RETINEX_TLABEL_TOOLTIP;Transmission map result.\nMin and Max are used by Variance.\nMean and Sigma.\nTm=Min TM=Max of transmission map. TP_RETINEX_TRANSMISSION;Transmission map +TP_RETINEX_GAINTRANSMISSION;Gain transmission +TP_RETINEX_GAINTRANSMISSION_TOOLTIP;Amplfy or reduce transmission-map to achieve luminance.\nAbscissa: transmission -min from 0, mean, and values (max).\nOrdinate : gain TP_RETINEX_TRANSMISSION_TOOLTIP;Transmission according to transmission.\nAbscissa: transmission from negative values (min), mean, and positives values (max).\nOrdinate: amplification or reduction. TP_RETINEX_UNIFORM;Uniform TP_RETINEX_VARIANCE;Contrast diff --git a/rtengine/curves.cc b/rtengine/curves.cc index d0b4c026f..a0ac2c381 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -1429,6 +1429,39 @@ void RetinextransmissionCurve::Set(const std::vector &curvePoints) } } + +RetinexgaintransmissionCurve::RetinexgaintransmissionCurve() {}; + +void RetinexgaintransmissionCurve::Reset() +{ + lutgaintransmission.reset(); +} + +void RetinexgaintransmissionCurve::Set(const Curve &pCurve) +{ + if (pCurve.isIdentity()) { + lutgaintransmission.reset(); // raise this value if the quality suffers from this number of samples + return; + } + + lutgaintransmission(501); // raise this value if the quality suffers from this number of samples + + for (int i = 0; i < 501; i++) { + lutgaintransmission[i] = pCurve.getVal(double(i) / 500.); + } +} + +void RetinexgaintransmissionCurve::Set(const std::vector &curvePoints) +{ + if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { + FlatCurve tcurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + tcurve.setIdentityValue(0.); + Set(tcurve); + } else { + Reset(); + } +} + void ToneCurve::Reset() { lutToneCurve.reset(); diff --git a/rtengine/curves.h b/rtengine/curves.h index e55d7bc2a..330b5c5ce 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -454,6 +454,30 @@ public: } }; +class RetinexgaintransmissionCurve +{ +private: + LUTf lutgaintransmission; // 0xffff range + void Set(const Curve &pCurve); + +public: + virtual ~RetinexgaintransmissionCurve() {}; + RetinexgaintransmissionCurve(); + + void Reset(); + void Set(const Curve *pCurve); + void Set(const std::vector &curvePoints); + float operator[](float index) const + { + return lutgaintransmission[index]; + } + + operator bool (void) const + { + return lutgaintransmission; + } +}; + class ToneCurve diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 80fc53f23..905c8c50e 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -69,14 +69,14 @@ public: virtual int load (Glib::ustring fname, bool batch = false) = 0; virtual void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse) {}; virtual void demosaic (const RAWParams &raw) {}; - virtual void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; - virtual void retinexPrepareCurves (RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) {}; + virtual void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; + virtual void retinexPrepareCurves (RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) {}; virtual void retinexPrepareBuffers (ColorManagementParams cmp, RetinexParams retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI) {}; virtual void flushRawData () {}; virtual void flushRGB () {}; virtual void HLRecovery_Global (ToneCurveParams hrp) {}; virtual void HLRecovery_inpaint (float** red, float** green, float** blue) {}; - virtual void MSR(LabImage* lab, LUTf & mapcurve, bool &mapcontlutili, int width, int height, int skip, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) {}; + virtual void MSR(LabImage* lab, LUTf & mapcurve, bool &mapcontlutili, int width, int height, int skip, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) {}; virtual bool IsrgbSourceModified() = 0; // tracks whether cached rgb output of demosaic has been modified diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index ee75e831a..d24427be9 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -242,16 +242,16 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } } - if ((todo & (M_RETINEX|M_INIT)) && params.retinex.enabled) { + if ((todo & (M_RETINEX | M_INIT)) && params.retinex.enabled) { bool dehacontlutili = false; bool mapcontlutili = false; bool useHsl = false; LUTf cdcurve (65536, 0); LUTf mapcurve (65536, 0); - imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehacontlutili, mapcontlutili, useHsl, lhist16RETI, histLRETI); + imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, dehacontlutili, mapcontlutili, useHsl, lhist16RETI, histLRETI); float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; - imgsrc->retinex( params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI);//enabled Retinex + imgsrc->retinex( params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI);//enabled Retinex if(dehaListener) { dehaListener->minmaxChanged(maxCD, minCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); @@ -782,6 +782,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } } } + // Update the monitor color transform if necessary if (todo & M_MONITOR) { ipf.updateColorProfiles(params.icm, monitorProfile, monitorIntent); diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 4d442482e..6a6c203d2 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -136,6 +136,7 @@ protected: WavOpacityCurveW waOpacityCurveW; WavOpacityCurveWL waOpacityCurveWL; RetinextransmissionCurve dehatransmissionCurve; + RetinexgaintransmissionCurve dehagaintransmissionCurve; ColorAppearance customColCurve1; ColorAppearance customColCurve2; diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 090841a9e..d3d276c43 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -45,7 +45,6 @@ #include "rawimagesource.h" #include "improcfun.h" #include "opthelper.h" -#define BENCHMARK #include "StopWatch.h" #define MAX_RETINEX_SCALES 8 @@ -207,9 +206,8 @@ void mean_stddv( float **dst, float &mean, float &stddv, int W_L, int H_L, const stddv = (float)sqrt(stddv); } -void RawImageSource::MSR(float** luminance, float** originalLuminance, float **exLuminance, LUTf & mapcurve, bool &mapcontlutili, int width, int height, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) +void RawImageSource::MSR(float** luminance, float** originalLuminance, float **exLuminance, LUTf & mapcurve, bool &mapcontlutili, int width, int height, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) { - BENCHFUN if (deh.enabled) {//enabled float mean, stddv, maxtr, mintr; @@ -733,7 +731,8 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e delta = 1.0f; } - float cdfactor = gain2 * 32768.f / delta; + // float cdfactor = gain2 * 32768.f / delta; + float cdfactor = 32768.f / delta; maxCD = -9999999.f; minCD = 9999999.f; // coeff for auto "transmission" with 2 sigma #95% datas @@ -742,22 +741,72 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e float bza = 16300.f / (2.f * stddv); float bzb = 16300.f - bza * (mean); +//prepare work for curve gain +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < H_L; i++) { + for (int j = 0; j < W_L; j++) { + luminance[i][j] = luminance[i][j] - mini; + } + } + + mean = 0.f; + stddv = 0.f; + // I call mean_stddv2 instead of mean_stddv ==> logBetaGain + + mean_stddv2( luminance, mean, stddv, W_L, H_L, maxtr, mintr); + float asig, bsig, amax, bmax, amin, bmin; + + if (dehagaintransmissionCurve && mean != 0.f && stddv != 0.f) { //if curve + asig = 0.166666f / stddv; + bsig = 0.5f - asig * mean; + amax = 0.333333f / (maxtr - mean - stddv); + bmax = 1.f - amax * maxtr; + amin = 0.333333f / (mean - stddv - mintr); + bmin = -amin * mintr; + + asig *= 500.f; + bsig *= 500.f; + amax *= 500.f; + bmax *= 500.f; + amin *= 500.f; + bmin *= 500.f; + } #ifdef _OPENMP #pragma omp parallel #endif { + float absciss; float cdmax = -999999.f, cdmin = 999999.f; - #ifdef _OPENMP #pragma omp for #endif for ( int i = 0; i < H_L; i ++ ) for (int j = 0; j < W_L; j++) { - //float cd = cdfactor * ( luminance[i][j] * logBetaGain - mini ) + offse; - float cd = cdfactor * ( luminance[i][j] - mini ) + offse; + float gan; + + if (dehagaintransmissionCurve && mean != 0.f && stddv != 0.f) { + + if (LIKELY(fabsf(luminance[i][j] - mean) < stddv)) { + absciss = asig * luminance[i][j] + bsig; + } else if (luminance[i][j] >= mean) { + absciss = amax * luminance[i][j] + bmax; + } else { /*if(luminance[i][j] <= mean - stddv)*/ + absciss = amin * luminance[i][j] + bmin; + } + + + // float cd = cdfactor * ( luminance[i][j] - mini ) + offse; + gan = 2.f * (dehagaintransmissionCurve[absciss]); //new gain function transmission + } else { + gan = 0.5f; + } + + float cd = gan * cdfactor * ( luminance[i][j] ) + offse; if(cd > cdmax) { cdmax = cd; diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 558f509c2..cd6fc2cb2 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -466,6 +466,7 @@ enum ProcEvent { EvmapMethod = 436, EvRetinexmapcurve = 437, EvviewMethod = 438, + EvRetinexgaintransmission = 439, NUMOFEVENTS }; } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index f79f51c91..988bd20dc 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -136,6 +136,23 @@ void RetinexParams::getDefaulttransmissionCurve(std::vector &curve) curve.at(i) = v[i - 1]; } } +void RetinexParams::getDefaultgaintransmissionCurve(std::vector &curve) +{ + double v[16] = { 0.00, 0.1, 0.35, 0.00, + 0.25, 0.25, 0.35, 0.35, + 0.70, 0.25, 0.35, 0.35, + 1.00, 0.1, 0.00, 0.00 + }; + + + curve.resize(17); + curve.at(0 ) = double(FCT_MinMaxCPoints); + + for (size_t i = 1; i < curve.size(); ++i) { + curve.at(i) = v[i - 1]; + } +} + void RetinexParams::setDefaults() { @@ -175,13 +192,16 @@ void RetinexParams::setDefaults() lhcurve.push_back(DCT_Linear); mapcurve.clear(); mapcurve.push_back(DCT_Linear); + getDefaultgaintransmissionCurve(gaintransmissionCurve); getDefaulttransmissionCurve(transmissionCurve); } -void RetinexParams::getCurves(RetinextransmissionCurve &transmissionCurveLUT) const +void RetinexParams::getCurves(RetinextransmissionCurve &transmissionCurveLUT, RetinexgaintransmissionCurve &gaintransmissionCurveLUT) const { transmissionCurveLUT.Set(this->transmissionCurve); + gaintransmissionCurveLUT.Set(this->gaintransmissionCurve); + } @@ -1585,6 +1605,11 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_double_list("Retinex", "TransmissionCurve", transmissionCurve); } + if (!pedited || pedited->retinex.gaintransmissionCurve) { + Glib::ArrayHandle gaintransmissionCurve = retinex.gaintransmissionCurve; + keyFile.set_double_list("Retinex", "GainTransmissionCurve", gaintransmissionCurve); + } + // save channel mixer if (!pedited || pedited->chmixer.red[0] || pedited->chmixer.red[1] || pedited->chmixer.red[2]) { Glib::ArrayHandle rmix (chmixer.red, 3, Glib::OWNERSHIP_NONE); @@ -4129,6 +4154,16 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) pedited->retinex.transmissionCurve = true; } } + + + if (keyFile.has_key ("Retinex", "GainTransmissionCurve")) { + retinex.gaintransmissionCurve = keyFile.get_double_list ("Retinex", "GainTransmissionCurve"); + + if (pedited) { + pedited->retinex.gaintransmissionCurve = true; + } + } + } @@ -7514,6 +7549,7 @@ bool ProcParams::operator== (const ProcParams& other) && retinex.cdHcurve == other.retinex.cdHcurve && retinex.lhcurve == other.retinex.lhcurve && retinex.transmissionCurve == other.retinex.transmissionCurve + && retinex.gaintransmissionCurve == other.retinex.gaintransmissionCurve && retinex.str == other.retinex.str && retinex.scal == other.retinex.scal && retinex.iter == other.retinex.iter diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 47b8f1cf1..0b45e7d7a 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -41,6 +41,7 @@ class WavOpacityCurveBY; class WavOpacityCurveW; class WavOpacityCurveWL; class RetinextransmissionCurve; +class RetinexgaintransmissionCurve; enum RenderingIntent { RI_PERCEPTUAL = INTENT_PERCEPTUAL, @@ -282,6 +283,7 @@ public: std::vector cdHcurve; std::vector lhcurve; std::vector transmissionCurve; + std::vector gaintransmissionCurve; std::vector mapcurve; int str; int scal; @@ -312,7 +314,9 @@ public: bool medianmap; RetinexParams (); void setDefaults(); - void getCurves(RetinextransmissionCurve &transmissionCurveLUT) const; + void getCurves(RetinextransmissionCurve &transmissionCurveLUT, RetinexgaintransmissionCurve &gaintransmissionCurveLUT) const; + + static void getDefaultgaintransmissionCurve(std::vector &curve); static void getDefaulttransmissionCurve(std::vector &curve); }; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index d1d4da54f..2251c15dd 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1422,6 +1422,7 @@ SSEFUNCTION int RawImageSource::findHotDeadPixels( PixelsMap &bpMap, float thres } #else + // 25 fabs function calls and 25 float additions without SSE for (int mm = rr - 2; mm <= rr + 2; mm++) { for (int nn = cc - 2; nn <= cc + 2; nn++) { @@ -2216,7 +2217,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } -void RawImageSource::retinexPrepareCurves(RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) +void RawImageSource::retinexPrepareCurves(RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) { useHsl = (retinexParams.retinexcolorspace == "HSLLOG" || retinexParams.retinexcolorspace == "HSLLIN"); @@ -2228,11 +2229,10 @@ void RawImageSource::retinexPrepareCurves(RetinexParams retinexParams, LUTf &cdc CurveFactory::mapcurve (mapcontlutili, retinexParams.mapcurve, mapcurve, 1, lhist16RETI, histLRETI); - retinexParams.getCurves(retinextransmissionCurve); + retinexParams.getCurves(retinextransmissionCurve, retinexgaintransmissionCurve); } -//void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) -void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) +void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) { MyTime t4, t5; @@ -2384,7 +2384,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC } } - MSR(LBuffer, conversionBuffer[2], conversionBuffer[3], mapcurve, mapcontlutili, WNew, HNew, deh, dehatransmissionCurve, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + MSR(LBuffer, conversionBuffer[2], conversionBuffer[3], mapcurve, mapcontlutili, WNew, HNew, deh, dehatransmissionCurve, dehagaintransmissionCurve, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); if(useHsl) { if(chutili) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index bef4ad4e2..0f4ca2402 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -118,8 +118,8 @@ public: int load (Glib::ustring fname, bool batch = false); void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse); void demosaic (const RAWParams &raw); - void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI); - void retinexPrepareCurves (RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI); + void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI); + void retinexPrepareCurves (RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI); void retinexPrepareBuffers (ColorManagementParams cmp, RetinexParams retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI); void flushRawData (); void flushRGB (); @@ -196,7 +196,7 @@ public: void boxblur2(float** src, float** dst, float** temp, int H, int W, int box ); void boxblur_resamp(float **src, float **dst, float** temp, int H, int W, int box, int samp ); - void MSR(float** luminance, float **originalLuminance, float **exLuminance, LUTf & mapcurve, bool &mapcontlutili, int width, int height, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax); + void MSR(float** luminance, float **originalLuminance, float **exLuminance, LUTf & mapcurve, bool &mapcontlutili, int width, int height, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax); void HLRecovery_inpaint (float** red, float** green, float** blue); static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval); static void HLRecovery_CIELab (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval, double cam[3][3], double icam[3][3]); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 6a2925be9..10f911529 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -465,6 +465,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLradius RETINEX, // EvmapMethod DEMOSAIC, // EvRetinexmapcurve - DEMOSAIC // EvviewMethod + DEMOSAIC, // EvviewMethod + RETINEX // EvRetinexgaintransmission + }; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 9ae940980..9916c9f38 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -129,15 +129,16 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p LUTf mapcurve (65536, 0); LUTu dummy; RetinextransmissionCurve dehatransmissionCurve; + RetinexgaintransmissionCurve dehagaintransmissionCurve; bool dehacontlutili = false; bool mapcontlutili = false; bool useHsl = false; // multi_array2D conversionBuffer(1, 1); multi_array2D conversionBuffer(1, 1); imgsrc->retinexPrepareBuffers(params.icm, params.retinex, conversionBuffer, dummy); - imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehacontlutili, mapcontlutili, useHsl, dummy, dummy ); + imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, dehacontlutili, mapcontlutili, useHsl, dummy, dummy ); float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; - imgsrc->retinex( params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, dummy); + imgsrc->retinex( params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, dummy); } if (pl) { diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 062c61ba2..1183b8260 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -76,6 +76,7 @@ void ParamsEdited::set (bool v) // retinex.grbl = v; retinex.medianmap = v; retinex.transmissionCurve = v; + retinex.gaintransmissionCurve = v; retinex.highlights = v; retinex.htonalwidth = v; retinex.shadows = v; @@ -544,6 +545,7 @@ void ParamsEdited::initFrom (const std::vector retinex.cdHcurve = retinex.cdHcurve && p.retinex.cdHcurve == other.retinex.cdHcurve; retinex.lhcurve = retinex.lhcurve && p.retinex.lhcurve == other.retinex.lhcurve; retinex.transmissionCurve = retinex.transmissionCurve && p.retinex.transmissionCurve == other.retinex.transmissionCurve; + retinex.gaintransmissionCurve = retinex.gaintransmissionCurve && p.retinex.gaintransmissionCurve == other.retinex.gaintransmissionCurve; retinex.retinexMethod = retinex.retinexMethod && p.retinex.retinexMethod == other.retinex.retinexMethod; retinex.mapMethod = retinex.mapMethod && p.retinex.mapMethod == other.retinex.mapMethod; retinex.viewMethod = retinex.viewMethod && p.retinex.viewMethod == other.retinex.viewMethod; @@ -1088,6 +1090,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.retinex.transmissionCurve = mods.retinex.transmissionCurve; } + if (retinex.gaintransmissionCurve) { + toEdit.retinex.gaintransmissionCurve = mods.retinex.gaintransmissionCurve; + } + if (retinex.retinexMethod) { toEdit.retinex.retinexMethod = mods.retinex.retinexMethod; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 261da1753..8e21ef5ad 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -81,6 +81,7 @@ public: // bool grbl; bool method; bool transmissionCurve; + bool gaintransmissionCurve; bool cdcurve; bool mapcurve; bool cdHcurve; diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index 561a28edf..bad21cfe7 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -161,7 +161,7 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), grad = Gtk::manage (new Adjuster (M("TP_RETINEX_GRAD"), -2., 2., 1., 1.)); grads = Gtk::manage (new Adjuster (M("TP_RETINEX_GRADS"), -2., 2., 1., 1.)); gain = Gtk::manage (new Adjuster (M("TP_RETINEX_GAIN"), 20, 200, 1, 50)); - offs = Gtk::manage (new Adjuster (M("TP_RETINEX_OFFSET"), -10000, 10000, 1, 0)); + offs = Gtk::manage (new Adjuster (M("TP_RETINEX_OFFSET"), -1000, 5000, 1, 0)); // vart = Gtk::manage (new Adjuster (M("TP_RETINEX_VARIANCE"), 50, 500, 1, 125)); limd = Gtk::manage (new Adjuster (M("TP_RETINEX_THRESHOLD"), 2, 100, 1, 8)); baselog = Gtk::manage (new Adjuster (M("TP_RETINEX_BASELOG"), 1.1, 100., 0.001, 2.718)); @@ -175,6 +175,21 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), limd->set_tooltip_markup (M("TP_RETINEX_THRESHOLD_TOOLTIP")); baselog->set_tooltip_markup (M("TP_RETINEX_BASELOG_TOOLTIP")); + // Gain Transmission map curve + gaintransmissionCurve = new CurveEditorGroup (options.lastRetinexDir, M("TP_RETINEX_GAINTRANSMISSION")); + gaintransmissionCurve->setCurveListener (this); + +// std::vector defaultCurve; + rtengine::RetinexParams::getDefaultgaintransmissionCurve(defaultCurve); + gaintransmissionShape = static_cast(gaintransmissionCurve->addCurve(CT_Flat, "", NULL, false)); + gaintransmissionShape->setIdentityValue(0.); + gaintransmissionShape->setResetCurve(FlatCurveType(defaultCurve.at(0)), defaultCurve); + gaintransmissionShape->setBottomBarBgGradient(milestones); + gaintransmissionCurve->set_tooltip_markup (M("TP_RETINEX_GAINTRANSMISSION_TOOLTIP")); + + gaintransmissionCurve->curveListComplete(); + + Gtk::Frame *p1Frame; p1Frame = Gtk::manage (new Gtk::Frame(M("TP_RETINEX_LABEL_MASK")) ); p1Frame->set_border_width(0); @@ -285,19 +300,34 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), settingsVBox->pack_start (*grads); grads->show (); - settingsVBox->pack_start (*gain); - gain->show (); - - settingsVBox->pack_start (*offs); - offs->show (); - -// settingsVBox->pack_start (*vart); -// vart->show (); - settingsVBox->pack_start (*limd); limd->show (); - // settingsVBox->pack_start (*Gtk::manage (new Gtk::HSeparator())); + settingsVBox->pack_start( *transmissionCurveEditorG, Gtk::PACK_SHRINK, 2); + transmissionCurveEditorG->show(); + + settingsVBox->pack_start (*medianmap); + medianmap->show (); + + // settingsVBox->pack_start (*gain); + // gain->show (); + + +// settingsVBox->pack_start (*vart); +// vart->show (); + Gtk::VBox *gainBox = Gtk::manage (new Gtk::VBox()); + + Gtk::HSeparator *separator = Gtk::manage (new Gtk::HSeparator()); + settingsVBox->pack_start(*separator, Gtk::PACK_SHRINK, 2); + gainFrame = Gtk::manage (new Gtk::Frame(M("TP_RETINEX_GAINOFFS"))); + + gainBox->pack_start( *gaintransmissionCurve, Gtk::PACK_SHRINK, 2); + gaintransmissionCurve->show(); + + gainBox->pack_start (*offs); + offs->show (); + gainFrame->add(*gainBox); + settingsVBox->pack_start (*gainFrame); viewbox->pack_start(*viewMethod); // settingsVBox->pack_start(*viewbox); @@ -334,11 +364,7 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), // grbl->show (); // settingsVBox->pack_start (*Gtk::manage (new Gtk::HSeparator())); - settingsVBox->pack_start( *transmissionCurveEditorG, Gtk::PACK_SHRINK, 2); - transmissionCurveEditorG->show(); - settingsVBox->pack_start (*medianmap); - medianmap->show (); expsettings->add(*settingsVBox); neutrHBox = Gtk::manage (new Gtk::HBox ()); @@ -495,6 +521,7 @@ Retinex::~Retinex() delete curveEditorGD; delete curveEditorGDH; delete transmissionCurveEditorG; + delete gaintransmissionCurve; delete curveEditorGH; delete curveEditormap; @@ -526,6 +553,7 @@ void Retinex::neutral_pressed () retinexcolorspace->set_active(0); gammaretinex->set_active(0); transmissionShape->reset(); + gaintransmissionShape->reset(); cdshape->reset(); cdshapeH->reset(); lhshape->reset(); @@ -690,6 +718,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) cdshape->setUnChanged (!pedited->retinex.cdcurve); cdshapeH->setUnChanged (!pedited->retinex.cdHcurve); transmissionShape->setUnChanged (!pedited->retinex.transmissionCurve); + gaintransmissionShape->setUnChanged (!pedited->retinex.gaintransmissionCurve); lhshape->setUnChanged (!pedited->retinex.lhcurve); mapshape->setUnChanged (!pedited->retinex.mapcurve); @@ -810,6 +839,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) mapMethodConn.block(false); viewMethodConn.block(false); transmissionShape->setCurve (pp->retinex.transmissionCurve); + gaintransmissionShape->setCurve (pp->retinex.gaintransmissionCurve); enableListener (); @@ -840,6 +870,7 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pp->retinex.cdHcurve = cdshapeH->getCurve (); pp->retinex.mapcurve = mapshape->getCurve (); pp->retinex.transmissionCurve = transmissionShape->getCurve (); + pp->retinex.gaintransmissionCurve = gaintransmissionShape->getCurve (); pp->retinex.enabled = getEnabled(); pp->retinex.medianmap = medianmap->get_active(); @@ -875,6 +906,7 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pedited->retinex.cdcurve = !cdshape->isUnChanged (); pedited->retinex.cdHcurve = !cdshapeH->isUnChanged (); pedited->retinex.transmissionCurve = !transmissionShape->isUnChanged (); + pedited->retinex.gaintransmissionCurve = !gaintransmissionShape->isUnChanged (); pedited->retinex.mapcurve = !mapshape->isUnChanged (); pedited->retinex.enabled = !get_inconsistent(); pedited->retinex.medianmap = !medianmap->get_inconsistent(); @@ -1275,6 +1307,7 @@ void Retinex::autoOpenCurve () cdshape->openIfNonlinear(); cdshapeH->openIfNonlinear(); transmissionShape->openIfNonlinear(); + gaintransmissionShape->openIfNonlinear(); lhshape->openIfNonlinear(); mapshape->openIfNonlinear(); @@ -1290,6 +1323,8 @@ void Retinex::curveChanged (CurveEditor* ce) listener->panelChanged (EvLCDHCurve, M("HISTORY_CUSTOMCURVE")); } else if (ce == transmissionShape) { listener->panelChanged (EvRetinextransmission, M("HISTORY_CUSTOMCURVE")); + } else if (ce == gaintransmissionShape) { + listener->panelChanged (EvRetinexgaintransmission, M("HISTORY_CUSTOMCURVE")); } else if (ce == lhshape) { listener->panelChanged (EvRetinexlhcurve, M("HISTORY_CUSTOMCURVE")); } else if (ce == mapshape) { @@ -1415,6 +1450,7 @@ void Retinex::setBatchMode (bool batchMode) curveEditorGD->setBatchMode (batchMode); curveEditorGDH->setBatchMode (batchMode); transmissionCurveEditorG->setBatchMode (batchMode); + gaintransmissionCurve->setBatchMode (batchMode); curveEditorGH->setBatchMode (batchMode); curveEditormap->setBatchMode (batchMode); diff --git a/rtgui/retinex.h b/rtgui/retinex.h index d24254757..b8034ccb9 100644 --- a/rtgui/retinex.h +++ b/rtgui/retinex.h @@ -76,15 +76,18 @@ protected: Gtk::Label* mMLabels; Gtk::Label* transLabels; Gtk::Label* transLabels2; + Gtk::Frame *gainFrame; DiagonalCurveEditor* cdshape; DiagonalCurveEditor* cdshapeH; DiagonalCurveEditor* mapshape; CurveEditorGroup* transmissionCurveEditorG; + CurveEditorGroup* gaintransmissionCurve; sigc::connection retinexMethodConn, neutralconn, mapMethodConn, viewMethodConn; sigc::connection retinexColorSpaceConn; sigc::connection gammaretinexConn; FlatCurveEditor* transmissionShape; + FlatCurveEditor* gaintransmissionShape; FlatCurveEditor* lhshape; bool lastmedianmap; sigc::connection medianmapConn; From a21deef3deda7af52ca9546e0872bc4cd172ae2a Mon Sep 17 00:00:00 2001 From: Desmis Date: Fri, 12 Feb 2016 12:51:46 +0100 Subject: [PATCH 02/18] GUI improvment and re-introduce scale --- rtdata/languages/default | 9 +++- rtengine/ipretinex.cc | 11 +++-- rtengine/procevents.h | 1 + rtengine/procparams.cc | 26 +++++------ rtengine/procparams.h | 2 +- rtengine/refreshmap.cc | 3 +- rtgui/paramsedited.cc | 10 ++--- rtgui/paramsedited.h | 2 +- rtgui/retinex.cc | 96 +++++++++++++++++++++++----------------- rtgui/retinex.h | 5 ++- 10 files changed, 98 insertions(+), 67 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index ae3a81050..6c3561efb 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -671,6 +671,7 @@ HISTORY_MSG_437;Retinex - M - Method HISTORY_MSG_438;Retinex - M - Equalizer HISTORY_MSG_439;Retinex - Preview HISTORY_MSG_440;Retinex - Gain transmission +HISTORY_MSG_441;Retinex - Scale HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1665,10 +1666,11 @@ TP_RETINEX_CURVEEDITOR_LH;Strength=f(H) TP_RETINEX_CURVEEDITOR_LH_TOOLTIP;Strength according to hue Strength=f(H)\nThis curve also acts on chroma when using the "Highlight" retinex method. TP_RETINEX_CURVEEDITOR_MAP;L=f(L) TP_RETINEX_CURVEEDITOR_MAP_TOOLTIP;This curve can be applied alone or with a Gaussian mask or wavelet mask.\nBeware of artifacts! +TP_RETINEX_EQUAL;Equalizer TP_RETINEX_FREEGAMMA;Free gamma TP_RETINEX_GAIN;Gain TP_RETINEX_GAIN_TOOLTIP;Acts on the restored image.\n\nThis is very different from the others settings. Used for black or white pixels, and to help balance the histogram. -TP_RETINEX_GAINOFFS;Gain and Brightness (offset) +TP_RETINEX_GAINOFFS;Gain and Offset (brightness) TP_RETINEX_GAMMA;Gamma TP_RETINEX_GAMMA_FREE;Free TP_RETINEX_GAMMA_HIGH;High @@ -1686,6 +1688,7 @@ TP_RETINEX_HIGHLIGHT;Highlight threshold TP_RETINEX_HIGHLIGHT_TOOLTIP;Increase action of High algorithm.\nMay require you to re-adjust "Neighboring pixels" and to increase the "White-point correction" in the Raw tab -> Raw White Points tool. TP_RETINEX_HSLSPACE_LIN;HSL-Linear TP_RETINEX_HSLSPACE_LOG;HSL-Logarithmic +TP_RETINEX_ITERF;Tone mapping TP_RETINEX_ITER;Iterations (Tone-mapping) TP_RETINEX_ITER_TOOLTIP;Simulate a tone-mapping operator.\nHigh values increase the processing time. TP_RETINEX_LABEL;Retinex @@ -1707,17 +1710,19 @@ TP_RETINEX_MLABEL_TOOLTIP;Should be near min=0 max=32768\nRestored image with no TP_RETINEX_NEIGHBOR;Radius TP_RETINEX_NEUTRAL;Reset TP_RETINEX_NEUTRAL_TIP;Reset all sliders and curves to their default values. -TP_RETINEX_OFFSET;Brightness (offset) +TP_RETINEX_OFFSET;Offset (brightness) TP_RETINEX_SCALES;Gaussian gradient TP_RETINEX_SCALES_TOOLTIP;If slider at 0, all iterations are identical.\nIf > 0 Scale and radius are reduced when iterations increase, and conversely. TP_RETINEX_SETTINGS;Settings TP_RETINEX_SLOPE;Free gamma slope +TP_RETINEX_SKAL;Scale TP_RETINEX_STRENGTH;Strength TP_RETINEX_THRESHOLD;Threshold TP_RETINEX_THRESHOLD_TOOLTIP;Limits in/out.\nIn = image source,\nOut = image gauss. TP_RETINEX_TLABEL;TM Min=%1 Max=%2 Mean=%3 Sigma=%4 TP_RETINEX_TLABEL2;TM Tm=%1 TM=%2 TP_RETINEX_TLABEL_TOOLTIP;Transmission map result.\nMin and Max are used by Variance.\nMean and Sigma.\nTm=Min TM=Max of transmission map. +TP_RETINEX_TRANF;Transmission TP_RETINEX_TRANSMISSION;Transmission map TP_RETINEX_GAINTRANSMISSION;Gain transmission TP_RETINEX_GAINTRANSMISSION_TOOLTIP;Amplfy or reduce transmission-map to achieve luminance.\nAbscissa: transmission -min from 0, mean, and values (max).\nOrdinate : gain diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index d3d276c43..bab98ef0c 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -236,6 +236,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e bool higplus = false ; float elogt; float hl = deh.baselog; + scal = deh.skal; if(hl >= 2.71828f) { elogt = 2.71828f + SQR(SQR(hl - 2.71828f)); @@ -292,11 +293,11 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e float grads; float grad = 1.f; - float sc = 3.f; + float sc = scal; if(gradient == 0) { grad = 1.f; - sc = 3.f; + sc = scal;//3.f } else if(gradient == 1) { grad = 0.25f * it + 0.75f; sc = -0.5f * it + 4.5f; @@ -336,6 +337,10 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e sc = 3.f; } + if(iter == 1) { + sc = scal; + } + float varx; float limdx, ilimdx; @@ -396,7 +401,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } strengthx = ks * strength; - + //printf("scale=%d\n", scal); retinex_scales( RetinexScales, scal, moderetinex, nei / grad, high ); float *src[H_L] ALIGNED16; diff --git a/rtengine/procevents.h b/rtengine/procevents.h index cd6fc2cb2..2a12516ce 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -467,6 +467,7 @@ enum ProcEvent { EvRetinexmapcurve = 437, EvviewMethod = 438, EvRetinexgaintransmission = 439, + EvLskal = 440, NUMOFEVENTS }; } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 988bd20dc..1252fc0b4 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -158,7 +158,7 @@ void RetinexParams::setDefaults() { enabled = false; str = 20; - scal = 3; + scal = 0; iter = 1; grad = 1; grads = 1; @@ -177,7 +177,7 @@ void RetinexParams::setDefaults() radius = 40; baselog = 2.71828; -// grbl = 50; + skal = 3; retinexMethod = "high"; mapMethod = "none"; viewMethod = "none"; @@ -1536,9 +1536,9 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_double ("Retinex", "baselog", retinex.baselog); } -// if (!pedited || pedited->retinex.grbl) { -// keyFile.set_integer ("Retinex", "grbl", retinex.grbl); -// } + if (!pedited || pedited->retinex.skal) { + keyFile.set_integer ("Retinex", "skal", retinex.skal); + } if (!pedited || pedited->retinex.retinexMethod) { keyFile.set_string ("Retinex", "RetinexMethod", retinex.retinexMethod); @@ -4065,14 +4065,14 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } - /* if (keyFile.has_key ("Retinex", "grbl")) { - retinex.grbl = keyFile.get_integer ("Retinex", "grbl"); + if (keyFile.has_key ("Retinex", "skal")) { + retinex.skal = keyFile.get_integer ("Retinex", "skal"); + + if (pedited) { + pedited->retinex.skal = true; + } + } - if (pedited) { - pedited->retinex.grbl = true; - } - } - */ if (keyFile.has_key ("Retinex", "CDCurve")) { retinex.cdcurve = keyFile.get_double_list ("Retinex", "CDCurve"); @@ -7568,7 +7568,7 @@ bool ProcParams::operator== (const ProcParams& other) && retinex.radius == other.retinex.radius && retinex.baselog == other.retinex.baselog -// && retinex.grbl == other.retinex.grbl + && retinex.skal == other.retinex.skal && retinex.offs == other.retinex.offs && retinex.retinexMethod == other.retinex.retinexMethod && retinex.mapMethod == other.retinex.mapMethod diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 0b45e7d7a..f07de9523 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -310,7 +310,7 @@ public: int limd; int highl; double baselog; -// int grbl; + int skal; bool medianmap; RetinexParams (); void setDefaults(); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 10f911529..240c871b5 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -466,7 +466,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvmapMethod DEMOSAIC, // EvRetinexmapcurve DEMOSAIC, // EvviewMethod - RETINEX // EvRetinexgaintransmission + RETINEX, // EvRetinexgaintransmission + RETINEX //EvLskal }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 1183b8260..5608590ca 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -73,7 +73,7 @@ void ParamsEdited::set (bool v) retinex.limd = v; retinex.highl = v; retinex.baselog = v; -// retinex.grbl = v; + retinex.skal = v; retinex.medianmap = v; retinex.transmissionCurve = v; retinex.gaintransmissionCurve = v; @@ -565,7 +565,7 @@ void ParamsEdited::initFrom (const std::vector retinex.limd = retinex.limd && p.retinex.limd == other.retinex.limd; retinex.highl = retinex.highl && p.retinex.highl == other.retinex.highl; retinex.baselog = retinex.baselog && p.retinex.baselog == other.retinex.baselog; -// retinex.grbl = retinex.grbl && p.retinex.grbl == other.retinex.grbl; + retinex.skal = retinex.skal && p.retinex.skal == other.retinex.skal; retinex.medianmap = retinex.medianmap && p.retinex.medianmap == other.retinex.medianmap; retinex.highlights = retinex.highlights && p.retinex.highlights == other.retinex.highlights; retinex.htonalwidth = retinex.htonalwidth && p.retinex.htonalwidth == other.retinex.htonalwidth; @@ -1166,9 +1166,9 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.retinex.baselog = mods.retinex.baselog; } -// if (retinex.grbl) { -// toEdit.retinex.grbl = mods.retinex.grbl; -// } + if (retinex.skal) { + toEdit.retinex.skal = mods.retinex.skal; + } if (retinex.gain) { toEdit.retinex.gain = dontforceSet && options.baBehav[ADDSET_RETI_GAIN] ? toEdit.retinex.gain + mods.retinex.gain : mods.retinex.gain; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 8e21ef5ad..3e2583bf2 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -78,7 +78,7 @@ public: bool limd; bool highl; bool baselog; -// bool grbl; + bool skal; bool method; bool transmissionCurve; bool gaintransmissionCurve; diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index bad21cfe7..b0db92448 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -54,6 +54,9 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), dhbox->pack_start(*retinexcolorspace); retinexVBox->pack_start(*dhbox); + Gtk::VBox *equalVBox = Gtk::manage (new Gtk::VBox()); + + equalFrame = Gtk::manage (new Gtk::Frame(M("TP_RETINEX_EQUAL"))); // Histogram equalizer Lab curve curveEditorGD = new CurveEditorGroup (options.lastRetinexDir, M("TP_RETINEX_CONTEDIT_LAB")); @@ -164,8 +167,8 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), offs = Gtk::manage (new Adjuster (M("TP_RETINEX_OFFSET"), -1000, 5000, 1, 0)); // vart = Gtk::manage (new Adjuster (M("TP_RETINEX_VARIANCE"), 50, 500, 1, 125)); limd = Gtk::manage (new Adjuster (M("TP_RETINEX_THRESHOLD"), 2, 100, 1, 8)); - baselog = Gtk::manage (new Adjuster (M("TP_RETINEX_BASELOG"), 1.1, 100., 0.001, 2.718)); -// grbl = Gtk::manage (new Adjuster (M("TP_RETINEX_HIGHLIGHT3"), 1, 100, 1, 50)); + baselog = Gtk::manage (new Adjuster (M("TP_RETINEX_BASELOG"), 1., 10., 1., 3.)); + skal = Gtk::manage (new Adjuster (M("TP_RETINEX_SKAL"), 1, 10, 1, 3)); gain->set_tooltip_markup (M("TP_RETINEX_GAIN_TOOLTIP")); scal->set_tooltip_markup (M("TP_RETINEX_SCALES_TOOLTIP")); iter->set_tooltip_markup (M("TP_RETINEX_ITER_TOOLTIP")); @@ -267,54 +270,68 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), settingsVBox->pack_start (*transLabels2); transLabels2->show (); - settingsVBox->pack_start (*curveEditorGD, Gtk::PACK_SHRINK, 4); + equalVBox->pack_start (*curveEditorGD, Gtk::PACK_SHRINK, 4); curveEditorGD->show(); - settingsVBox->pack_start (*curveEditorGDH, Gtk::PACK_SHRINK, 4); + equalVBox->pack_start (*curveEditorGDH, Gtk::PACK_SHRINK, 4); curveEditorGDH->show(); - settingsVBox->pack_start (*curveEditorGH, Gtk::PACK_SHRINK, 4); + equalVBox->pack_start (*curveEditorGH, Gtk::PACK_SHRINK, 4); curveEditorGH->show(); gambox->pack_start(*gammaretinex); - settingsVBox->pack_start(*gambox); + equalVBox->pack_start(*gambox); gammaretinex->show(); - settingsVBox->pack_start (*gam); + equalVBox->pack_start (*gam); gam->show (); - settingsVBox->pack_start (*slope); + equalVBox->pack_start (*slope); slope->show (); + equalFrame->add(*equalVBox); + settingsVBox->pack_start (*equalFrame); - settingsVBox->pack_start (*iter); + + Gtk::VBox *iterVBox = Gtk::manage (new Gtk::VBox()); + + iterFrame = Gtk::manage (new Gtk::Frame(M("TP_RETINEX_ITERF"))); + + iterVBox->pack_start (*iter); iter->show (); - settingsVBox->pack_start (*scal); + iterVBox->pack_start (*scal); scal->show (); - settingsVBox->pack_start (*grad); + iterVBox->pack_start (*grad); grad->show (); - settingsVBox->pack_start (*grads); + iterVBox->pack_start (*grads); grads->show (); - settingsVBox->pack_start (*limd); - limd->show (); + iterFrame->add(*iterVBox); + settingsVBox->pack_start (*iterFrame); - settingsVBox->pack_start( *transmissionCurveEditorG, Gtk::PACK_SHRINK, 2); + Gtk::VBox *tranVBox = Gtk::manage (new Gtk::VBox()); + + tranFrame = Gtk::manage (new Gtk::Frame(M("TP_RETINEX_TRANF"))); + + tranVBox->pack_start( *transmissionCurveEditorG, Gtk::PACK_SHRINK, 2); transmissionCurveEditorG->show(); - settingsVBox->pack_start (*medianmap); + tranVBox->pack_start (*skal); + skal->show (); + + tranVBox->pack_start (*limd); + limd->show (); + + tranVBox->pack_start (*medianmap); medianmap->show (); - // settingsVBox->pack_start (*gain); - // gain->show (); + tranFrame->add(*tranVBox); + settingsVBox->pack_start (*tranFrame); - -// settingsVBox->pack_start (*vart); -// vart->show (); Gtk::VBox *gainBox = Gtk::manage (new Gtk::VBox()); Gtk::HSeparator *separator = Gtk::manage (new Gtk::HSeparator()); @@ -357,11 +374,9 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), // settingsVBox->pack_start (*highl); // highl->show (); -// settingsVBox->pack_start (*baselog); -// baselog->show (); +// settingsVBox->pack_start (*baselog); +// baselog->show (); -// settingsVBox->pack_start (*grbl); -// grbl->show (); // settingsVBox->pack_start (*Gtk::manage (new Gtk::HSeparator())); @@ -495,12 +510,12 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), s_tonalwidth->delay = 200; } - /* grbl->setAdjusterListener (this); + skal->setAdjusterListener (this); + + if (skal->delay < 200) { + skal->delay = 200; + } - if (grbl->delay < 200) { - grbl->delay = 200; - } - */ pack_start (*retinexVBox); p1Frame->add(*p1VBox); pack_start (*p1Frame, Gtk::PACK_EXPAND_WIDGET, 4); @@ -685,7 +700,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) limd->setEditedState (pedited->retinex.limd ? Edited : UnEdited); highl->setEditedState (pedited->retinex.highl ? Edited : UnEdited); baselog->setEditedState (pedited->retinex.baselog ? Edited : UnEdited); -// grbl->setEditedState (pedited->retinex.grbl ? Edited : UnEdited); + skal->setEditedState (pedited->retinex.skal ? Edited : UnEdited); set_inconsistent (multiImage && !pedited->retinex.enabled); medianmap->set_inconsistent (!pedited->retinex.medianmap); radius->setEditedState (pedited->retinex.radius ? Edited : UnEdited); @@ -745,7 +760,8 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) shadows->setValue (pp->retinex.shadows); s_tonalwidth->setValue (pp->retinex.stonalwidth); -// grbl->setValue (pp->retinex.grbl); + skal->setValue (pp->retinex.skal); + if(pp->retinex.iter == 1) { grad->set_sensitive(false); scal->set_sensitive(false); @@ -864,7 +880,7 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pp->retinex.limd = (int)limd->getValue (); pp->retinex.highl = (int)highl->getValue (); pp->retinex.baselog = baselog->getValue (); -// pp->retinex.grbl = (int)grbl->getValue (); + pp->retinex.skal = (int)skal->getValue (); pp->retinex.cdcurve = cdshape->getCurve (); pp->retinex.lhcurve = lhshape->getCurve (); pp->retinex.cdHcurve = cdshapeH->getCurve (); @@ -902,7 +918,7 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pedited->retinex.limd = limd->getEditedState (); pedited->retinex.highl = highl->getEditedState (); pedited->retinex.baselog = baselog->getEditedState (); -// pedited->retinex.grbl = grbl->getEditedState (); + pedited->retinex.skal = skal->getEditedState (); pedited->retinex.cdcurve = !cdshape->isUnChanged (); pedited->retinex.cdHcurve = !cdshapeH->isUnChanged (); pedited->retinex.transmissionCurve = !transmissionShape->isUnChanged (); @@ -1164,7 +1180,7 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi limd->setDefault (defParams->retinex.limd); highl->setDefault (defParams->retinex.highl); baselog->setDefault (defParams->retinex.baselog); -// grbl->setDefault (defParams->retinex.grbl); + skal->setDefault (defParams->retinex.skal); gam->setDefault (defParams->retinex.gam); slope->setDefault (defParams->retinex.slope); @@ -1187,7 +1203,7 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi limd->setDefaultEditedState (pedited->retinex.limd ? Edited : UnEdited); highl->setDefaultEditedState (pedited->retinex.highl ? Edited : UnEdited); baselog->setDefaultEditedState (pedited->retinex.baselog ? Edited : UnEdited); -// grbl->setDefaultEditedState (pedited->retinex.grbl ? Edited : UnEdited); + skal->setDefaultEditedState (pedited->retinex.skal ? Edited : UnEdited); gam->setDefaultEditedState (pedited->retinex.gam ? Edited : UnEdited); slope->setDefaultEditedState (pedited->retinex.slope ? Edited : UnEdited); @@ -1205,7 +1221,7 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi limd->setDefaultEditedState (Irrelevant); highl->setDefaultEditedState (Irrelevant); baselog->setDefaultEditedState (Irrelevant); -// grbl->setDefaultEditedState (Irrelevant); + skal->setDefaultEditedState (Irrelevant); str->setDefaultEditedState (Irrelevant); scal->setDefaultEditedState (Irrelevant); iter->setDefaultEditedState (Irrelevant); @@ -1278,8 +1294,8 @@ void Retinex::adjusterChanged (Adjuster* a, double newval) listener->panelChanged (EvLhighl, highl->getTextValue()); } else if (a == baselog) { listener->panelChanged (EvLbaselog, baselog->getTextValue()); -// } else if (a == grbl) { -// listener->panelChanged (EvLgrbl, grbl->getTextValue()); + } else if (a == skal) { + listener->panelChanged (EvLskal, skal->getTextValue()); } else if (a == gam) { listener->panelChanged (EvLgam, gam->getTextValue()); } else if (a == slope) { @@ -1446,7 +1462,7 @@ void Retinex::setBatchMode (bool batchMode) shadows->showEditedCB (); s_tonalwidth->showEditedCB (); -// grbl->showEditedCB (); + skal->showEditedCB (); curveEditorGD->setBatchMode (batchMode); curveEditorGDH->setBatchMode (batchMode); transmissionCurveEditorG->setBatchMode (batchMode); diff --git a/rtgui/retinex.h b/rtgui/retinex.h index b8034ccb9..064756a7b 100644 --- a/rtgui/retinex.h +++ b/rtgui/retinex.h @@ -35,7 +35,7 @@ protected: Adjuster* limd; Adjuster* highl; Adjuster* baselog; - Adjuster* grbl; + Adjuster* skal; Adjuster* gam; Adjuster* slope; Adjuster* highlights; @@ -77,6 +77,9 @@ protected: Gtk::Label* transLabels; Gtk::Label* transLabels2; Gtk::Frame *gainFrame; + Gtk::Frame *tranFrame; + Gtk::Frame *iterFrame; + Gtk::Frame *equalFrame; DiagonalCurveEditor* cdshape; DiagonalCurveEditor* cdshapeH; From ba5161d446bee8d3273963faa3fe295a5c1f431d Mon Sep 17 00:00:00 2001 From: Desmis Date: Fri, 12 Feb 2016 13:36:32 +0100 Subject: [PATCH 03/18] change default Tansmission curve --- rtengine/procparams.cc | 2 +- rtgui/retinex.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 1252fc0b4..96f8be01f 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -123,7 +123,7 @@ RetinexParams::RetinexParams () void RetinexParams::getDefaulttransmissionCurve(std::vector &curve) { - double v[12] = { 0.00, 0.34, 0.35, 0.35, + double v[12] = { 0.00, 0.50, 0.35, 0.35, 0.60, 0.75, 0.35, 0.35, 1.00, 0.50, 0.35, 0.35, }; diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index b0db92448..167e8efeb 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -168,7 +168,7 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), // vart = Gtk::manage (new Adjuster (M("TP_RETINEX_VARIANCE"), 50, 500, 1, 125)); limd = Gtk::manage (new Adjuster (M("TP_RETINEX_THRESHOLD"), 2, 100, 1, 8)); baselog = Gtk::manage (new Adjuster (M("TP_RETINEX_BASELOG"), 1., 10., 1., 3.)); - skal = Gtk::manage (new Adjuster (M("TP_RETINEX_SKAL"), 1, 10, 1, 3)); + skal = Gtk::manage (new Adjuster (M("TP_RETINEX_SKAL"), 1, 8, 1, 3)); gain->set_tooltip_markup (M("TP_RETINEX_GAIN_TOOLTIP")); scal->set_tooltip_markup (M("TP_RETINEX_SCALES_TOOLTIP")); iter->set_tooltip_markup (M("TP_RETINEX_ITER_TOOLTIP")); From 73b0bb14c0fd6b621b3e61bfbf6bced3b6fd6d4c Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 12 Feb 2016 18:42:08 +0100 Subject: [PATCH 04/18] Retinex, precalculate some expensive stuff (sin, cos, atan2) using SSE and line buffers --- rtengine/rawimagesource.cc | 119 +++++++++++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 26 deletions(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 2251c15dd..5b5ad6a99 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2447,46 +2447,113 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC // gamut control only in Lab mode const bool highlight = Tc.hrenabled; #ifdef _OPENMP - #pragma omp parallel for + #pragma omp parallel +#endif + { +#ifdef __SSE2__ + // we need some line buffers to precalculate some expensive stuff using SSE + float atan2Buffer[W] ALIGNED16; + float sqrtBuffer[W] ALIGNED16; + float sincosxBuffer[W] ALIGNED16; + float sincosyBuffer[W] ALIGNED16; + const vfloat c327d68v = F2V(327.68); + const vfloat onev = F2V(1.f); +#endif // __SSE2__ +#ifdef _OPENMP + #pragma omp for #endif - for (int i = border; i < H - border; i++ ) { - for (int j = border; j < W - border; j++) { + for (int i = border; i < H - border; i++ ) { +#ifdef __SSE2__ + // vectorized precalculation + { + int j = border; - float Lprov1 = (LBuffer[i - border][j - border]) / 327.68f; - float Chprov1 = sqrt(SQR(conversionBuffer[0][i - border][j - border]) + SQR(conversionBuffer[1][i - border][j - border])) / 327.68f; - float HH = xatan2f(conversionBuffer[1][i - border][j - border], conversionBuffer[0][i - border][j - border]); - float2 sincosval; - float valp; - float chr; - - if(chutili) { // c=f(H) + for (; j < W - border - 3; j += 4) { - valp = float((chcurve->getVal(Color::huelab_to_huehsv2(HH)) - 0.5f)); - Chprov1 *= (1.f + 2.f * valp); + vfloat av = LVFU(conversionBuffer[0][i - border][j - border]); + vfloat bv = LVFU(conversionBuffer[1][i - border][j - border]); + vfloat chprovv = vsqrtf(SQRV(av) + SQRV(bv)); + STVF(sqrtBuffer[j - border], chprovv / c327d68v); + vfloat HHv = xatan2f(bv, av); + STVF(atan2Buffer[j - border], HHv); + av /= chprovv; + bv /= chprovv; + vmask selMask = vmaskf_eq(chprovv, ZEROV); + STVF(sincosyBuffer[j - border], vself(selMask, onev, av)); + STVF(sincosxBuffer[j - border], vselfnotzero(selMask, bv)); + } + + for (; j < W - border; j++) + { + float aa = conversionBuffer[0][i - border][j - border]; + float bb = conversionBuffer[1][i - border][j - border]; + float Chprov1 = sqrt(SQR(aa) + SQR(bb)) / 327.68f; + sqrtBuffer[j - border] = Chprov1; + float HH = xatan2f(bb, aa); + atan2Buffer[j - border] = HH; + + if(Chprov1 == 0.0f) { + sincosyBuffer[j - border] = 1.f; + sincosxBuffer[j - border] = 0.0f; + } else { + sincosyBuffer[j - border] = aa / (Chprov1 * 327.68f); + sincosxBuffer[j - border] = bb / (Chprov1 * 327.68f); + } } } +#endif // __SSE2__ + + for (int j = border; j < W - border; j++) { + float Lprov1 = (LBuffer[i - border][j - border]) / 327.68f; +#ifdef __SSE2__ + float Chprov1 = sqrtBuffer[j - border]; + float HH = atan2Buffer[j - border]; + float2 sincosval; + sincosval.x = sincosxBuffer[j - border]; + sincosval.y = sincosyBuffer[j - border]; - sincosval = xsincosf(HH); - float R, G, B; -#ifdef _DEBUG - bool neg = false; - bool more_rgb = false; - //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else - //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); + float aa = conversionBuffer[0][i - border][j - border]; + float bb = conversionBuffer[1][i - border][j - border]; + float Chprov1 = sqrt(SQR(aa) + SQR(bb)) / 327.68f; + float HH = xatan2f(bb, aa); + float2 sincosval;// = xsincosf(HH); + + if(Chprov1 == 0.0f) { + sincosval.y = 1.f; + sincosval.x = 0.0f; + } else { + sincosval.y = aa / (Chprov1 * 327.68f); + sincosval.x = bb / (Chprov1 * 327.68f); + } + +#endif + + if(chutili) { // c=f(H) + float valp = float((chcurve->getVal(Color::huelab_to_huehsv2(HH)) - 0.5f)); + Chprov1 *= (1.f + 2.f * valp); + } + + float R, G, B; +#ifdef _DEBUG + bool neg = false; + bool more_rgb = false; + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); +#else + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); #endif - conversionBuffer[0][i - border][j - border] = 327.68f * Chprov1 * sincosval.y; - conversionBuffer[1][i - border][j - border] = 327.68f * Chprov1 * sincosval.x; - LBuffer[i - border][j - border] = Lprov1 * 327.68f; + conversionBuffer[0][i - border][j - border] = 327.68f * Chprov1 * sincosval.y; + conversionBuffer[1][i - border][j - border] = 327.68f * Chprov1 * sincosval.x; + LBuffer[i - border][j - border] = Lprov1 * 327.68f; + } } } - //end gamut control #ifdef __SSE2__ vfloat wipv[3][3]; From 67a19d0cc97fbb289e2cc5db91f2211c1d3255fc Mon Sep 17 00:00:00 2001 From: Desmis Date: Sat, 13 Feb 2016 08:02:04 +0100 Subject: [PATCH 05/18] small change to take into account new scale with iterations --- rtengine/ipretinex.cc | 15 ++++++++++++++- rtengine/procparams.cc | 2 +- rtengine/rawimagesource.cc | 1 - 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index bab98ef0c..f66fb39af 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -297,7 +297,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e if(gradient == 0) { grad = 1.f; - sc = scal;//3.f + sc = 3.f; } else if(gradient == 1) { grad = 0.25f * it + 0.75f; sc = -0.5f * it + 4.5f; @@ -339,6 +339,19 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e if(iter == 1) { sc = scal; + } else { + //adjust sc in function of choice of scale by user if iterations + if(scal < 3) { + sc -= 1; + + if(sc < 1.f) {//avoid 0 + sc = 1.f; + } + } + + if(scal > 4) { + sc += 1; + } } float varx; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 96f8be01f..7575564c5 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -158,7 +158,7 @@ void RetinexParams::setDefaults() { enabled = false; str = 20; - scal = 0; + scal = 3; iter = 1; grad = 1; grads = 1; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 5b5ad6a99..b29348c9f 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2234,7 +2234,6 @@ void RawImageSource::retinexPrepareCurves(RetinexParams retinexParams, LUTf &cdc void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) { - MyTime t4, t5; t4.set(); From 721de446f456ed1cf06b58cc05d76673e0fbcb43 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 9 May 2016 20:00:12 +0200 Subject: [PATCH 06/18] Fix crash caused by uninitialized variables when using ciecam02 on files without exif data, fixes #3084 --- rtengine/imagedata.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index c0da10761..bbfc303fc 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -44,7 +44,7 @@ ImageMetaData* ImageMetaData::fromFile (const Glib::ustring& fname, RawMetaDataL return new ImageData (fname, rml); } -ImageData::ImageData (Glib::ustring fname, RawMetaDataLocation* ri) +ImageData::ImageData (Glib::ustring fname, RawMetaDataLocation* ri) : iso_speed(0), aperture(0.), shutter(0.) { size_t dotpos = fname.find_last_of ('.'); From 1edfb0c6f79d72acb6f759e2df30a11503404b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Tue, 10 May 2016 20:39:20 +0200 Subject: [PATCH 07/18] Switch `getClutValue` to vfloat2 and load/store source[RGB] unaligned Ingo had some cleanup suggestions in #3154 which I tried to realize with this commit. Although switching to `vfloat2` is a clever idea, I can see no further speedup. --- rtengine/clutstore.cc | 27 +++++++++++++++++++-------- rtengine/improcfun.cc | 34 ++++++++++++++++------------------ 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index 5d859f90c..fc167734c 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -56,7 +56,7 @@ bool loadFile( img_src.convertColorSpace(img_float.get(), icm, curr_wb); } - AlignedBuffer image(fw * fh * 4 + 8); // + 8 because of SSE4_1 version of getClutValue + AlignedBuffer image(fw * fh * 4 + 8); // + 8 because of SSE4_1 version of getClutValues std::size_t index = 0; @@ -78,12 +78,19 @@ bool loadFile( } #ifdef __SSE2__ -vfloat getClutValue(const AlignedBuffer& clut_image, size_t index) +vfloat2 getClutValues(const AlignedBuffer& clut_image, size_t index) { + const __m128i v_values = _mm_loadu_si128(reinterpret_cast(clut_image.data + index)); #ifdef __SSE4_1__ - return _mm_cvtepi32_ps(_mm_cvtepu16_epi32(_mm_loadu_si128(reinterpret_cast(clut_image.data + index)))); + return { + _mm_cvtepi32_ps(_mm_cvtepu16_epi32(v_values)), + _mm_cvtepi32_ps(_mm_cvtepu16_epi32(_mm_srli_si128(v_values, 8))) + }; #else - return _mm_set_ps(clut_image.data[index + 3], clut_image.data[index + 2], clut_image.data[index + 1], clut_image.data[index]); + return { + _mm_cvtpu16_ps(_mm_movepi64_pi64(v_values)), + _mm_cvtpu16_ps(_mm_movepi64_pi64(_mm_srli_si128(v_values, 8))) + }; #endif } #endif @@ -212,11 +219,13 @@ void rtengine::HaldCLUT::getRGB( const vfloat v_r = PERMUTEPS(v_rgb, _MM_SHUFFLE(0, 0, 0, 0)); - vfloat v_tmp1 = vintpf(v_r, getClutValue(clut_image, index + 4), getClutValue(clut_image, index)); + vfloat2 v_clut_values = getClutValues(clut_image, index); + vfloat v_tmp1 = vintpf(v_r, v_clut_values.y, v_clut_values.x); index = (color + level) * 4; - vfloat v_tmp2 = vintpf(v_r, getClutValue(clut_image, index + 4), getClutValue(clut_image, index)); + v_clut_values = getClutValues(clut_image, index); + vfloat v_tmp2 = vintpf(v_r, v_clut_values.y, v_clut_values.x); const vfloat v_g = PERMUTEPS(v_rgb, _MM_SHUFFLE(1, 1, 1, 1)); @@ -224,11 +233,13 @@ void rtengine::HaldCLUT::getRGB( index = (color + level_square) * 4; - v_tmp1 = vintpf(v_r, getClutValue(clut_image, index + 4), getClutValue(clut_image, index)); + v_clut_values = getClutValues(clut_image, index); + v_tmp1 = vintpf(v_r, v_clut_values.y, v_clut_values.x); index = (color + level + level_square) * 4; - v_tmp2 = vintpf(v_r, getClutValue(clut_image, index + 4), getClutValue(clut_image, index)); + v_clut_values = getClutValues(clut_image, index); + v_tmp2 = vintpf(v_r, v_clut_values.y, v_clut_values.x); v_tmp1 = vintpf(v_g, v_tmp2, v_tmp1); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index e9ae98e2a..bc70bf5e5 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -3226,8 +3226,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer xyz2clut = iccStore->workingSpaceInverseMatrix( hald_clut->getProfile() ); xyz2work = iccStore->workingSpaceInverseMatrix( params->icm.working ); clut2xyz = iccStore->workingSpaceMatrix( hald_clut->getProfile() ); -#ifdef __SSE2__ +#ifdef __SSE2__ for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { v_work2xyz[i][j] = F2V(work2xyz[i][j]); @@ -3236,8 +3236,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer v_clut2xyz[i][j] = F2V(clut2xyz[i][j]); } } - #endif + } } } @@ -4361,12 +4361,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // Convert from working to clut profile int j = jstart; int tj = 0; -#ifdef __SSE2__ +#ifdef __SSE2__ for (; j < tW - 3; j += 4, tj += 4) { - vfloat sourceR = LVFU(rtemp[ti * TS + tj]); - vfloat sourceG = LVFU(gtemp[ti * TS + tj]); - vfloat sourceB = LVFU(btemp[ti * TS + tj]); + vfloat sourceR = LVF(rtemp[ti * TS + tj]); + vfloat sourceG = LVF(gtemp[ti * TS + tj]); + vfloat sourceB = LVF(btemp[ti * TS + tj]); vfloat x; vfloat y; @@ -4374,11 +4374,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, v_work2xyz); Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, v_xyz2clut); - STVFU(rtemp[ti * TS + tj], sourceR); - STVFU(gtemp[ti * TS + tj], sourceG); - STVFU(btemp[ti * TS + tj], sourceB); + STVF(rtemp[ti * TS + tj], sourceR); + STVF(gtemp[ti * TS + tj], sourceG); + STVF(btemp[ti * TS + tj], sourceB); } - #endif for (; j < tW; j++, tj++) { @@ -4428,12 +4427,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // Convert from clut to working profile int j = jstart; int tj = 0; -#ifdef __SSE2__ +#ifdef __SSE2__ for (; j < tW - 3; j += 4, tj += 4) { - vfloat sourceR = LVFU(rtemp[ti * TS + tj]); - vfloat sourceG = LVFU(gtemp[ti * TS + tj]); - vfloat sourceB = LVFU(btemp[ti * TS + tj]); + vfloat sourceR = LVF(rtemp[ti * TS + tj]); + vfloat sourceG = LVF(gtemp[ti * TS + tj]); + vfloat sourceB = LVF(btemp[ti * TS + tj]); vfloat x; vfloat y; @@ -4441,11 +4440,10 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, v_clut2xyz); Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, v_xyz2work); - STVFU(rtemp[ti * TS + tj], sourceR); - STVFU(gtemp[ti * TS + tj], sourceG); - STVFU(btemp[ti * TS + tj], sourceB); + STVF(rtemp[ti * TS + tj], sourceR); + STVF(gtemp[ti * TS + tj], sourceG); + STVF(btemp[ti * TS + tj], sourceB); } - #endif for (; j < tW; j++, tj++) { From f4d5c645de112bf9e5423707513115eaf82653e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Wed, 11 May 2016 20:01:17 +0200 Subject: [PATCH 08/18] Add Ingo's `clutstore_no_mmx.patch` Ingo has provided a solution for the strange Windows crash with `_mm_cvtpu16_ps()`: It was not an alignment problem, but the use of MMX instructions which led to the SEGV. Now Ingo's solutions omits MMX instructions altogether and is nevertheless faster than the `_mm_set_ps()` workaround. Many thanks to @heckflosse! --- rtengine/clutstore.cc | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index fc167734c..2724ed34e 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -87,9 +87,18 @@ vfloat2 getClutValues(const AlignedBuffer& clut_image, size_t ind _mm_cvtepi32_ps(_mm_cvtepu16_epi32(_mm_srli_si128(v_values, 8))) }; #else + vint lowval = _mm_shuffle_epi32(v_values, _MM_SHUFFLE(1, 0, 1, 0)); + vint highval = _mm_shuffle_epi32(v_values, _MM_SHUFFLE(3, 2, 3, 2)); + lowval = _mm_shufflelo_epi16(lowval, _MM_SHUFFLE(1, 1, 0, 0)); + highval = _mm_shufflelo_epi16(highval, _MM_SHUFFLE(1, 1, 0, 0)); + lowval = _mm_shufflehi_epi16(lowval, _MM_SHUFFLE(3, 3, 2, 2)); + highval = _mm_shufflehi_epi16(highval, _MM_SHUFFLE(3, 3, 2, 2)); + lowval = vandm(lowval, _mm_set1_epi32(0x0000ffff)); + highval = vandm(highval, _mm_set1_epi32(0x0000ffff)); + return { - _mm_cvtpu16_ps(_mm_movepi64_pi64(v_values)), - _mm_cvtpu16_ps(_mm_movepi64_pi64(_mm_srli_si128(v_values, 8))) + _mm_cvtepi32_ps(lowval), + _mm_cvtepi32_ps(highval) }; #endif } @@ -261,12 +270,6 @@ void rtengine::HaldCLUT::splitClutFilename( { Glib::ustring basename = Glib::path_get_basename(filename); - Glib::ustring::size_type last_slash_pos = basename.rfind('/'); - - if (last_slash_pos == Glib::ustring::npos) { - last_slash_pos = basename.rfind('\\'); - } - const Glib::ustring::size_type last_dot_pos = basename.rfind('.'); if (last_dot_pos != Glib::ustring::npos) { From 12656796517cfd733cc9747a47de3a51ee39b682 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Wed, 11 May 2016 21:04:32 +0200 Subject: [PATCH 09/18] Retinex: some small improvements and some cleanup --- rtengine/improccoordinator.cc | 3 +- rtengine/ipretinex.cc | 246 +++++++++++----------------------- rtengine/rawimagesource.cc | 139 ++++++++++--------- 3 files changed, 158 insertions(+), 230 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index b6862ab66..7434776d5 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -55,7 +55,7 @@ ImProcCoordinator::ImProcCoordinator () lhist16(65536), lhist16Cropped(65536), lhist16CAM(65536), lhist16CroppedCAM(65536), lhist16CCAM(65536), - lhist16RETI(65536), + lhist16RETI(), histCropped(65536), lhist16Clad(65536), lhist16CLlad(65536), lhist16LClad(65536), lhist16LLClad(65536), @@ -236,6 +236,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } if (params.retinex.enabled) { + lhist16RETI(32768); lhist16RETI.clear(); imgsrc->retinexPrepareBuffers(params.icm, params.retinex, conversionBuffer, lhist16RETI); diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index f66fb39af..6773e7a12 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -47,7 +47,6 @@ #include "opthelper.h" #include "StopWatch.h" -#define MAX_RETINEX_SCALES 8 #define clipretinex( val, minv, maxv ) (( val = (val < minv ? minv : val ) ) > maxv ? maxv : val ) #define med3(a0,a1,a2,a3,a4,a5,a6,a7,a8,median) { \ @@ -60,13 +59,9 @@ PIX_SORT(pp[3],pp[6]); PIX_SORT(pp[1],pp[4]); PIX_SORT(pp[2],pp[5]); \ PIX_SORT(pp[4],pp[7]); PIX_SORT(pp[4],pp[2]); PIX_SORT(pp[6],pp[4]); \ PIX_SORT(pp[4],pp[2]); median=pp[4];} //pp4 = median -namespace rtengine + +namespace { - -extern const Settings* settings; - -static float RetinexScales[MAX_RETINEX_SCALES]; - void retinex_scales( float* scales, int nscales, int mode, int s, float high) { if ( nscales == 1 ) { @@ -102,6 +97,7 @@ void retinex_scales( float* scales, int nscales, int mode, int s, float high) } } } + void mean_stddv2( float **dst, float &mean, float &stddv, int W_L, int H_L, float &maxtr, float &mintr) { // summation using double precision to avoid too large summation error for large pictures @@ -123,14 +119,8 @@ void mean_stddv2( float **dst, float &mean, float &stddv, int W_L, int H_L, floa sum += dst[i][j]; vsquared += (dst[i][j] * dst[i][j]); - if ( dst[i][j] > lmax) { - lmax = dst[i][j] ; - } - - if ( dst[i][j] < lmin) { - lmin = dst[i][j] ; - } - + lmax = dst[i][j] > lmax ? dst[i][j] : lmax; + lmin = dst[i][j] < lmin ? dst[i][j] : lmin; } #ifdef _OPENMP @@ -148,81 +138,30 @@ void mean_stddv2( float **dst, float &mean, float &stddv, int W_L, int H_L, floa stddv = (float)sqrt(stddv); } - - - - - -void mean_stddv( float **dst, float &mean, float &stddv, int W_L, int H_L, const float factor, float &maxtr, float &mintr) - -{ - // summation using double precision to avoid too large summation error for large pictures - double vsquared = 0.f; - double sum = 0.f; - maxtr = 0.f; - mintr = 0.f; -#ifdef _OPENMP - #pragma omp parallel -#endif - { - float lmax = 0.f, lmin = 0.f; - -#ifdef _OPENMP - #pragma omp for reduction(+:sum,vsquared) // this can lead to differences, but parallel summation is more accurate -#endif - - for (int i = 0; i < H_L; i++ ) - for (int j = 0; j < W_L; j++) { - sum += dst[i][j]; - vsquared += (dst[i][j] * dst[i][j]); - - if ( dst[i][j] > lmax) { - lmax = dst[i][j] ; - } - - if ( dst[i][j] < lmin) { - lmin = dst[i][j] ; - } - - } - -#ifdef _OPENMP - #pragma omp critical -#endif - { - maxtr = maxtr > lmax ? maxtr : lmax; - mintr = mintr < lmin ? mintr : lmin; - } - - } - - sum *= factor; - maxtr *= factor; - mintr *= factor; - vsquared *= (factor * factor); - mean = sum / (float) (W_L * H_L); - vsquared /= (float) W_L * H_L; - stddv = ( vsquared - (mean * mean) ); - stddv = (float)sqrt(stddv); } + +namespace rtengine +{ + +extern const Settings* settings; + void RawImageSource::MSR(float** luminance, float** originalLuminance, float **exLuminance, LUTf & mapcurve, bool &mapcontlutili, int width, int height, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) { if (deh.enabled) {//enabled float mean, stddv, maxtr, mintr; - //float mini, delta, maxi; float delta; - float eps = 2.f; + constexpr float eps = 2.f; bool useHsl = deh.retinexcolorspace == "HSLLOG"; bool useHslLin = deh.retinexcolorspace == "HSLLIN"; float gain2 = (float) deh.gain / 100.f; //def =1 not use gain2 = useHslLin ? gain2 * 0.5f : gain2; float offse = (float) deh.offs; //def = 0 not use int iter = deh.iter; - int gradient = deh.scal; + int gradient = deh.scal; int scal = 3;//disabled scal - int nei = (int) 2.8f * deh.neigh; //def = 220 + int nei = (int) (2.8f * deh.neigh); //def = 220 float vart = (float)deh.vart / 100.f;//variance float gradvart = (float)deh.grad; float gradstr = (float)deh.grads; @@ -231,9 +170,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e limD = pow(limD, 1.7f);//about 2500 enough limD *= useHslLin ? 10.f : 1.f; float ilimD = 1.f / limD; - int moderetinex = 2; // default to 2 ( deh.retinexMethod == "high" ) float hig = ((float) deh.highl) / 100.f; - bool higplus = false ; float elogt; float hl = deh.baselog; scal = deh.skal; @@ -248,50 +185,43 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e int W_L = width; float *tran[H_L] ALIGNED16; - float *tranBuffer; - int viewmet = 0; + float *tranBuffer = nullptr; elogt = 2.71828f;//disabled baselog - FlatCurve* shcurve = NULL;//curve L=f(H) bool lhutili = false; - if (deh.enabled) { - shcurve = new FlatCurve(deh.lhcurve); + FlatCurve* shcurve = new FlatCurve(deh.lhcurve); //curve L=f(H) - if (!shcurve || shcurve->isIdentity()) { - if (shcurve) { - delete shcurve; - shcurve = NULL; - } - } else { - lhutili = true; + if (!shcurve || shcurve->isIdentity()) { + if (shcurve) { + delete shcurve; + shcurve = nullptr; } + } else { + lhutili = true; } + bool higplus = false ; + int moderetinex = 2; // default to 2 ( deh.retinexMethod == "high" ) + if(deh.retinexMethod == "highliplus") { higplus = true; - } - - if (deh.retinexMethod == "uni") { + moderetinex = 3; + } else if (deh.retinexMethod == "uni") { moderetinex = 0; - } - - if (deh.retinexMethod == "low") { + } else if (deh.retinexMethod == "low") { moderetinex = 1; - } - - if (deh.retinexMethod == "highli" || deh.retinexMethod == "highliplus") { + } else { /*if (deh.retinexMethod == "highli") */ moderetinex = 3; } - for(int it = 1; it < iter + 1; it++) { //iter nb max of iterations - float aahi = 49.f / 99.f; ////reduce sensibility 50% - float bbhi = 1.f - aahi; - float high; - high = bbhi + aahi * (float) deh.highl; + constexpr float aahi = 49.f / 99.f; ////reduce sensibility 50% + constexpr float bbhi = 1.f - aahi; + + for(int it = 1; it < iter + 1; it++) { //iter nb max of iterations + float high = bbhi + aahi * (float) deh.highl; - float grads; float grad = 1.f; float sc = scal; @@ -382,7 +312,6 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } scal = round(sc); - float strengthx; float ks = 1.f; if(gradstr != 0) { @@ -413,8 +342,11 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } } - strengthx = ks * strength; - //printf("scale=%d\n", scal); + float strengthx = ks * strength; + + constexpr auto maxRetinexScales = 8; + float RetinexScales[maxRetinexScales]; + retinex_scales( RetinexScales, scal, moderetinex, nei / grad, high ); float *src[H_L] ALIGNED16; @@ -428,39 +360,28 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e int shHighlights = deh.highlights; int shShadows = deh.shadows; + int mapmet = 0; if(deh.mapMethod == "map") { mapmet = 2; - } - - if(deh.mapMethod == "mapT") { + } else if(deh.mapMethod == "mapT") { mapmet = 3; - } - - /*if(deh.mapMethod == "curv") { - mapmet = 1; - }*/ - - if(deh.mapMethod == "gaus") { + } else if(deh.mapMethod == "gaus") { mapmet = 4; } const double shradius = mapmet == 4 ? (double) deh.radius : 40.; + int viewmet = 0; + if(deh.viewMethod == "mask") { viewmet = 1; - } - - if(deh.viewMethod == "tran") { + } else if(deh.viewMethod == "tran") { viewmet = 2; - } - - if(deh.viewMethod == "tran2") { + } else if(deh.viewMethod == "tran2") { viewmet = 3; - } - - if(deh.viewMethod == "unsharp") { + } else if(deh.viewMethod == "unsharp") { viewmet = 4; } @@ -554,6 +475,12 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e #endif if(mapmet > 0 && mapcontlutili && it == 1) { + // TODO: When rgbcurvespeedup branch is merged into master we can simplify the code by + // 1) in rawimagesource.retinexPrepareCurves() insert + // mapcurve *= 0.5f; + // after + // CurveFactory::mapcurve (mapcontlutili, retinexParams.mapcurve, mapcurve, 1, lhist16RETI, histLRETI); + // 2) remove the division by 2.f from the code 7 lines below this line #ifdef _OPENMP #pragma omp parallel for #endif @@ -567,21 +494,21 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } if(((mapmet == 2 && scale > 2) || mapmet == 3 || mapmet == 4) && it == 1) { - - + float hWeight = (100.f - shHighlights) / 100.f; + float sWeight = (100.f - shShadows) / 100.f; #ifdef _OPENMP - #pragma omp parallel for + #pragma omp parallel for schedule(dynamic,16) #endif for (int i = 0; i < H_L; i++) { for (int j = 0; j < W_L; j++) { - double mapval = 1.0 + shmap->map[i][j]; - double factor = 1.0; + float mapval = 1.f + shmap->map[i][j]; + float factor = 1.f; if (mapval > h_th) { - factor = (h_th + (100.0 - shHighlights) * (mapval - h_th) / 100.0) / mapval; + factor = (h_th + hWeight * (mapval - h_th)) / mapval; } else if (mapval < s_th) { - factor = (s_th - (100.0 - shShadows) * (s_th - mapval) / 100.0) / mapval; + factor = (s_th - sWeight * (s_th - mapval)) / mapval; } out[i][j] *= factor; @@ -629,10 +556,9 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } } - shmap = NULL; + shmap = nullptr; delete [] buffer; - //delete [] outBuffer; delete [] srcBuffer; mean = 0.f; @@ -657,6 +583,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e bmax *= 500.f; amin *= 500.f; bmin *= 500.f; + #ifdef _OPENMP #pragma omp parallel #endif @@ -676,6 +603,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e absciss = amin * luminance[i][j] + bmin; } + //TODO : move multiplication by 4.f and subtraction of 1.f inside the curve luminance[i][j] *= (-1.f + 4.f * dehatransmissionCurve[absciss]); //new transmission if(viewmet == 3 || viewmet == 2) { @@ -797,10 +725,9 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e #pragma omp parallel #endif { - float absciss; float cdmax = -999999.f, cdmin = 999999.f; #ifdef _OPENMP - #pragma omp for + #pragma omp for schedule(dynamic,16) nowait #endif for ( int i = 0; i < H_L; i ++ ) @@ -808,6 +735,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e float gan; if (dehagaintransmissionCurve && mean != 0.f && stddv != 0.f) { + float absciss; if (LIKELY(fabsf(luminance[i][j] - mean) < stddv)) { absciss = asig * luminance[i][j] + bsig; @@ -819,6 +747,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e // float cd = cdfactor * ( luminance[i][j] - mini ) + offse; + // TODO : move multiplication by 2.f inside the curve gan = 2.f * (dehagaintransmissionCurve[absciss]); //new gain function transmission } else { gan = 0.5f; @@ -826,17 +755,12 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e float cd = gan * cdfactor * ( luminance[i][j] ) + offse; - if(cd > cdmax) { - cdmax = cd; - } - - if(cd < cdmin) { - cdmin = cd; - } + cdmax = cd > cdmax ? cd : cdmax; + cdmin = cd < cdmin ? cd : cdmin; float str = strengthx; - if(lhutili && it == 1) { // S=f(H) + if(lhutili && it == 1) { // S=f(H) { float HH = exLuminance[i][j]; float valparam; @@ -851,31 +775,23 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } } - if(exLuminance[i][j] > 65535.f * hig && higplus) { + if(higplus && exLuminance[i][j] > 65535.f * hig) { str *= hig; } if(viewmet == 0) { - luminance[i][j] = clipretinex( cd, 0.f, 32768.f ) * str + (1.f - str) * originalLuminance[i][j]; - } - - if(viewmet == 1) { + luminance[i][j] = intp(str, clipretinex( cd, 0.f, 32768.f ), originalLuminance[i][j]); + } else if(viewmet == 1) { luminance[i][j] = out[i][j]; - } - - if(viewmet == 4) { - luminance[i][j] = (1.f + str) * originalLuminance[i][j] - str * out[i][j]; //unsharp - } - - if(viewmet == 2) { + } else if(viewmet == 4) { + luminance[i][j] = originalLuminance[i][j] + str * (originalLuminance[i][j] - out[i][j]);//unsharp + } else if(viewmet == 2) { if(tran[i][j] <= mean) { luminance[i][j] = azb + aza * tran[i][j]; //auto values } else { luminance[i][j] = bzb + bza * tran[i][j]; } - } - - if(viewmet == 3) { + } else { /*if(viewmet == 3) */ luminance[i][j] = 1000.f + tran[i][j] * 700.f; //arbitrary values to help display log values which are between -20 to + 30 - usage values -4 + 5 } @@ -890,23 +806,23 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } } + delete [] outBuffer; - outBuffer = NULL; + outBuffer = nullptr; //printf("cdmin=%f cdmax=%f\n",minCD, maxCD); Tmean = mean; Tsigma = stddv; Tmin = mintr; Tmax = maxtr; - - if (shcurve && it == 1) { + if (shcurve) { delete shcurve; + shcurve = nullptr; } } - if(viewmet == 3 || viewmet == 2) { + if(tranBuffer) { delete [] tranBuffer; - tranBuffer = NULL; } } diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 27ddb6b3c..2780c033f 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1764,7 +1764,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le LCPProfile *pLCPProf = lcpStore->getProfile(lensProf.lcpFile); if (pLCPProf) { // don't check focal length to allow distortion correction for lenses without chip, also pass dummy focal length 1 in case of 0 - LCPMapper map(pLCPProf, max(idata->getFocalLen(),1.0), idata->getFocalLen35mm(), idata->getFocusDist(), idata->getFNumber(), true, false, W, H, coarse, -1); + LCPMapper map(pLCPProf, max(idata->getFocalLen(), 1.0), idata->getFocalLen35mm(), idata->getFocusDist(), idata->getFNumber(), true, false, W, H, coarse, -1); #ifdef _OPENMP #pragma omp parallel for @@ -1970,7 +1970,6 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar LUTf *retinexgamtab;//gamma before and after Retinex to restore tones LUTf lutTonereti; - lutTonereti(65536); if(retinexParams.gammaretinex == "low") { retinexgamtab = &(Color::gammatab_115_2); @@ -1986,24 +1985,33 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar double gamm2 = retinexParams.gam; if(gamm2 < 1.) { - pwr = 1. / pwr; - gamm = 1. / gamm; + std::swap(pwr, gamm); } int mode = 0, imax = 0; Color::calcGamma(pwr, ts, mode, imax, g_a0, g_a1, g_a2, g_a3, g_a4, g_a5); // call to calcGamma with selected gamma and slope // printf("g_a0=%f g_a1=%f g_a2=%f g_a3=%f g_a4=%f\n", g_a0,g_a1,g_a2,g_a3,g_a4); + double start; + double add; + + if(gamm2 < 1.) { + start = g_a2; + add = g_a4; + } else { + start = g_a3; + add = g_a4; + } + + double mul = 1. + g_a4; + + lutTonereti(65536); + for (int i = 0; i < 65536; i++) { double val = (i) / 65535.; - double start = g_a3; - double add = g_a4; - double mul = 1. + g_a4; double x; if(gamm2 < 1.) { - start = g_a2; - add = g_a4; x = Color::igammareti (val, gamm, start, ts, mul , add); } else { x = Color::gammareti (val, gamm, start, ts, mul , add); @@ -2055,6 +2063,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } */ if(retinexParams.gammaretinex != "none" && retinexParams.str != 0) {//gamma + #ifdef _OPENMP #pragma omp parallel for #endif @@ -2083,7 +2092,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar if(lhist16RETI) { - lhist16RETIThr(32769, 0); + lhist16RETIThr(lhist16RETI.getSize()); lhist16RETIThr.clear(); } @@ -2101,7 +2110,6 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar for (; j < W - border - 3; j += 4) { vfloat H, S, L; - int pos; Color::rgb2hsl(LVFU(red[i][j]), LVFU(green[i][j]), LVFU(blue[i][j]), H, S, L); STVFU(conversionBuffer[0][i - border][j - border], H); STVFU(conversionBuffer[1][i - border][j - border], S); @@ -2111,7 +2119,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar if(lhist16RETI) { for(int p = 0; p < 4; p++) { - pos = (int) clipretinex( conversionBuffer[2][i - border][j - border + p], 0.f, 32768.f);//histogram in curve HSL + int pos = ( conversionBuffer[2][i - border][j - border + p]);//histogram in curve HSL lhist16RETIThr[pos]++; } } @@ -2121,14 +2129,13 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar for (; j < W - border; j++) { float H, S, L; - int pos; //rgb=>lab Color::rgb2hslfloat(red[i][j], green[i][j], blue[i][j], conversionBuffer[0][i - border][j - border], conversionBuffer[1][i - border][j - border], L); L *= 32768.f; conversionBuffer[2][i - border][j - border] = L; if(lhist16RETI) { - pos = (int) clipretinex(L, 0, 32768); + int pos = L; lhist16RETIThr[pos]++; } } @@ -2139,10 +2146,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar { if(lhist16RETI) { - // Add per Thread LUT to global LUT - for(int i = 0; i < 32769; i++) { - lhist16RETI[i] += lhist16RETIThr[i]; - } + lhist16RETI += lhist16RETIThr; // Add per Thread LUT to global LUT } } #endif @@ -2150,10 +2154,10 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } } else { TMatrix wprof = iccStore->workingSpaceMatrix (cmp.working); - double wp[3][3] = { - {wprof[0][0], wprof[0][1], wprof[0][2]}, - {wprof[1][0], wprof[1][1], wprof[1][2]}, - {wprof[2][0], wprof[2][1], wprof[2][2]} + float wp[3][3] = { + {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, + {static_cast(wprof[1][0]), static_cast(wprof[1][1]), static_cast(wprof[1][2])}, + {static_cast(wprof[2][0]), static_cast(wprof[2][1]), static_cast(wprof[2][2])} }; // Conversion rgb -> lab is hard to vectorize because it uses a lut (that's not the main problem) @@ -2166,25 +2170,19 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar LUTu lhist16RETIThr; if(lhist16RETI) { - lhist16RETIThr(32769, 0); + lhist16RETIThr(lhist16RETI.getSize()); lhist16RETIThr.clear(); } #ifdef _OPENMP - #pragma omp for + #pragma omp for schedule(dynamic,16) #endif for (int i = border; i < H - border; i++ ) for (int j = border; j < W - border; j++) { float X, Y, Z, L, aa, bb; - int pos; - float R_, G_, B_; - R_ = red[i][j]; - G_ = green[i][j]; - B_ = blue[i][j]; - float k; //rgb=>lab - Color::rgbxyz(R_, G_, B_, X, Y, Z, wp); + Color::rgbxyz(red[i][j], green[i][j], blue[i][j], X, Y, Z, wp); //convert Lab Color::XYZ2Lab(X, Y, Z, L, aa, bb); conversionBuffer[0][i - border][j - border] = aa; @@ -2195,7 +2193,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar // if(R_>40000.f && G_ > 30000.f && B_ > 30000.f) conversionBuffer[3][i - border][j - border] = R_; // else conversionBuffer[3][i - border][j - border] = 0.f; if(lhist16RETI) { - pos = (int) clipretinex(L, 0, 32768); + int pos = L; lhist16RETIThr[pos]++;//histogram in Curve Lab } } @@ -2204,10 +2202,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar #pragma omp critical { if(lhist16RETI) { - // Add per Thread LUT to global LUT - for(int i = 0; i < 32769; i++) { - lhist16RETI[i] += lhist16RETIThr[i]; - } + lhist16RETI += lhist16RETIThr; // Add per Thread LUT to global LUT } } #endif @@ -2263,23 +2258,29 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC int mode = 0, imax = 0; if(gamm2 < 1.) { - pwr = 1. / pwr; - gamm = 1. / gamm; + std::swap(pwr, gamm); } Color::calcGamma(pwr, ts, mode, imax, g_a0, g_a1, g_a2, g_a3, g_a4, g_a5); // call to calcGamma with selected gamma and slope + double mul = 1. + g_a4; + double add; + double start; + + if(gamm2 < 1.) { + start = g_a3; + add = g_a3; + } else { + add = g_a4; + start = g_a2; + } + // printf("g_a0=%f g_a1=%f g_a2=%f g_a3=%f g_a4=%f\n", g_a0,g_a1,g_a2,g_a3,g_a4); for (int i = 0; i < 65536; i++) { double val = (i) / 65535.; double x; - double mul = 1. + g_a4; - double add = g_a4; - double start = g_a2; if(gamm2 < 1.) { - start = g_a3; - add = g_a3; x = Color::gammareti (val, gamm, start, ts, mul , add); } else { x = Color::igammareti (val, gamm, start, ts, mul , add); @@ -2303,11 +2304,10 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC float val; if(dehacontlutili && histLRETI) { - hist16RET(32769, 0); + hist16RET(32768); hist16RET.clear(); histLRETI.clear(); - dLcurve(32769, 0); - dLcurve.clear(); + dLcurve(32768); } FlatCurve* chcurve = NULL;//curve c=f(H) @@ -2335,8 +2335,8 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC // one LUT per thread LUTu hist16RETThr; - if(dehacontlutili && histLRETI) { - hist16RETThr(32769, 0); + if(hist16RET) { + hist16RETThr(hist16RET.getSize()); hist16RETThr.clear(); } @@ -2350,7 +2350,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC LBuffer[i][j] = cdcurve[2.f * temp[i][j]] / 2.f; if(histLRETI) { - int pos = (int) clipretinex(LBuffer[i][j], 0.f, 32768.f); + int pos = LBuffer[i][j]; hist16RETThr[pos]++; //histogram in Curve } } @@ -2363,24 +2363,24 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC #pragma omp critical #endif { - if(dehacontlutili && histLRETI) { - // Add per Thread LUT to global LUT - for(int i = 0; i < 32769; i++) { - hist16RET[i] += hist16RETThr[i]; - } + if(hist16RET) { + hist16RET += hist16RETThr; // Add per Thread LUT to global LUT } } } - if(dehacontlutili && histLRETI) {//update histogram + if(hist16RET) {//update histogram + // TODO : When rgbcurvesspeedup branch is merged into master, replace this by the following 1-liner + // hist16RET.compressTo(histLRETI); + // also remove declaration and init of dLcurve some lines above then and finally remove this comment :) for (int i = 0; i < 32768; i++) { val = (double)i / 32767.0; - dLcurve[i] = CLIPD(val); + dLcurve[i] = val; } for (int i = 0; i < 32768; i++) { float hval = dLcurve[i]; - int hi = (int)(255.0f * CLIPD(hval)); + int hi = (int)(255.0f * hval); histLRETI[hi] += hist16RET[i]; } } @@ -2399,7 +2399,6 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC for (; j < W - border; j++) { float valp; - float chr; // if(chutili) { // c=f(H) { valp = float((chcurve->getVal(conversionBuffer[3][i - border][j - border]) - 0.5f)); @@ -4365,12 +4364,12 @@ void RawImageSource::hlRecovery (std::string method, float* red, float* green, f void RawImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) { -BENCHFUN + BENCHFUN histcompr = 3; histogram(65536 >> histcompr); histogram.clear(); - const float refwb[3] = {static_cast(refwb_red),static_cast(refwb_green),static_cast(refwb_blue)}; + const float refwb[3] = {static_cast(refwb_red), static_cast(refwb_green), static_cast(refwb_blue)}; #ifdef _OPENMP #pragma omp parallel @@ -4388,11 +4387,11 @@ BENCHFUN if (ri->getSensorType() == ST_BAYER) { for (int j = start; j < end; j++) { - tmphistogram[(int)(refwb[ri->FC(i,j)] * rawData[i][j]) >> histcompr] += 4; + tmphistogram[(int)(refwb[ri->FC(i, j)] * rawData[i][j]) >> histcompr] += 4; } } else if (ri->getSensorType() == ST_FUJI_XTRANS) { for (int j = start; j < end; j++) { - tmphistogram[(int)(refwb[ri->XTRANSFC(i,j)] * rawData[i][j]) >> histcompr] += 4; + tmphistogram[(int)(refwb[ri->XTRANSFC(i, j)] * rawData[i][j]) >> histcompr] += 4; } } else if (ri->get_colors() == 1) { for (int j = start; j < end; j++) { @@ -4419,7 +4418,7 @@ BENCHFUN // Histogram MUST be 256 in size; gamma is applied, blackpoint and gain also void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) { -BENCHFUN + BENCHFUN histRedRaw.clear(); histGreenRaw.clear(); histBlueRaw.clear(); @@ -4429,17 +4428,19 @@ BENCHFUN 65535.0f / ri->get_white(3) }; - const bool fourColours = ri->getSensorType() == ST_BAYER && ((mult[1] != mult[3] || cblacksom[1] != cblacksom[3]) || FC(0,0) == 3 || FC(0,1) == 3 || FC(1,0) == 3 || FC(1,1) == 3); + const bool fourColours = ri->getSensorType() == ST_BAYER && ((mult[1] != mult[3] || cblacksom[1] != cblacksom[3]) || FC(0, 0) == 3 || FC(0, 1) == 3 || FC(1, 0) == 3 || FC(1, 1) == 3); LUTu hist[4]; hist[0](65536); hist[0].clear(); + if (ri->get_colors() > 1) { hist[1](65536); hist[1].clear(); hist[2](65536); hist[2].clear(); } + if (fourColours) { hist[3](65536); hist[3].clear(); @@ -4458,16 +4459,19 @@ BENCHFUN LUTu tmphist[4]; tmphist[0](65536); tmphist[0].clear(); + if (ri->get_colors() > 1) { tmphist[1](65536); tmphist[1].clear(); tmphist[2](65536); tmphist[2].clear(); + if (fourColours) { tmphist[3](65536); tmphist[3].clear(); } } + #ifdef _OPENMP #pragma omp for nowait #endif @@ -4514,9 +4518,11 @@ BENCHFUN #endif { hist[0] += tmphist[0]; + if (ri->get_colors() > 1) { hist[1] += tmphist[1]; hist[2] += tmphist[2]; + if (fourColours) { hist[3] += tmphist[3]; } @@ -4528,13 +4534,16 @@ BENCHFUN int idx; idx = CLIP((int)Color::gamma(mult[0] * (i - (cblacksom[0]/*+black_lev[0]*/)))); histRedRaw[idx >> 8] += hist[0][i]; + if (ri->get_colors() > 1) { idx = CLIP((int)Color::gamma(mult[1] * (i - (cblacksom[1]/*+black_lev[1]*/)))); histGreenRaw[idx >> 8] += hist[1][i]; + if (fourColours) { idx = CLIP((int)Color::gamma(mult[3] * (i - (cblacksom[3]/*+black_lev[3]*/)))); histGreenRaw[idx >> 8] += hist[3][i]; } + idx = CLIP((int)Color::gamma(mult[2] * (i - (cblacksom[2]/*+black_lev[2]*/)))); histBlueRaw[idx >> 8] += hist[2][i]; } @@ -4574,6 +4583,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) { BENCHFUN constexpr double clipHigh = 64000.0; + if (ri->get_colors() == 1) { rm = gm = bm = 1; return; @@ -4653,6 +4663,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) #ifdef _OPENMP #pragma omp for schedule(dynamic,16) nowait #endif + for (int i = 32; i < H - 32; i++) { for (int j = 32; j < W - 32; j++) { // each loop read 1 rgb triplet value From e8595890c5bf2dffa1d2cbd6e95c35b502e8fc68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Thu, 12 May 2016 20:21:17 +0200 Subject: [PATCH 10/18] Final cleanups --- rtengine/clutstore.cc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index 2724ed34e..f738c3da9 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -80,21 +80,23 @@ bool loadFile( #ifdef __SSE2__ vfloat2 getClutValues(const AlignedBuffer& clut_image, size_t index) { - const __m128i v_values = _mm_loadu_si128(reinterpret_cast(clut_image.data + index)); + const vint v_values = _mm_loadu_si128(reinterpret_cast(clut_image.data + index)); #ifdef __SSE4_1__ return { _mm_cvtepi32_ps(_mm_cvtepu16_epi32(v_values)), _mm_cvtepi32_ps(_mm_cvtepu16_epi32(_mm_srli_si128(v_values, 8))) }; #else - vint lowval = _mm_shuffle_epi32(v_values, _MM_SHUFFLE(1, 0, 1, 0)); - vint highval = _mm_shuffle_epi32(v_values, _MM_SHUFFLE(3, 2, 3, 2)); - lowval = _mm_shufflelo_epi16(lowval, _MM_SHUFFLE(1, 1, 0, 0)); - highval = _mm_shufflelo_epi16(highval, _MM_SHUFFLE(1, 1, 0, 0)); - lowval = _mm_shufflehi_epi16(lowval, _MM_SHUFFLE(3, 3, 2, 2)); - highval = _mm_shufflehi_epi16(highval, _MM_SHUFFLE(3, 3, 2, 2)); - lowval = vandm(lowval, _mm_set1_epi32(0x0000ffff)); - highval = vandm(highval, _mm_set1_epi32(0x0000ffff)); + const vint v_mask = _mm_set1_epi32(0x0000FFFF); + + vint v_low = _mm_shuffle_epi32(v_values, _MM_SHUFFLE(1, 0, 1, 0)); + vint v_high = _mm_shuffle_epi32(v_values, _MM_SHUFFLE(3, 2, 3, 2)); + v_low = _mm_shufflelo_epi16(v_low, _MM_SHUFFLE(1, 1, 0, 0)); + v_high = _mm_shufflelo_epi16(v_high, _MM_SHUFFLE(1, 1, 0, 0)); + v_low = _mm_shufflehi_epi16(v_low, _MM_SHUFFLE(3, 3, 2, 2)); + v_high = _mm_shufflehi_epi16(v_high, _MM_SHUFFLE(3, 3, 2, 2)); + v_low = vandm(v_low, m_mask); + v_high = vandm(v_high, v_mask); return { _mm_cvtepi32_ps(lowval), From aa2912531644cf66c2565c73776f13de67ef3e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Thu, 12 May 2016 21:44:20 +0200 Subject: [PATCH 11/18] Read-ahead of `getClutValues()` is only one pixel now --- rtengine/clutstore.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index f738c3da9..5fd2cfae3 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -56,7 +56,7 @@ bool loadFile( img_src.convertColorSpace(img_float.get(), icm, curr_wb); } - AlignedBuffer image(fw * fh * 4 + 8); // + 8 because of SSE4_1 version of getClutValues + AlignedBuffer image(fw * fh * 4 + 4); // getClutValues() loads one pixel in advance std::size_t index = 0; From e8d90698cfe2bfb5c5a05ffe4d7b4cf113829c8f Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 14 May 2016 14:26:56 +0200 Subject: [PATCH 12/18] Fix copy/paste bugs --- rtengine/clutstore.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index 5fd2cfae3..e8f1c920e 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -95,12 +95,12 @@ vfloat2 getClutValues(const AlignedBuffer& clut_image, size_t ind v_high = _mm_shufflelo_epi16(v_high, _MM_SHUFFLE(1, 1, 0, 0)); v_low = _mm_shufflehi_epi16(v_low, _MM_SHUFFLE(3, 3, 2, 2)); v_high = _mm_shufflehi_epi16(v_high, _MM_SHUFFLE(3, 3, 2, 2)); - v_low = vandm(v_low, m_mask); + v_low = vandm(v_low, v_mask); v_high = vandm(v_high, v_mask); return { - _mm_cvtepi32_ps(lowval), - _mm_cvtepi32_ps(highval) + _mm_cvtepi32_ps(v_low), + _mm_cvtepi32_ps(v_high) }; #endif } From 80f86c7189c4b88ee51fddbef5874e312aedf648 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 14 May 2016 19:29:26 +0200 Subject: [PATCH 13/18] Histogram of working space does not show 'gray2C' for gray regions, fixes #3283, fixes #3213, kudos to mmmtok for providing the patch --- rtengine/iplab2rgb.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 21e5ca794..79a45c99e 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -202,7 +202,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, } } else { - const auto rgb_xyz = iccStore->workingSpaceMatrix (profile); + const auto xyz_rgb = iccStore->workingSpaceInverseMatrix (profile); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if (multiThread) @@ -227,7 +227,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, float z_ = 65535.0 * Color::f2xyz(fz) * Color::D50z; float y_ = (LL > Color::epskap) ? 65535.0 * fy * fy * fy : 65535.0 * LL / Color::kappa; - Color::xyz2rgb(x_, y_, z_, R, G, B, rgb_xyz); + Color::xyz2rgb(x_, y_, z_, R, G, B, xyz_rgb); image->data[ix++] = (int)Color::gamma2curve[CLIP(R)] >> 8; image->data[ix++] = (int)Color::gamma2curve[CLIP(G)] >> 8; From 89a7ebac166483a6f3deb5bd139a4c5917083558 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 16 May 2016 19:13:35 +0200 Subject: [PATCH 14/18] fix wrong condition in Color::transitred --- rtengine/color.cc | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/rtengine/color.cc b/rtengine/color.cc index dc0710a2f..3684891df 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -1844,21 +1844,13 @@ void Color::transitred (const float HH, float const Chprov1, const float dred, c if(HH >= 0.15f && HH < 1.3f) { if (Chprov1 < dred) { factor = factorskin; - } else if(Chprov1 < (dred + protect_red)) - // factor = (factorsat-factorskin)/protect_red*Chprov1+factorsat-(dred+protect_red)*(factorsat-factorskin)/protect_red; - // optimized formula - { + } else if(Chprov1 < (dred + protect_red)) { factor = ((factorsat - factorskin) * Chprov1 + factorsat * protect_red - (dred + protect_red) * (factorsat - factorskin)) / protect_red; } - } - // then test if chroma is in the extanded range - else if ( HH > (0.15f - deltaHH) || HH < (1.3f + deltaHH) ) { + } else if ( HH > (0.15f - deltaHH) && HH < (1.3f + deltaHH) ) { // test if chroma is in the extended range if (Chprov1 < dred) { factor = factorskinext; // C=dred=55 => real max of skin tones - } else if (Chprov1 < (dred + protect_red)) // transition - // factor = (factorsat-factorskinext)/protect_red*Chprov1+factorsat-(dred+protect_red)*(factorsat-factorskinext)/protect_red; - // optimized formula - { + } else if (Chprov1 < (dred + protect_red)) {// transition factor = ((factorsat - factorskinext) * Chprov1 + factorsat * protect_red - (dred + protect_red) * (factorsat - factorskinext)) / protect_red; } } From 68a77f26f631651c11716d3f609eedc8dea8a0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Tue, 17 May 2016 20:51:14 +0200 Subject: [PATCH 15/18] Fix std::out_of_range exception with empty HaldCLUT basename User jgschaefer [reported an error on pixls.us](https://discuss.pixls.us/t/rt-build-from-git-crash-on-launch-debian-testing-64-bit/1425) which could be traced down to an empty basename for a HaldCLUT. The original implementation did not throw an exception due to the use of `std::string::substr()` instead of `std::string::erase()`, but silently assigned the first working profile to `profile_name`. --- rtengine/clutstore.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index e8f1c920e..f3ef27a79 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -283,11 +283,16 @@ void rtengine::HaldCLUT::splitClutFilename( profile_name = "sRGB"; - for (const auto& working_profile : rtengine::getWorkingProfiles()) { - if (std::search(name.rbegin(), name.rend(), working_profile.rbegin(), working_profile.rend()) == name.rbegin()) { - profile_name = working_profile; - name.erase(name.size() - working_profile.size()); - break; + if (!name.empty()) { + for (const auto& working_profile : rtengine::getWorkingProfiles()) { + if ( + !working_profile.empty() // This isn't strictly needed, but an empty wp name should be skipped anyway + && std::search(name.rbegin(), name.rend(), working_profile.rbegin(), working_profile.rend()) == name.rbegin() + ) { + profile_name = working_profile; + name.erase(name.size() - working_profile.size()); + break; + } } } } From 53f03bd00cf337d0743eb2009094047ca8bb8184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Wed, 18 May 2016 20:57:46 +0200 Subject: [PATCH 16/18] Fix ODR violation When building with LTO, the compiler warns about a violation of the ODR. This commit fixes the two competing places by moving the structs into anonymous namespaces. --- rtengine/jdatasrc.cc | 4 ++++ rtengine/jpeg_memsrc.cc | 3 +++ 2 files changed, 7 insertions(+) diff --git a/rtengine/jdatasrc.cc b/rtengine/jdatasrc.cc index c8567387b..ff509301d 100644 --- a/rtengine/jdatasrc.cc +++ b/rtengine/jdatasrc.cc @@ -32,6 +32,8 @@ /* Expanded data source object for stdio input */ +namespace +{ typedef struct { struct jpeg_source_mgr pub; /* public fields */ @@ -44,6 +46,8 @@ typedef struct { typedef my_source_mgr * my_src_ptr; +} + #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ diff --git a/rtengine/jpeg_memsrc.cc b/rtengine/jpeg_memsrc.cc index 75a0b25bc..ab4ecf7d6 100644 --- a/rtengine/jpeg_memsrc.cc +++ b/rtengine/jpeg_memsrc.cc @@ -26,6 +26,8 @@ /* Expanded data source object for memory input */ +namespace +{ typedef struct { struct jpeg_source_mgr pub; /* public fields */ @@ -36,6 +38,7 @@ typedef struct { typedef my_source_mgr * my_src_ptr; +} /* * Initialize source --- called by jpeg_read_header From c556771843cd7d39ff90144b9ea352c32cbf740d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Wed, 18 May 2016 21:16:27 +0200 Subject: [PATCH 17/18] Prevent narrowing conversion when building for PowerPC --- rtengine/iccstore.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index 66099199c..82f280e54 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -263,7 +263,7 @@ cmsHPROFILE ICCStore::makeStdGammaProfile (cmsHPROFILE iprof) tags[i].sig == 0x6B545243) { // kTRC if (gamma_offset == 0) { gamma_offset = offset; - uint32_t pcurve[] = { htonl(0x63757276), htonl(0), htonl(gamma_size == 12 ? 0 : 1) }; + uint32_t pcurve[] = { htonl(0x63757276), htonl(0), htonl(gamma_size == 12 ? 0U : 1U) }; memcpy(&nd[offset], pcurve, 12); if (gamma_size == 14) { From 7d97d0da9311650331869db594574452524c91d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20P=C3=A9rez?= Date: Thu, 19 May 2016 15:23:37 +0200 Subject: [PATCH 18/18] Use "find_program" to search for git executable CMake's "find_file" can return non-executable files or folders, thus "find_program" must be used to ensure that only executable files are detected. Fixes issue #3290 --- AboutThisBuild.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AboutThisBuild.cmake b/AboutThisBuild.cmake index 68dea478d..2163ed0cb 100644 --- a/AboutThisBuild.cmake +++ b/AboutThisBuild.cmake @@ -5,13 +5,13 @@ find_file(REL_INFO_FILE ReleaseInfo.cmake PATHS "${PROJECT_SOURCE_DIR}" NO_DEFAU if (REL_INFO_FILE STREQUAL REL_INFO_FILE-NOTFOUND) # we look for the git command in this paths by order of preference if (WIN32) - find_file(GIT_CMD git.exe HINTS ENV Path PATH_SUFFIXES ../) + find_program(GIT_CMD git.exe HINTS ENV Path PATH_SUFFIXES ../) elseif (APPLE) - find_file(GIT_CMD git PATHS "/opt/local/bin" "/usr/local/bin" "/usr/bin") - find_file(GIT_CMD git) + find_program(GIT_CMD git PATHS "/opt/local/bin" "/usr/local/bin" "/usr/bin") + find_program(GIT_CMD git) set (SHELL "/bin/bash") else (WIN32) # Linux - find_file(GIT_CMD git) + find_program(GIT_CMD git) set (SHELL "/bin/bash") endif (WIN32)