From 13e26d3979f8e37d4b0bb55ae794cc67a950a18a Mon Sep 17 00:00:00 2001 From: jdc Date: Thu, 29 Jan 2015 07:07:00 +0100 Subject: [PATCH] Wavelet Levels - My kingdom for more wavelets - issue2594 --- rtdata/languages/default | 122 ++- rtengine/CMakeLists.txt | 2 +- rtengine/color.h | 75 +- rtengine/curves.cc | 96 ++- rtengine/curves.h | 52 ++ rtengine/dcrop.cc | 61 ++ rtengine/dirpyr_equalizer.cc | 53 +- rtengine/improccoordinator.cc | 26 +- rtengine/improccoordinator.h | 6 + rtengine/improcfun.h | 27 +- rtengine/ipwavelet.cc | 1258 ++++++++++++++++++++++++++++++ rtengine/procevents.h | 35 + rtengine/procparams.cc | 354 ++++++++- rtengine/procparams.h | 63 +- rtengine/refreshmap.cc | 37 +- rtengine/rtengine.h | 8 + rtengine/simpleprocess.cc | 18 +- rtgui/CMakeLists.txt | 2 +- rtgui/addsetids.h | 17 +- rtgui/batchtoolpanelcoord.cc | 19 +- rtgui/dirpyrequalizer.cc | 39 +- rtgui/dirpyrequalizer.h | 2 +- rtgui/exportpanel.cc | 10 +- rtgui/exportpanel.h | 4 +- rtgui/filecatalog.cc | 25 +- rtgui/options.cc | 35 +- rtgui/options.h | 4 +- rtgui/paramsedited.cc | 120 ++- rtgui/paramsedited.h | 45 +- rtgui/partialpastedlg.cc | 5 + rtgui/partialpastedlg.h | 3 +- rtgui/preferences.cc | 18 + rtgui/sharpening.cc | 1 - rtgui/thresholdadjuster.cc | 8 +- rtgui/thresholdadjuster.h | 1 + rtgui/toolpanelcoord.cc | 3 + rtgui/toolpanelcoord.h | 4 +- rtgui/wavelet.cc | 1347 +++++++++++++++++++++++++++++++++ rtgui/wavelet.h | 139 ++++ 39 files changed, 4008 insertions(+), 136 deletions(-) create mode 100644 rtengine/ipwavelet.cc create mode 100644 rtgui/wavelet.cc create mode 100644 rtgui/wavelet.h diff --git a/rtdata/languages/default b/rtdata/languages/default index b94d6ad89..e62a16f22 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -62,6 +62,7 @@ EXPORT_BYPASS_ALL;Select / Unselect All EXPORT_BYPASS_DEFRINGE;Bypass Defringe EXPORT_BYPASS_DIRPYRDENOISE;Bypass Noise Reduction EXPORT_BYPASS_DIRPYREQUALIZER;Bypass Contrast by Detail Levels +EXPORT_BYPASS_EQUALIZER;Bypass Wavelet Levels EXPORT_BYPASS_RAW_CA;Bypass [raw] Chromatic Aberration Correction EXPORT_BYPASS_RAW_CCSTEPS;Bypass [raw] False Color Suppression EXPORT_BYPASS_RAW_DCB_ENHANCE;Bypass [raw] DCB Enhancement Steps @@ -519,6 +520,40 @@ HISTORY_MSG_300;- HISTORY_MSG_301;NR - Luma control HISTORY_MSG_302;NR - Chroma method HISTORY_MSG_303;NR - Chroma method +HISTORY_MSG_304;Wavelet level +HISTORY_MSG_305;Wavelet level +HISTORY_MSG_306;Wavelet N° level +HISTORY_MSG_307;Wavelet Ch level +HISTORY_MSG_308;Wavelet direction +HISTORY_MSG_309;Wavelet tiles +HISTORY_MSG_310;Wavelet Hue-tones sky +HISTORY_MSG_311;Wavelet threshold +HISTORY_MSG_312;Wavelet Shadow Threshold +HISTORY_MSG_313;Wavelet Pastel Saturated +HISTORY_MSG_314;Wavelet artifacts blue sky +HISTORY_MSG_315;Wavelet Contrast uniformity +HISTORY_MSG_316;Wavelet Skin tones +HISTORY_MSG_317;Wavelet Skin hue +HISTORY_MSG_318;Wavelet highlight levels +HISTORY_MSG_319;Wavelet highlight range +HISTORY_MSG_320;Wavelet shadow range +HISTORY_MSG_321;Wavelet shadow levels +HISTORY_MSG_322;Wavelet avoid color shift +HISTORY_MSG_323;Wavelet Chroma level +HISTORY_MSG_324;Wavelet Chroma pastel +HISTORY_MSG_325;Wavelet Chroma saturated +HISTORY_MSG_326;Wavelet Chroma method +HISTORY_MSG_327;Wavelet Contrast method +HISTORY_MSG_328;Wavelet Chroma link +HISTORY_MSG_329;Wavelet Opacity RG +HISTORY_MSG_330;Wavelet Opacity BY +HISTORY_MSG_331;Wavelet Extra +HISTORY_MSG_332;Wavelet Tiles Method +HISTORY_MSG_333;Wavelet Shadow contrast +HISTORY_MSG_334;Wavelet Chroma +HISTORY_MSG_335;Wavelet Highlight contrast +HISTORY_MSG_336;Wavelet Highlight threshold +HISTORY_MSG_337;Wavelet Hue range HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOTS;Snapshots @@ -670,6 +705,7 @@ PARTIALPASTE_EPD;Tone mapping PARTIALPASTE_EVERYTHING;Everything PARTIALPASTE_EXIFCHANGES;Exif PARTIALPASTE_EXPOSURE;Exposure +PARTIALPASTE_EQUALIZER;Wavelet Equalizer PARTIALPASTE_FILMSIMULATION;Film Simulation PARTIALPASTE_FLATFIELDAUTOSELECT;Flat-field auto-selection PARTIALPASTE_FLATFIELDBLURRADIUS;Flat-field blur radius @@ -859,8 +895,8 @@ PREFERENCES_PROFILESAVECACHE;Save processing profile to the cache PREFERENCES_PROFILESAVEINPUT;Save processing profile next to the input file PREFERENCES_PROPERTY;Property PREFERENCES_PSPATH;Adobe Photoshop installation directory -PREFERENCES_RGBDTL_LABEL;Max number of threads -PREFERENCES_RGBDTL_TOOLTIP;Noise Reduction requires a baseline of about 128MB RAM for a 10MPix image or 512MB for a 40MPix image, and additionally 128MB RAM per thread. The more threads run in parallel, the faster the computation. Leave the setting at "0" to automatically use as many threads as possible. +PREFERENCES_RGBDTL_LABEL;Max number of threads Denoise and Wavelet (divide by 2) +PREFERENCES_RGBDTL_TOOLTIP;Noise Reduction and Wavelet requires a baseline of about 128MB RAM for a 10MPix image or 512MB for a 40MPix image, and additionally 128MB RAM per thread. The more threads run in parallel, the faster the computation. Leave the setting at "0" to automatically use as many threads as possible. PREFERENCES_SELECTFONT;Select font PREFERENCES_SELECTLANG;Select language PREFERENCES_SELECTTHEME;Select theme @@ -1237,7 +1273,89 @@ TP_DIRPYRDENOISE_SHALBI;High TP_DIRPYRDENOISE_SHAL;Standard TP_DIRPYRDENOISE_SLI;Slider TP_DIRPYRDENOISE_SOFT;3x3 +TP_WAVELET_RESID;Residual image +TP_WAVELET_RESCON;Shadows Contrast +TP_WAVELET_RESCONH;Highlights Contrast +TP_WAVELET_RESCHRO;Chromaticity +TP_WAVELET_THR;Threshold shadows +TP_WAVELET_THRH;Threshold highlights +TP_WAVELET_HUESKY;Hue Range (sky) +TP_WAVELET_HUESKY_TOOLTIP;This pyramid is for the upper part, so far as the algorithm at its maximum efficiency.\nTo the lower part, the transition zones.\nIf you need to move the area significantly to the left or right - or if there are artifacts: the white balance is incorrect\nYou can slightly reduce the zone to prevent the rest of the image is affected. +TP_WAVELET_SKY;Hue-tones (sky) targetting/protection +TP_WAVELET_SKY_TOOLTIP;Increase/reduce chrominance in/out hue range\nAvoid artifacts in blue sky - due to micro-contrast, micro-chroma,... +TP_WAVELET_LEVF;Contrast +TP_WAVELET_LEVCH;Chromaticity +TP_WAVELET_TON;Toning +TP_WAVELET_COLORT;Opacity Red-Green Levels +TP_WAVELET_OPACITY;Opacity Blue-Yellow Levels +TP_WAVELET_CONTR;Gamut - controls +TP_WAVELET_UTIL;Utilities +TP_WAVELET_UNIF;Contrast Uniformity +TP_WAVELET_UNIF_TOOLTIP;Modulation of the effect based on local contrast\nTake into account local contrast\nMore it is present, more its increasing is reduct regardless to the slider +TP_WAVELET_DISP;Display Wavelet levels +TP_WAVELET_DISPLAY;Show Levels and Utilities TP_DIRPYRDENOISE_TILELABEL;Tile size=%1, Center: Tx=%2 Ty=%3 +TP_WAVELET_CONTRAST_MINUS;Contrast - +TP_WAVELET_NEUTRAL;Neutral +TP_WAVELET_CONTRAST_PLUS;Contrast + +TP_WAVELET_FINEST;Finest +TP_WAVELET_LARGEST;Coarsest +TP_WAVELET_LABEL;Wavelet levels +TP_WAVELET_ONE;one level +TP_WAVELET_INF;below or equal the level +TP_WAVELET_SUP;above the level + residual +TP_WAVELET_SUPE;Extra +TP_WAVELET_ALL;all levels-directions +TP_WAVELET_CONTRAST;Contrast levels +TP_WAVELET_0;level 0 +TP_WAVELET_1;level 1 +TP_WAVELET_2;level 2 +TP_WAVELET_3;level 3 +TP_WAVELET_4;level 4 +TP_WAVELET_5;level 5 +TP_WAVELET_6;level 6 +TP_WAVELET_7;level 7 +TP_WAVELET_8;level 8 +TP_WAVELET_LEVLABEL;Preview maximum possible levels=%1 +TP_WAVELET_AVOID;Avoid color shift +TP_WAVELET_DONE;Direction: Vertical +TP_WAVELET_DTWO;Direction: Horizontal +TP_WAVELET_DTHR;Direction: Diagonal +TP_WAVELET_DALL;All directions +TP_WAVELET_MEDI;Reduce artifacts in blue sky +TP_WAVELET_THRES;Max level +TP_WAVELET_THRES_TOOLTIP;Can act on the number of active levels. Levels higher values are not taken into account, regardless of the position of the slider. +TP_WAVELET_TILES;Tiles size (* 128) +TP_WAVELET_TILES_TOOLTIP;If you select full image process will be performed - for a 16M image and 10 levels this option needs memory 2.G°\nfor a 24M image and 10 levels this option needs memory 2.5G°\nfor a 35M image and 10 levels this option needs memory 3.3G°\nOtherwise select tiles or if memory is too low +TP_WAVELET_TILESFULL;Full image +TP_WAVELET_TILESBIG;Big Tiles +TP_WAVELET_TILESLIT;Little Tiles +TP_WAVELET_CHRO;Saturated - Pastel +TP_WAVELET_CHR;Chroma link +TP_WAVELET_CHR_TOOLTIP;Adjust chroma in function of:\na-levels contrasts\nb-Chroma link slider strength +TP_WAVELET_CHRO_TOOLTIP;Limit between pastel and saturated\n 1-x level saturated \n x-9 level pastel +TP_WAVELET_THRESHOLD;Highlight Levels numbers used (finest to coarsest - master) +TP_WAVELET_THRESHOLD_TOOLTIP;If you change this value, only level beyond will be treated with highlight luminance levels\nOthers level will be full treated +TP_WAVELET_THRESHOLD2_TOOLTIP;If you change this value, only level between 9 and 9 minus value, will be treated with shadow luminance levels\nOthers level will be full treated\nMax level shadow is limited by value of highlight level (9-highlight level) +TP_WAVELET_HIGHSHA;Highlight Shadows +TP_WAVELET_HIGHLIGHT;Highlight Luminance Range (0..100) +TP_WAVELET_THRESHOLD2;Shadows Levels numbers used(coarsest to finest) +TP_WAVELET_LOWLIGHT;Shadow Luminance Range (0..100) +TP_WAVELET_PASTEL;Pastel chromacity +TP_WAVELET_SAT;Saturated chromacity +TP_WAVELET_CH1;All chroma +TP_WAVELET_CH2;Pastel - Saturated +TP_WAVELET_CH3;Link contrast levels +TP_WAVELET_HS1;All luminance +TP_WAVELET_HS2;Highlight - Shadows +TP_WAVELET_MIN;min +TP_WAVELET_MAX;max +TP_WAVELET_CLVCURVE;Chrominance - Levels +TP_WAVELET_CURVEEDITOR_CLV_TOOLTIP;Give chroma in function of levels (absciss)\nLevels are discrets values +TP_WAVELET_HUESKIN;Hue Range (skin) +TP_WAVELET_HUESKIN_TOOLTIP;This pyramid is for the upper part, so far as the algorithm at its maximum efficiency.\nTo the lower part, the transition zones.\nIf you need to move the area significantly to the left or right - or if there are artifacts: the white balance is incorrect\nYou can slightly reduce the zone to prevent the rest of the image is affected. +TP_WAVELET_SKIN;Hue-tones (skin) targetting/protection +TP_WAVELET_SKIN_TOOLTIP;At -100 skin-tones are targetted.\nAt 0 all tones are treated equally.\nAt +100 skin-tones are protected while all other tones are affected. TP_DIRPYREQUALIZER_ALGO;Skin Color Range TP_DIRPYREQUALIZER_ALGO_TOOLTIP;Fine: closer to the colors of the skin, minimizing the action on other colors\nLarge: avoid more artifacts. TP_DIRPYREQUALIZER_GAMUT;Reduce artifacts diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 72a238273..6eff1db5a 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -16,7 +16,7 @@ set (RTENGINESOURCEFILES safegtk.cc colortemp.cc curves.cc flatcurves.cc diagona iplab2rgb.cc ipsharpen.cc iptransform.cc ipresize.cc ipvibrance.cc imagedimensions.cc jpeg_memsrc.cc jdatasrc.cc iimage.cc EdgePreservingDecomposition.cc cplx_wavelet_dec.cc FTblockDN.cc - PF_correct_RT.cc previewimage.cc + PF_correct_RT.cc previewimage.cc ipwavelet.cc dirpyr_equalizer.cc calc_distort.cc lcp.cc dcp.cc cJSON.c camconst.cc diff --git a/rtengine/color.h b/rtengine/color.h index 8c12467b5..5a41f7e29 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -892,7 +892,7 @@ public: static inline double gamman (double x, double gamma) { //standard gamma without slope... return (x =exp(log(x)/gamma)); } - + /** * @brief Very basic gamma * @param x red, green or blue channel's value [0 ; 1] @@ -1112,7 +1112,80 @@ public: scale *= modula; } } + + static inline void SkinSatCbdl2 (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r, float b_r, int basc) { + + static const float C9=8.f, C8=15.f, C7=12.f, C4=7.f, C3=5.f, C2=5.f, C1=5.f; + static const float H9=0.05f, H8=0.25f, H7=0.1f, H4=0.02f, H3=0.02f, H2=0.1f, H1=0.1f, H10=-0.2f,H11=-0.2f; + + // "real" skin color : take into account a slightly usage of contrast and saturation in RT if option "skin" = 1, uses imolicit factor 1.0 + // wide area skin color, useful if not accurate colorimetry or if the user has changed hue and saturation, uses explicit facor 0.6 + // wide area for transition, uses explicit factor 0.4 + if((b_l > -0.3f && b_r < 2.f) || basc==0) { //range maxi skin + if (lum >= 85.0f) { + if((hue > (t_l+0.53f-H9) && hue < (t_r+H9)) && (chrom > 8.0f && chrom < (14.0f+C9))) scale = (100.f-skinprot)/100.1f; + else if (lum >= 92.0f) { + if((hue > t_l+0.4f && hue < t_r) && (chrom > 7.0f && chrom < (15.0f))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l && hue < t_r) && (chrom > 7.0f && chrom < (18.0f))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > t_l+0.4f && hue < t_r-0.3f) && (chrom > 7.0f && chrom < (26.0f+C9))) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > b_l+0.05f && hue < t_r) && (chrom > 7.0f && chrom < (35.0f+C9))) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 70.0f) { + if((hue > t_l+0.15f && hue < (t_r-0.2f+H8)) && (chrom > 8.0f && chrom < (35.0f+C8))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 52.0f) { + if((hue > t_l && hue < (t_r+H7)) && (chrom > 11.0f && chrom < (35.0f+C7))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 35.0f) { + if((hue > t_l && hue < (t_r+H4)) && (chrom > 13.0f && chrom < (37.0f+C4))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 20.0f) { + if((hue > t_l && hue < (t_r+H3)) && (chrom > 7.0f && chrom <(35.0f+C3) )) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (48.0f+C9) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f + H11) && hue < t_r) && (chrom > 7.0f && chrom < (55.0f+C9) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if (lum >= 10.0f) { + if((hue > (t_l-0.25f + H10) && hue < (t_r-0.3f +H2)) && (chrom > 8.0f && chrom < (23.0f+C2))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + } + else if ((hue > (t_l -0.2f + H10) && hue < (t_r-0.3f+H1)) && (chrom > 8.0f && chrom < (23.0f+C1))) scale = (100.f-skinprot)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.2f) && (chrom > 7.0f && chrom < (35.0f+C1) )) scale = (100.f-skinprot*0.6f)/100.1f; + else if ((hue > (b_l+0.07f+H11) && hue < t_r-0.1f) && (chrom > 7.0f && chrom < (45.0f+C1) )) scale = (100.f-skinprot*0.4f)/100.1f; + + //extended zone for hair, beard and if user adjust high value for skinprot + if(skinprot > 85.f && chrom < 20.f && neg) { + float modula = -0.0666f * skinprot + 6.66f; + scale *= modula; + } + } + //end hue skin algo + else if (basc==1) {//not hue skin linear transition or mod chroma curve + if(hue >= t_l && hue <= t_r) scale = (100.f-skinprot)/100.1f; + else if(hue > b_l && hue < t_l) { + float sc=(100.f-skinprot)/100.1f; + float aa=(1.f-sc)/(b_l-t_l); + float bb=1.f-aa*b_l; + scale=aa*hue + bb; + } + else if(hue > t_r && hue < b_r) { + float sc=(100.f-skinprot)/100.1f; + float aa=(sc-1.f)/(t_r-b_r); + float bb=1.f-aa*b_r; + scale=aa*hue + bb; + } + } + } + + static inline void SkinSatCbdlCam (float lum, float hue, float chrom, float skinprot, float &scale, bool neg, float b_l, float t_l, float t_r) { static const float C9=8.f, C8=15.f, C7=12.f, C4=7.f, C3=5.f, C2=5.f, C1=5.f; diff --git a/rtengine/curves.cc b/rtengine/curves.cc index fb5d4e534..2d518c29b 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -1166,6 +1166,93 @@ void OpacityCurve::Set(const std::vector &curvePoints, bool &opautili) { } } +WavCurve::WavCurve() : sum(0.f) {}; + +void WavCurve::Reset() { + lutWavCurve.reset(); + sum = 0.f; +} + +void WavCurve::Set(const Curve &pCurve) { + if (pCurve.isIdentity()) { + Reset(); // raise this value if the quality suffers from this number of samples + return; + } + lutWavCurve(501); // raise this value if the quality suffers from this number of samples + sum=0.f; + for (int i=0; i<501; i++) { + lutWavCurve[i] = pCurve.getVal(double(i)/500.); + if(lutWavCurve[i] < 0.02f) + lutWavCurve[i] = 0.02f;//avoid 0.f for wavelet : under 0.01f quasi no action for each value + sum += lutWavCurve[i]; + } + //lutWavCurve.dump("wav"); +} +void WavCurve::Set(const std::vector &curvePoints) { + + if (!curvePoints.empty() && curvePoints[0]>FCT_Linear && curvePoints[0] &curvePoints) { + if (!curvePoints.empty() && curvePoints[0]>FCT_Linear && curvePoints[0] &curvePoints) { + if (!curvePoints.empty() && curvePoints[0]>FCT_Linear && curvePoints[0]isIdentity()) { - Color::hsv2rgb(0.5f, satur, lumin, r, g, b); + Color::hsv2rgb(0.5f, satur, lumin, r, g, b); Color::rgbxyz(r, g, b, xx, yy, zz, xyz_rgb); for (int i=0; i<=500; ++i) { @@ -1245,6 +1332,7 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], low=nextX; lr1=(0.5f+low)/2.f;//optimize use of gamut in low light..one can optimize more using directly low ? //lr1=low; + for (int i=0; i<=upperBound; ++i) { double x = double(i)/double(upperBound); @@ -1261,14 +1349,14 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], } if (!ptNum) { - Color::hsv2rgb(float(prevY), satur, lr1, r, g, b); + Color::hsv2rgb(float(prevY), satur, lr1, r, g, b); Color::rgbxyz(r, g, b, xx, yy, zz, xyz_rgb); lut1[i] = xx; lut2[i] = yy; lut3[i] = zz; } else if (ptNum >= nPoints) { - Color::hsv2rgb(float(nextY), satur, lr2, r, g, b); + Color::hsv2rgb(float(nextY), satur, lr2, r, g, b); Color::rgbxyz(r, g, b, xx, yy, zz, xyz_rgb); lut1[i] = xx; lut2[i] = yy; @@ -1278,7 +1366,7 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], double currY = pCurve->getVal(x) - prevY; if (dY > 0.000001 || dY < -0.000001) { float r1, g1, b1, r2, g2, b2, ro, go, bo; - Color::hsv2rgb(float(prevY), satur, lr1, r1, g1, b1); + Color::hsv2rgb(float(prevY), satur, lr1, r1, g1, b1); Color::hsv2rgb(float(nextY), satur, lr2, r2, g2, b2); bool chr = false; bool lum = true; diff --git a/rtengine/curves.h b/rtengine/curves.h index 831af5003..0a7a9e606 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -372,6 +372,57 @@ class OpacityCurve { operator bool (void) const { return lutOpacityCurve; } }; + +class WavCurve { + private: + LUTf lutWavCurve; // 0xffff range + void Set(const Curve &pCurve); + + public: + float sum; + + virtual ~WavCurve() {}; + WavCurve(); + void Reset(); + void Set(const std::vector &curvePoints); + float getSum() const {return sum;} + + float operator[](float index) const { return lutWavCurve[index]; } + operator bool (void) const { return lutWavCurve; } +}; + +class WavOpacityCurveRG { + private: + LUTf lutOpacityCurveRG; // 0xffff range + void Set(const Curve &pCurve); + public: + virtual ~WavOpacityCurveRG() {}; + WavOpacityCurveRG(); + + void Reset(); + // void Set(const std::vector &curvePoints, bool &opautili); + void Set(const std::vector &curvePoints); + float operator[](float index) const { return lutOpacityCurveRG[index]; } + + operator bool (void) const { return lutOpacityCurveRG; } +}; +class WavOpacityCurveBY { + private: + LUTf lutOpacityCurveBY; // 0xffff range + void Set(const Curve &pCurve); + + public: + virtual ~WavOpacityCurveBY() {}; + WavOpacityCurveBY(); + + void Reset(); + void Set(const Curve *pCurve); + void Set(const std::vector &curvePoints); + float operator[](float index) const { return lutOpacityCurveBY[index]; } + + operator bool (void) const { return lutOpacityCurveBY; } +}; + class NoiseCurve { private: LUTf lutNoiseCurve; // 0xffff range @@ -383,6 +434,7 @@ class NoiseCurve { NoiseCurve(); void Reset(); void Set(const std::vector &curvePoints); + float getSum() const {return sum;} float operator[](float index) const { return lutNoiseCurve[index]; } operator bool (void) const { return lutNoiseCurve; } diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 6c4beaa4d..39e3f1759 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -657,11 +657,72 @@ void Crop::update (int todo) { } } // if (skip==1) { + WaveletParams WaveParams = params.wavelet; if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) { parent->ipf.dirpyrequalizer (labnCrop, skip); // parent->ipf.Lanczoslab (labnCrop,labnCrop , 1.f/skip); } + TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.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]}}; + TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); + double wip[3][3] = { + {wiprof[0][0],wiprof[0][1],wiprof[0][2]}, + {wiprof[1][0],wiprof[1][1],wiprof[1][2]}, + {wiprof[2][0],wiprof[2][1],wiprof[2][2]} + }; + + + + + int kall=0; + int minwin=min(labnCrop->W,labnCrop->H); + int maxlevelcrop=10; + // if(cp.mul[9]!=0)maxlevelcrop=10; + // adap maximum level wavelet to size of crop + if(minwin*skip < 1024) maxlevelcrop = 9;//sampling wavelet 512 + if(minwin*skip < 512) maxlevelcrop = 8;//sampling wavelet 256 + if(minwin*skip < 256) maxlevelcrop = 7;//sampling 128 + if(minwin*skip < 128) maxlevelcrop = 6; + if(minwin < 64) maxlevelcrop = 5; + int tilesize; + int overlap; + tilesize = 1024; + overlap = 128; + tilesize=128*params.wavelet.tiles; + //overlap=(int) tilesize*params->wavelet.overl; + overlap=(int) tilesize*0.125f; + // printf("overl=%d\n",overlap); + int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; + + parent->ipf.Tile_calc (tilesize, overlap, kall, labnCrop->W, labnCrop->H, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip); + //now we have tile dimensions, overlaps + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + int minsizetile=min(tilewidth, tileheight); + int maxlev2=10; + if(minsizetile < 1024 && maxlevelcrop==10) maxlev2 = 9; + if(minsizetile < 512) maxlev2 = 8; + if(minsizetile < 256) maxlev2 = 7; + if(minsizetile < 128) maxlev2 = 6; + int maxL=min(maxlev2,maxlevelcrop); + + if(parent->awavListener) parent->awavListener->wavChanged(float(maxL)); + + if((params.wavelet.enabled)) { + WavCurve wavCLVCurve; + WavOpacityCurveRG waOpacityCurveRG; + WavOpacityCurveBY waOpacityCurveBY; + + params.wavelet.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY); + + parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, skip); + } + + // } + // } if(params.colorappearance.enabled){ float fnum = parent->imgsrc->getMetaData()->getFNumber (); // F number diff --git a/rtengine/dirpyr_equalizer.cc b/rtengine/dirpyr_equalizer.cc index 006519e31..ccd92b1ce 100644 --- a/rtengine/dirpyr_equalizer.cc +++ b/rtengine/dirpyr_equalizer.cc @@ -40,11 +40,11 @@ namespace rtengine { - static const int maxlevel = 5; + static const int maxlevel = 6; static const float noise = 2000; //sequence of scales - static const int scales[5] = {1,2,4,8,16}; + static const int scales[6] = {1,2,4,8,16,32}; extern const Settings* settings; //sequence of scales @@ -62,7 +62,7 @@ SSEFUNCTION void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, if(atten0 < 0.f) atten0=0.f; if((t_r-t_l)<0.55f) - t_l = t_r + 0.55f;//avoid too small range + t_l = t_r + 0.55f;//avoid too small range while (lastlevel>0 && fabs(mult[lastlevel-1]-1)<0.001) { @@ -72,16 +72,16 @@ SSEFUNCTION void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, if (lastlevel==0) return; int level; - float multi[5]={1.f,1.f,1.f,1.f,1.f}; - float scalefl[5]; + float multi[6]={1.f,1.f,1.f,1.f,1.f,1.f}; + float scalefl[6]; - for(int lv=0;lv<5;lv++) { + for(int lv=0;lv<6;lv++) { scalefl[lv]= ((float) scales[lv])/(float) scaleprev; if(lv>=1) {if(scalefl[lv] < 1.f) multi[lv] = (atten123*((float) mult[lv] -1.f)/100.f)+1.f; else multi[lv]=(float) mult[lv];}//modulate action if zoom < 100% else {if(scalefl[lv] < 1.f) multi[lv] = (atten0*((float) mult[lv] -1.f)/100.f)+1.f; else multi[lv]=(float) mult[lv];}//modulate action if zoom < 100% } - if(settings->verbose) printf("CbDL mult0=%f 1=%f 2=%f 3=%f 4=%f\n",multi[0],multi[1],multi[2],multi[3],multi[4]); + if(settings->verbose) printf("CbDL mult0=%f 1=%f 2=%f 3=%f 4=%f 5=%f\n",multi[0],multi[1],multi[2],multi[3],multi[4],multi[5]); multi_array2D dirpyrlo (srcwidth, srcheight); @@ -210,7 +210,7 @@ SSEFUNCTION void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, if(atten0 < 0.f) atten0=0.f; if((t_r-t_l)<0.55f) - t_l = t_r + 0.55f;//avoid too small range + t_l = t_r + 0.55f;//avoid too small range while (fabs(mult[lastlevel-1]-1)<0.001 && lastlevel>0) { lastlevel--; @@ -220,10 +220,10 @@ SSEFUNCTION void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, int level; - float multi[5]={1.f,1.f,1.f,1.f,1.f}; - float scalefl[5]; + float multi[6]={1.f,1.f,1.f,1.f,1.f,1.f}; + float scalefl[6]; - for(int lv=0;lv<5;lv++) { + for(int lv=0;lv<6;lv++) { scalefl[lv]= ((float) scales[lv])/(float) scaleprev; // if(scalefl[lv] < 1.f) multi[lv] = 1.f; else multi[lv]=(float) mult[lv]; if (lv>=1) {if(scalefl[lv] < 1.f) multi[lv] = (atten123*((float) mult[lv] -1.f)/100.f)+1.f; else multi[lv]=(float) mult[lv];} @@ -231,7 +231,7 @@ SSEFUNCTION void ImProcFunctions :: dirpyr_equalizer(float ** src, float ** dst, } - if(settings->verbose) printf("CAM CbDL mult0=%f 1=%f 2=%f 3=%f 4=%f\n",multi[0],multi[1],multi[2],multi[3],multi[4]); + if(settings->verbose) printf("CAM CbDL mult0=%f 1=%f 2=%f 3=%f 4=%f 5=%f\n",multi[0],multi[1],multi[2],multi[3],multi[4],multi[5]); @@ -303,6 +303,7 @@ SSEFUNCTION void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** da if(level > 1) { //generate domain kernel int domker[5][5] = {{1,1,1,1,1},{1,2,2,2,1},{1,2,2,2,1},{1,2,2,2,1},{1,1,1,1,1}}; + // int domker[5][5] = {{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1},{1,1,1,1,1}}; static const int halfwin=2; const int scalewin = halfwin*scale; #ifdef _OPENMP @@ -315,6 +316,7 @@ SSEFUNCTION void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** da // multiplied each value of domkerv by 1000 to avoid multiplication by 1000 inside the loop float domkerv[5][5][4] __attribute__ ((aligned (16))) = {{{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000}},{{1000,1000,1000,1000},{2000,2000,2000,2000},{2000,2000,2000,2000},{2000,2000,2000,2000},{1000,1000,1000,1000}},{{1000,1000,1000,1000},{2000,2000,2000,2000},{2000,2000,2000,2000},{2000,2000,2000,2000},{1000,1000,1000,1000}},{{1000,1000,1000,1000},{2000,2000,2000,2000},{2000,2000,2000,2000},{2000,2000,2000,2000},{1000,1000,1000,1000}},{{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000},{1000,1000,1000,1000}}}; #endif // __SSE2__ + int j; #ifdef _OPENMP #pragma omp for //schedule (dynamic,8) @@ -325,8 +327,10 @@ SSEFUNCTION void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** da float val=0.f; float norm=0.f; + for(int inbr=max(0,i-scalewin); inbr<=min(height-1,i+scalewin); inbr+=scale) { for (int jnbr=max(0,j-scalewin); jnbr<=j+scalewin; jnbr+=scale) { + //printf("i=%d ",(inbr-i)/scale+halfwin); dirwt = DIRWT(inbr, jnbr, i, j); val += dirwt*data_fine[inbr][jnbr]; norm += dirwt; @@ -366,6 +370,7 @@ SSEFUNCTION void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** da data_coarse[i][j]=val/norm;//low pass filter } #else + for(; j < width-scalewin; j++) { float val=0.f; @@ -459,6 +464,7 @@ SSEFUNCTION void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** da data_coarse[i][j]=val/norm;//low pass filter } #else + for(; j < width-scale; j++) { float val=0.f; @@ -505,19 +511,25 @@ SSEFUNCTION void ImProcFunctions::dirpyr_channel(float ** data_fine, float ** da offs = 0.f; else offs = -1.f; + float multbis[6]; + + multbis[level]=mult[level];//multbis to reduce artifacts for high values mult + if(level==4 && mult[level]> 1.f) multbis[level]=1.f+0.65f*(mult[level]-1.f); + if(level==5 && mult[level]> 1.f) multbis[level]=1.f+0.45f*(mult[level]-1.f); LUTf irangefn (0x20000); { const float noisehi = 1.33f*noise*dirpyrThreshold/expf(level*log(3.0)), noiselo = 0.66f*noise*dirpyrThreshold/expf(level*log(3.0)); //printf("level=%i multlev=%f noisehi=%f noiselo=%f skinprot=%f\n",level,mult[level], noisehi, noiselo, skinprot); + for (int i=0; i<0x20000; i++) { - if (abs(i-0x10000)>noisehi || mult[level]<1.0) { - irangefn[i] = mult[level] + offs; + if (abs(i-0x10000)>noisehi || multbis[level]<1.0) { + irangefn[i] = multbis[level] + offs; } else { if (abs(i-0x10000) 1.f) multbis[level]=1.f+0.65f*(mult[level]-1.f); + if(level==5 && mult[level]> 1.f) multbis[level]=1.f+0.45f*(mult[level]-1.f); LUTf irangefn (0x20000); { const float noisehi = 1.33f*noise*dirpyrThreshold/expf(level*log(3.0)), noiselo = 0.66f*noise*dirpyrThreshold/expf(level*log(3.0)); //printf("level=%i multlev=%f noisehi=%f noiselo=%f skinprot=%f\n",level,mult[level], noisehi, noiselo, skinprot); for (int i=0; i<0x20000; i++) { - if (abs(i-0x10000)>noisehi || mult[level]<1.0) { - irangefn[i] = mult[level] + offs; + if (abs(i-0x10000)>noisehi || multbis[level]<1.0) { + irangefn[i] = multbis[level] + offs; } else { if (abs(i-0x10000)autocielab) || (!params.colorappearance.enabled)){ - progress ("Pyramid equalizer...",100*readyphase/numofphases); + progress ("Pyramid wavelet...",100*readyphase/numofphases); ipf.dirpyrequalizer (nprevl, scale); - //ipf.Lanczoslab (nprevl, nprevl, 1.f/scale); + //ipf.Lanczoslab (ip_wavelet(LabImage * lab, LabImage * dst, const procparams::EqualizerParams & eqparams), nprevl, 1.f/scale); readyphase++; } //} + TMatrix wprofa = iccStore->workingSpaceMatrix (params.icm.working); + double wpa[3][3] = { + {wprofa[0][0],wprofa[0][1],wprofa[0][2]}, + {wprofa[1][0],wprofa[1][1],wprofa[1][2]}, + {wprofa[2][0],wprofa[2][1],wprofa[2][2]}}; + TMatrix wiprofa = iccStore->workingSpaceInverseMatrix (params.icm.working); + double wipa[3][3] = { + {wiprofa[0][0],wiprofa[0][1],wiprofa[0][2]}, + {wiprofa[1][0],wiprofa[1][1],wiprofa[1][2]}, + {wiprofa[2][0],wiprofa[2][1],wiprofa[2][2]} + }; + + if((params.wavelet.enabled)) { + WaveletParams WaveParams = params.wavelet; + WaveParams.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY); + + int kall=0; + progress ("Wavelet...",100*readyphase/numofphases); + ipf.ip_wavelet(nprevl, nprevl, kall, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, scale); + } if(params.colorappearance.enabled){ diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 9a67323dc..e3ccecb66 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -120,6 +120,10 @@ class ImProcCoordinator : public StagedImageProcessor { OpacityCurve ctOpacityCurve; NoiseCurve noiseLCurve; NoiseCurve noiseCCurve; + WavCurve wavCLVCurve; + WavOpacityCurveRG waOpacityCurveRG; + WavOpacityCurveBY waOpacityCurveBY; + ColorAppearance customColCurve1; ColorAppearance customColCurve2; ColorAppearance customColCurve3; @@ -142,6 +146,7 @@ class ImProcCoordinator : public StagedImageProcessor { AutoBWListener* abwListener; AutoColorTonListener* actListener; AutoChromaListener* adnListener; + WaveletListener* awavListener; HistogramListener* hListener; std::vector sizeListeners; @@ -226,6 +231,7 @@ class ImProcCoordinator : public StagedImageProcessor { void setAutoBWListener (AutoBWListener* abw) {abwListener = abw; } void setAutoColorTonListener (AutoColorTonListener* bwct) {actListener = bwct; } void setAutoChromaListener (AutoChromaListener* adn) {adnListener = adn; } + void setWaveletListener (WaveletListener* awa) {awavListener = awa; } void saveInputICCReference (const Glib::ustring& fname); diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 80d2c8813..58454202e 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -266,7 +266,7 @@ class ImProcFunctions { void impulse_nrcam (CieImage* ncie, double thresh, float **buffers[3]); void dirpyrdenoise (LabImage* src);//Emil's pyramid denoise - void dirpyrequalizer (LabImage* lab, int scale);//Emil's equalizer + void dirpyrequalizer (LabImage* lab, int scale);//Emil's wavelet void EPDToneMap(LabImage *lab, unsigned int Iterates = 0, int skip = 1); void EPDToneMapCIE(CieImage *ncie, float a_w, float c_, float w_h, int Wid, int Hei, int begh, int endh, float minQ, float maxQ, unsigned int Iterates=0, int skip =1); @@ -285,6 +285,25 @@ class ImProcFunctions { //void RGB_OutputTransf(LabImage * src, Imagefloat * dst, const procparams::DirPyrDenoiseParams & dnparams); //void output_tile_row (float *Lbloxrow, float ** Lhipassdn, float ** tilemask, int height, int width, int top, int blkrad ); void Tile_calc (int tilesize, int overlap, int kall, int imwidth, int imheight, int &numtiles_W, int &numtiles_H, int &tilewidth, int &tileheight, int &tileWskip, int &tileHskip); + void ip_wavelet(LabImage * lab, LabImage * dst, int kall, const procparams::WaveletParams & waparams, const WavCurve & wavCLVCcurve, const WavOpacityCurveRG & waOpacityCurveRG, const WavOpacityCurveBY & waOpacityCurveBY, int skip); + void WaveletcontAllL(LabImage * lab, float **varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_L, + struct cont_params cp); + void WaveletcontAllAB(LabImage * lab, float **varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_a, + struct cont_params cp, const bool useChannelA); + void ContAllL (LabImage * lab, float **varhue, float **varchrom, float ** WavCoeffs_L, float * WavCoeffs_L0, int level, int dir, struct cont_params cp, + int W_L, int H_L); + void ContAllAB (LabImage * lab, float **varhue, float **varchrom, float ** WavCoeffs_a, float * WavCoeffs_a0, int level, int dir, struct cont_params cp, + int W_ab, int H_ab, const bool useChannelA); + void Evaluate(wavelet_decomposition &WaveletCoeffs_L, wavelet_decomposition &WaveletCoeffs_a, + wavelet_decomposition &WaveletCoeffs_b, float *av_LL, float *av_aa, float *av_bb,struct cont_params cp, int ind, float *mean, float *meanN, float *sigma, float *sigmaN); + void Eval (float ** WavCoeffs_L, float ** WavCoeffs_a, float ** WavCoeffs_b, int level,struct cont_params cp, + int W_L, int H_L, int W_ab, int H_ab,int skip_L, int skip_ab, float * av_LL, float * av_aa, float * av_bb, int ind, float *mean, float *meanN, float *sigma, float *sigmaN); + + void Aver(float * HH_Coeffs, int datalen, float &averagePlus, float &averageNeg, float &max, float &min); + void Sigma(float * HH_Coeffs, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg); + + + enum mediantype {MED_3X3SOFT, MED_3X3STRONG, MED_5X5SOFT, MED_5X5STRONG, MED_7X7, MED_9X9}; void Median_Denoise( float **src, float **dst, int width, int height, mediantype medianType, int iterations, int numThreads, float **buffer = NULL); void RGB_denoise(int kall, Imagefloat * src, Imagefloat * dst, Imagefloat * calclum, float * ch_M, float *max_r, float *max_b, bool isRAW, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp,const NoiseCurve & ctNoisCurve , const NoiseCurve & ctNoisCCcurve , float &chaut, float &redaut, float &blueaut, float &maxredaut, float & maxblueaut, float &nresi, float &highresi); @@ -314,9 +333,9 @@ class ImProcFunctions { float Mad(float * DataList, const int datalen); float MadRgb(float * DataList, const int datalen); - // pyramid equalizer - void dirpyr_equalizer (float ** src, float ** dst, int srcwidth, int srcheight, float ** l_a, float ** l_b, float ** dest_a, float ** dest_b, const double * mult, const double dirpyrThreshold, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scale);//Emil's directional pyramid equalizer - void dirpyr_equalizercam (CieImage* ncie, float ** src, float ** dst, int srcwidth, int srcheight, float ** h_p, float ** C_p, const double * mult, const double dirpyrThreshold, const double skinprot, bool execdir, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scale);//Emil's directional pyramid equalizer + // pyramid wavelet + void dirpyr_equalizer (float ** src, float ** dst, int srcwidth, int srcheight, float ** l_a, float ** l_b, float ** dest_a, float ** dest_b, const double * mult, const double dirpyrThreshold, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scale);//Emil's directional pyramid wavelet + void dirpyr_equalizercam (CieImage* ncie, float ** src, float ** dst, int srcwidth, int srcheight, float ** h_p, float ** C_p, const double * mult, const double dirpyrThreshold, const double skinprot, bool execdir, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scale);//Emil's directional pyramid wavelet void dirpyr_channel (float ** data_fine, float ** data_coarse, int width, int height, int level, int scale); void idirpyr_eq_channel (float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, float multi[5], const double dirpyrThreshold, float ** l_a_h, float ** l_b_c, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice); void idirpyr_eq_channelcam (float ** data_coarse, float ** data_fine, float ** buffer, int width, int height, int level, float multi[5], const double dirpyrThreshold, float ** l_a_h, float ** l_b_c, const double skinprot, float b_l, float t_l, float t_r); diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc new file mode 100644 index 000000000..dafc5e793 --- /dev/null +++ b/rtengine/ipwavelet.cc @@ -0,0 +1,1258 @@ +//////////////////////////////////////////////////////////////// +// +// +// +// +// code dated: December , 2014 +// +// Ipwaveletcc is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// * 2014 Jacques Desmis +// * 2014 Ingo Weyrich + +// +//////////////////////////////////////////////////////////////// + + + +#include +#include "../rtgui/threadutils.h" + +#include "rtengine.h" +#include "improcfun.h" +#include "LUT.h" +#include "array2D.h" +#include "boxblur.h" +#include "rt_math.h" +#include "mytime.h" +#include "sleef.c" +#include "opthelper.h" +#include "StopWatch.h" + +#ifdef _OPENMP +#include +#endif + +#include "cplx_wavelet_dec.h" + +#define TS 64 // Tile size +#define offset 25 // shift between tiles +#define fTS ((TS/2+1)) // second dimension of Fourier tiles +#define blkrad 1 // radius of block averaging + +#define PIX_SORT(a,b) { if ((a)>(b)) {temp=(a);(a)=(b);(b)=temp;} } + +#define med3(a0,a1,a2,a3,a4,a5,a6,a7,a8,median) { \ +pp[0]=a0; pp[1]=a1; pp[2]=a2; pp[3]=a3; pp[4]=a4; pp[5]=a5; pp[6]=a6; pp[7]=a7; pp[8]=a8; \ +PIX_SORT(pp[1],pp[2]); PIX_SORT(pp[4],pp[5]); PIX_SORT(pp[7],pp[8]); \ +PIX_SORT(pp[0],pp[1]); PIX_SORT(pp[3],pp[4]); PIX_SORT(pp[6],pp[7]); \ +PIX_SORT(pp[1],pp[2]); PIX_SORT(pp[4],pp[5]); PIX_SORT(pp[7],pp[8]); \ +PIX_SORT(pp[0],pp[3]); PIX_SORT(pp[5],pp[8]); PIX_SORT(pp[4],pp[7]); \ +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 + +#define epsilon 0.001f/(TS*TS) //tolerance + + +namespace rtengine { + +extern const Settings* settings; + +struct cont_params { + float mul[10]; + int chrom; + int chro; + int unif; + float th; + float thH; + float conres; + float conresH; + float chrores; + float sky; + float b_l,t_l,b_r,t_r; + float b_ly,t_ly,b_ry,t_ry; + float b_lsl,t_lsl,b_rsl,t_rsl; + float b_lhl,t_lhl,b_rhl,t_rhl; + + float b_lpast,t_lpast,b_rpast,t_rpast; + float b_lsat,t_lsat,b_rsat,t_rsat; + + int numlevH, numlevS; + float mulC[9]; + float mulopaRG[9]; + float mulopaBY[9]; + bool curv; + bool opaBY; + bool opaRG; + int CHmet; + bool HSmet; + bool avoi; +}; + +int wavNestedLevels = 1; + + void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const procparams::WaveletParams & waparams, const WavCurve & wavCLVCcurve, const WavOpacityCurveRG & waOpacityCurveRG, const WavOpacityCurveBY & waOpacityCurveBY, int skip) + { + MyTime t1e,t2e; + t1e.set(); + +#ifdef _DEBUG + // init variables to display Munsell corrections + MunsellDebugInfo* MunsDebugInfo = new MunsellDebugInfo(); +#endif + TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); + double wip[3][3] = { + {wiprof[0][0],wiprof[0][1],wiprof[0][2]}, + {wiprof[1][0],wiprof[1][1],wiprof[1][2]}, + {wiprof[2][0],wiprof[2][1],wiprof[2][2]} + }; + const short int imheight=lab->H, imwidth=lab->W; + struct cont_params cp; + cp.avoi=false; + if(params->wavelet.avoid) cp.avoi=true; + + int N=imheight*imwidth; + int maxmul=params->wavelet.thres; + cp.curv=false; + cp.opaRG=false; + cp.opaBY=false; + cp.CHmet=0; + cp.HSmet=false; + if(params->wavelet.CHmethod=="with") cp.CHmet=1; + if(params->wavelet.CHmethod=="link") cp.CHmet=2; + if(params->wavelet.HSmethod=="with") cp.HSmet=true; + + if(wavCLVCcurve) cp.curv=true; + + if(cp.curv) {//convert curve in discret values + cp.mulC[0]=200.f*(wavCLVCcurve[0]-0.5f); + cp.mulC[1]=200.f*(wavCLVCcurve[62]-0.5f); + cp.mulC[2]=200.f*(wavCLVCcurve[125]-0.5f); + cp.mulC[3]=200.f*(wavCLVCcurve[187]-0.5f); + cp.mulC[4]=200.f*(wavCLVCcurve[250]-0.5f); + cp.mulC[5]=200.f*(wavCLVCcurve[312]-0.5f); + cp.mulC[6]=200.f*(wavCLVCcurve[375]-0.5f); + cp.mulC[7]=200.f*(wavCLVCcurve[438]-0.5f); + cp.mulC[8]=200.f*(wavCLVCcurve[500]-0.5f); + } + else { + for(int level=0;level<9;level++) + cp.mulC[level] = 0.f; + } + if(waOpacityCurveRG) cp.opaRG=true; + + if(cp.opaRG) { + cp.mulopaRG[0]=200.f*(waOpacityCurveRG[0]-0.5f); + cp.mulopaRG[1]=200.f*(waOpacityCurveRG[62]-0.5f); + cp.mulopaRG[2]=200.f*(waOpacityCurveRG[125]-0.5f); + cp.mulopaRG[3]=200.f*(waOpacityCurveRG[187]-0.5f); + cp.mulopaRG[4]=200.f*(waOpacityCurveRG[250]-0.5f); + cp.mulopaRG[5]=200.f*(waOpacityCurveRG[312]-0.5f); + cp.mulopaRG[6]=200.f*(waOpacityCurveRG[375]-0.5f); + cp.mulopaRG[7]=200.f*(waOpacityCurveRG[438]-0.5f); + cp.mulopaRG[8]=200.f*(waOpacityCurveRG[500]-0.5f); + } + else { + for(int level=0;level<9;level++) + cp.mulopaRG[level] = 0.f; + } + + if(waOpacityCurveBY) cp.opaBY=true; + if(cp.opaBY) { + cp.mulopaBY[0]=200.f*(waOpacityCurveBY[0]-0.5f); + cp.mulopaBY[1]=200.f*(waOpacityCurveBY[62]-0.5f); + cp.mulopaBY[2]=200.f*(waOpacityCurveBY[125]-0.5f); + cp.mulopaBY[3]=200.f*(waOpacityCurveBY[187]-0.5f); + cp.mulopaBY[4]=200.f*(waOpacityCurveBY[250]-0.5f); + cp.mulopaBY[5]=200.f*(waOpacityCurveBY[312]-0.5f); + cp.mulopaBY[6]=200.f*(waOpacityCurveBY[375]-0.5f); + cp.mulopaBY[7]=200.f*(waOpacityCurveBY[438]-0.5f); + cp.mulopaBY[8]=200.f*(waOpacityCurveBY[500]-0.5f); + } + else { + for(int level=0;level<9;level++) + cp.mulopaBY[level] = 0.f; + } + + for(int m=0;m(params->wavelet.hueskin.value[0]) / 100.0f; + cp.t_l = static_cast(params->wavelet.hueskin.value[1]) / 100.0f; + cp.b_r = static_cast(params->wavelet.hueskin.value[2]) / 100.0f; + cp.t_r = static_cast(params->wavelet.hueskin.value[3]) / 100.0f; + + cp.b_ly = static_cast(params->wavelet.hueskin2.value[0]) / 100.0f; + cp.t_ly = static_cast(params->wavelet.hueskin2.value[1]) / 100.0f; + cp.b_ry = static_cast(params->wavelet.hueskin2.value[2]) / 100.0f; + cp.t_ry = static_cast(params->wavelet.hueskin2.value[3]) / 100.0f; + cp.numlevH=params->wavelet.threshold; + + cp.numlevH=params->wavelet.threshold; + //shadows + cp.b_lsl = static_cast(params->wavelet.bllev.value[0]); + cp.t_lsl = static_cast(params->wavelet.bllev.value[1]); + cp.b_rsl = static_cast(params->wavelet.bllev.value[2]); + cp.t_rsl = static_cast(params->wavelet.bllev.value[3]); + cp.numlevS=params->wavelet.threshold2; + int maxlevS=9-cp.numlevH; + cp.numlevS = MIN(cp.numlevS,maxlevS); + //highlight + cp.b_lhl = static_cast(params->wavelet.hllev.value[0]); + cp.t_lhl = static_cast(params->wavelet.hllev.value[1]); + cp.b_rhl = static_cast(params->wavelet.hllev.value[2]); + cp.t_rhl = static_cast(params->wavelet.hllev.value[3]); + //printf("H=%d S=%d\n",cp.numlevH,cp.numlevS); + //pastel + cp.b_lpast = static_cast(params->wavelet.pastlev.value[0]); + cp.t_lpast = static_cast(params->wavelet.pastlev.value[1]); + cp.b_rpast = static_cast(params->wavelet.pastlev.value[2]); + cp.t_rpast = static_cast(params->wavelet.pastlev.value[3]); + //saturated + cp.b_lsat = static_cast(params->wavelet.satlev.value[0]); + cp.t_lsat = static_cast(params->wavelet.satlev.value[1]); + cp.b_rsat = static_cast(params->wavelet.satlev.value[2]); + cp.t_rsat = static_cast(params->wavelet.satlev.value[3]); + + + int minwin=min(imwidth,imheight); + int maxlevelcrop=9; + if(cp.mul[9]!=0) + maxlevelcrop=10; + // adap maximum level wavelet to size of crop + if(minwin*skip < 1024) maxlevelcrop = 9;//sampling wavelet 512 + if(minwin*skip < 512) maxlevelcrop = 8;//sampling wavelet 256 + if(minwin*skip < 256) maxlevelcrop = 7;//sampling 128 + if(minwin*skip < 128) maxlevelcrop = 6; + if(minwin < 64) maxlevelcrop = 5; + printf("minwin=%d maxcrop=%d\n",minwin, maxlevelcrop); + + int levwav=params->wavelet.thres; + if(levwav==9 && cp.mul[9]!=0) levwav=10; + levwav=min(maxlevelcrop,levwav); + // determine number of levels to process. + // for(levwav=min(maxlevelcrop,levwav);levwav>0;levwav--) + // if(cp.mul[levwav-1]!=0.f || cp.curv) + // if(cp.mul[levwav-1]!=0.f) + // break; + // I suppress this fonctionality ==> crash for level < 3 + if(levwav<1) + return; // nothing to do + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // begin tile processing of image + + //output buffer + int realtile; + if(params->wavelet.Tilesmethod=="big") realtile=22; + if(params->wavelet.Tilesmethod=="lit") realtile=12; + + int tilesize; + int overlap; + tilesize = 1024; + overlap = 128; + //tilesize=128*params->wavelet.tiles; + tilesize=128*realtile; + //overlap=(int) tilesize*params->wavelet.overl; + overlap=(int) tilesize*0.125f; + // printf("overl=%d\n",overlap); + int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; + if(params->wavelet.Tilesmethod=="full") kall=0; + Tile_calc (tilesize, overlap, kall, imwidth, imheight, numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip); + + const int numtiles = numtiles_W*numtiles_H; + LabImage * dsttmp; + if(numtiles == 1) { + dsttmp = dst; + } else { + dsttmp = new LabImage(imwidth,imheight); + for (int n=0; n<3*imwidth*imheight; n++) dsttmp->data[n] = 0; + } + //now we have tile dimensions, overlaps + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + int minsizetile=min(tilewidth, tileheight); + int maxlev2=10; + if(minsizetile < 1024 && levwav==10) maxlev2 = 9; + if(minsizetile < 512) maxlev2 = 8; + if(minsizetile < 256) maxlev2 = 7; + if(minsizetile < 128) maxlev2 = 6; + levwav=min(maxlev2,levwav); + + printf("levwav = %d\n",levwav); + + int numthreads = 1; + int maxnumberofthreadsforwavelet =0; + //reduce memory for big tile size + if(kall!=0) { + if(realtile <= 22) maxnumberofthreadsforwavelet=2; + if(realtile <= 20) maxnumberofthreadsforwavelet=3; + if(realtile <= 18) maxnumberofthreadsforwavelet=4; + if(realtile <= 16) maxnumberofthreadsforwavelet=6; + if(realtile <= 14) maxnumberofthreadsforwavelet=8; + //printf("maxNRT=%d\n",maxnumberofthreadsforwavelet); + if((maxnumberofthreadsforwavelet==6 || maxnumberofthreadsforwavelet==8) && levwav==10) maxnumberofthreadsforwavelet-=2; + if(levwav <=7 && maxnumberofthreadsforwavelet ==8) maxnumberofthreadsforwavelet=0; + } + //printf("maxthre=%d\n",maxnumberofthreadsforwavelet); + +#ifdef _OPENMP + // Calculate number of tiles. If less than omp_get_max_threads(), then limit num_threads to number of tiles + if( options.rgbDenoiseThreadLimit>0) + maxnumberofthreadsforwavelet = min(max(options.rgbDenoiseThreadLimit / 2, 1), maxnumberofthreadsforwavelet); + + numthreads = MIN(numtiles,omp_get_max_threads()); + if(maxnumberofthreadsforwavelet > 0) + numthreads = MIN(numthreads,maxnumberofthreadsforwavelet); + wavNestedLevels = omp_get_max_threads() / numthreads; + bool oldNested = omp_get_nested(); + if(wavNestedLevels < 2) + wavNestedLevels = 1; + else + omp_set_nested(true); + if(maxnumberofthreadsforwavelet > 0) + while(wavNestedLevels*numthreads > maxnumberofthreadsforwavelet) + wavNestedLevels--; + if(settings->verbose) + printf("Ip Wavelet uses %d main thread(s) and up to %d nested thread(s) for each main thread\n",numthreads,wavNestedLevels); + + +#endif + +#pragma omp parallel num_threads(numthreads) + { + float *mean = new float [9]; + float *meanN = new float [9]; + float *sigma = new float [9]; + float *sigmaN = new float [9]; + + float** varhue = new float*[tileheight]; + for (int i=0; i we can use output buffer for labco + labco = dst; + else + labco = new LabImage(width,height); + +#ifdef _OPENMP +#pragma omp parallel for num_threads(wavNestedLevels) if(wavNestedLevels>1) +#endif + + for (int i=tiletop; iL[i][j]; + float a=lab->a[i][j]; + float b=lab->b[i][j]; + labco->L[i1][j1] = L; + labco->a[i1][j1] = a; + labco->b[i1][j1] = b; + varhue[i1][j1]=xatan2f(b,a); + varchro[i1][j1]=(sqrt(a*a+b*b))/327.68f; + } + } + //to avoid artifacts in blue sky + if(params->wavelet.median) { + float** tmL; + int wid=labco->W; + int hei=labco->H; + int borderL = 1; + tmL = new float*[hei]; + for (int i=0; iL[i][j]; + } + } + +#ifdef _OPENMP +#pragma omp parallel for num_threads(wavNestedLevels) if(wavNestedLevels>1) +#endif + for (int i=1; i - 2.6f) && (varchro[i][j] > 15.f && varchro[i][j] < 55.f) && labco->L[i][j] > 5000.f) //blue sky + med3x3 ==> after for more effect use denoise + med3(labco->L[i][j] ,labco->L[i-1][j], labco->L[i+1][j] ,labco->L[i][j+1],labco->L[i][j-1], labco->L[i-1][j-1],labco->L[i-1][j+1],labco->L[i+1][j-1],labco->L[i+1][j+1],tmL[i][j]);//3x3 + } + } + for(int i = borderL; i < hei-borderL; i++ ) { + for(int j = borderL; j < wid-borderL; j++) { + labco->L[i][j] = tmL[i][j]; + } + } + + for (int i=0; iwavelet.skinprotect != 0.0 || (cp.curv && cp.CHmet!=2)) // reduce the arrays to get faster access in following processing + for (int i=0; i<(tileheight)/2; i++) { + for (int j=0; j<(tilewidth)/2; j++) { + varhue[i][j]=varhue[i*2][j*2]; + } + } + int datalen = labco->W * labco->H; + + wavelet_decomposition* Ldecomp = new wavelet_decomposition (labco->data, labco->W, labco->H, levwav, 1, skip, max(1,wavNestedLevels) ); + if(!Ldecomp->memoryAllocationFailed) { + WaveletcontAllL(labco, varhue, varchro, *Ldecomp, cp); + Ldecomp->reconstruct(labco->data); + } + delete Ldecomp; + + wavelet_decomposition* adecomp = new wavelet_decomposition (labco->data+datalen, labco->W, labco->H,levwav, 1, skip, max(1,wavNestedLevels) ); + if(!adecomp->memoryAllocationFailed) { + WaveletcontAllAB(labco, varhue, varchro, *adecomp, cp, true); + adecomp->reconstruct(labco->data+datalen); + } + delete adecomp; + + wavelet_decomposition* bdecomp = new wavelet_decomposition (labco->data+2*datalen, labco->W, labco->H, levwav, 1, skip, max(1,wavNestedLevels) ); + if(!bdecomp->memoryAllocationFailed) { + WaveletcontAllAB(labco, varhue, varchro, *bdecomp, cp, false); + bdecomp->reconstruct(labco->data+2*datalen); + } + delete bdecomp; + + if(numtiles > 1 || (numtiles == 1 && cp.avoi)) { + //calculate mask for feathering output tile overlaps + float Vmask[height+overlap] ALIGNED16; + float Hmask[width+overlap] ALIGNED16; + + if(numtiles > 1) { + for (int i=0; i0) Vmask[i] = mask; + if (tilebottom0) Hmask[i] = mask; + if (tileright1) +#endif + for (int i=tiletop; iL[i1][j1]; + a = labco->a[i1][j1]; + b = labco->b[i1][j1]; + if(cp.avoi){//Gamut and Munsell + float HH=xatan2f(b,a); + float Chprov1=sqrt(SQR(a/327.68f) + SQR(b/327.68f)); + float Lprov1=L/327.68f; + float Lprov2 = lab->L[i][j]/327.68f; + float memChprov=varchro[i1][j1]; + bool highlight = params->toneCurve.hrenabled; + float R,G,B; + #ifdef _DEBUG + bool neg=false; + bool more_rgb=false; + Color::gamutLchonly(HH,Lprov1,Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f, neg, more_rgb); + #else + Color::gamutLchonly(HH,Lprov1,Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); + #endif + L=Lprov1*327.68f; + float2 sincosv = xsincosf(HH); + + a=327.68f*Chprov1*sincosv.y;//gamut + b=327.68f*Chprov1*sincosv.x;//gamut + { + float correctionHue=0.0f; // Munsell's correction + float correctlum=0.0f; + Lprov1=L/327.68f; + float Chprov=sqrt(SQR(a/327.68f)+ SQR(b/327.68f)); + #ifdef _DEBUG + Color::AllMunsellLch(true, Lprov1,Lprov2,HH,Chprov,memChprov,correctionHue,correctlum, MunsDebugInfo); + #else + Color::AllMunsellLch(true, Lprov1,Lprov2,HH,Chprov,memChprov,correctionHue,correctlum); + #endif + + if(fabs(correctionHue) < 0.015f) HH+=correctlum; // correct only if correct Munsell chroma very little. + float2 sincosval = xsincosf(HH+correctionHue); + + a=327.68f*Chprov*sincosval.y;// apply Munsell + b=327.68f*Chprov*sincosval.x;//aply Munsell + } + } + if(numtiles > 1) { + float factor = Vmask[i1]*Hmask[j1]; + dsttmp->L[i][j]+= factor*L; + dsttmp->a[i][j]+= factor*a; + dsttmp->b[i][j]+= factor*b; + } else { + dsttmp->L[i][j] = L; + dsttmp->a[i][j] = a; + dsttmp->b[i][j] = b; + + } + } + } + } + if(numtiles>1 || cp.avoi) + delete labco; + } + } + for (int i=0; i 1) { + dst->CopyFrom(dsttmp); + delete dsttmp; + } + +// if (settings->verbose) { + t2e.set(); + printf("Wavelet performed in %d usec:\n", t2e.etime(t1e)); +// } + +}//end o + + + + +#undef TS +#undef fTS +#undef offset +#undef epsilon + + void ImProcFunctions::Aver( float * RESTRICT DataList, int datalen, float &averagePlus, float &averageNeg, float &max, float &min) { + //find absolute mean + int averaP=0, averaN=0, count=0, countP=0, countN=0; + max=0.f;min=0.f; + averagePlus=0.f;averageNeg=0.f; + while (count= 0.f) {averaP += abs((int)DataList[count]); + if(abs((int)DataList[count])> max) max=abs((int)DataList[count]); + countP++; + } + if(DataList[count] < 0.f) {averaN += abs((int)DataList[count]); + if(abs((int)DataList[count])> min) min=abs((int)DataList[count]); + countN++; + } + + count++; + } + averagePlus=averaP/countP; + averageNeg=averaN/countN; + + } + + + void ImProcFunctions::Sigma( float * RESTRICT DataList, int datalen, float averagePlus, float averageNeg, float &sigmaPlus, float &sigmaNeg) { + int count=0, countP=0, countN=0; + float variP=0.f,variN=0.f; + while (count= 0.f) {variP += SQR(DataList[count] - averagePlus); + countP++; + } + else if(DataList[count] < 0.f) {variN += SQR(DataList[count] - averageNeg); + countN++; + } + count++; + } + sigmaPlus=sqrt(variP/countP); + sigmaNeg=sqrt(variN/countN); + + } + + void ImProcFunctions::Evaluate(wavelet_decomposition &WaveletCoeffs_L, wavelet_decomposition &WaveletCoeffs_a, + wavelet_decomposition &WaveletCoeffs_b, float *av_LL, float *av_aa, float *av_bb,struct cont_params cp, int ind, float *mean, float *meanN, float *sigma, float *sigmaN){ + int maxlvl = WaveletCoeffs_L.maxlevel(); + for (int lvl=0; lvlwavelet.thres; + for (int dir=1; dir<4; dir++) { + { + float averagePlus=0.f,averageNeg=0.f, max, min; + // Aver(WavCoeffs_L[dir], W_L*H_L, averagePlus, averageNeg, max, min); + Aver(WavCoeffs_b[dir], W_L*H_L, averagePlus, averageNeg, max, min); + avLP[dir] = fabs(averagePlus); + avLN[dir] = -fabs(averageNeg); + maxL[dir] = max; + minL[dir] = -min; + float sigmaPlus, sigmaNeg; + Sigma(WavCoeffs_b[dir], W_L*H_L, avLP[dir], -avLN[dir], sigmaPlus, sigmaNeg); + sigP[dir]=sigmaPlus; + sigN[dir]=sigmaNeg; + // printf("dir=%d level=%d avLP=%f max=%f avLN=%f min=%f sigP=%f sigN=%f\n",dir,level,avLP[dir] ,maxL[dir], avLN[dir] ,minL[dir], sigP[dir], sigN[dir]); + } + + } + AvL=0.f;AvN=0.f;SL=0.f;SN=0.f; + for (int dir=1; dir<4; dir++) { + AvL +=avLP[dir]; + AvN +=avLN[dir]; + SL +=sigP[dir]; + SN +=sigN[dir]; + } + AvL/=3; + AvN/=3; + SL/=3; + SN/=3; + mean[level]=AvL; + meanN[level]=AvN; + sigma[level]=SL; + sigmaN[level]=SN; + + printf("Ind=%d Level=%d AvL=%f AvN=%f SL=%f SN=%f\n",ind, level,mean[level],meanN[level],sigma[level],sigmaN[level]); + + } + + void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float **varchrom, wavelet_decomposition &WaveletCoeffs_L, + struct cont_params cp){ + + int maxlvl = WaveletCoeffs_L.maxlevel(); + int W_L = WaveletCoeffs_L.level_W(1); + int H_L = WaveletCoeffs_L.level_H(1); + + float * WavCoeffs_L0 = WaveletCoeffs_L.coeff0; +#ifdef _OPENMP +#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1) +#endif +{ +#ifdef _OPENMP +#pragma omp for nowait +#endif + for (int i=0; iL[ii*2][jj*2]; + float LL100 = LL/327.68f; + float tran = 5.f;//transition + //shadow + float alp=3.f;//increase contrast sahdow in lowlights between 1 and ?? + if(cp.th > (100.f-tran)) + tran=100.f-cp.th; + if(LL100 < cp.th){ + float aalp=(1.f-alp)/cp.th;//no changes for LL100 = cp.th + float kk=aalp*LL100+alp; + WavCoeffs_L0[i] *= (1.f+kk*cp.conres/200.f); + } + else if(LL100 < cp.th + tran) { + float ath = -cp.conres/tran; + float bth = cp.conres-ath*cp.th; + WavCoeffs_L0[i] *= (1.f+(LL100*ath+bth)/200.f); + } + //highlight + tran=5.f; + if(cp.thH < (tran)) + tran = cp.thH; + if(LL100 > cp.thH) + WavCoeffs_L0[i] *= (1.f+cp.conresH/200.f); + else if(LL100 > (cp.thH - tran)) { + float athH = cp.conresH/tran; + float bthH = cp.conresH-athH*cp.thH; + WavCoeffs_L0[i] *= (1.f+(LL100*athH+bthH)/200.f); + } + } + +#ifdef _OPENMP +#pragma omp for schedule(dynamic) collapse(2) +#endif + for (int dir=1; dir<4; dir++) { + for (int lvl=0; lvl1) +#endif +{ +#ifdef _OPENMP +#pragma omp for nowait +#endif + for (int i=0; i 0.f){ + if((modhue < cp.t_ry && modhue > cp.t_ly)) { + scale=(100.f-cp.sky)/100.1f; + } else if((modhue >= cp.t_ry && modhue < cp.b_ry)) { + scale=(100.f-cp.sky)/100.1f; + float ar=(scale-1.f)/(cp.t_ry- cp.b_ry); + float br=scale-cp.t_ry*ar; + scale=ar*modhue+br; + } else if((modhue > cp.b_ly && modhue < cp.t_ly)) { + scale=(100.f-cp.sky)/100.1f; + float al=(scale-1.f)/(-cp.b_ly + cp.t_ly); + float bl=scale-cp.t_ly*al; + scale=al*modhue+bl; + } + } else if(skyprot < 0.f){ + if((modhue > cp.t_ry || modhue < cp.t_ly)){ + scale=(100.f+cp.sky)/100.1f; + } + /* else if((modhue >= cp.t_ry && modhue < cp.b_ry)) { + scale=(100.f+cp.sky)/100.1f; + float ar=(scale-1.f)/(cp.t_ry- cp.b_ry); + float br=scale-cp.t_ry*ar; + scale=ar*modhue+br; + } + else if((modhue > cp.b_ly && modhue < cp.t_ly)) { + scale=(100.f+cp.sky)/100.1f; + float al=(scale-1.f)/(-cp.b_ly + cp.t_ly); + float bl=scale-cp.t_ly*al; + scale=al*modhue+bl; + } + */ + } + WavCoeffs_ab0[i]*=(1.f+cp.chrores*(scale)/100.f); + } + +#ifdef _OPENMP +#pragma omp for schedule(dynamic) collapse(2) +#endif + for (int dir=1; dir<4; dir++) { + for (int lvl=0; lvlwavelet.thres; + float cpMul = cp.mul[level]; + if(cpMul != 0.f) { // cpMul == 0.f means all will be multiplied by 1.f, so we can skip this + + const float skinprot = params->wavelet.skinprotect; + const float skinprotneg = -skinprot; + const float factorHard = (1.f - skinprotneg/100.f); + + //to adjust increase contrast with local contrast + + //for each pixel + // float k[8]={0.85f, 0.7f, 0.55f, 0.4f, 0.3f, 0.25f, 0.2f, 0.1f};//values to tested with several images + float k[9]={0.95f, 0.85f, 0.7f, 0.6f, 0.45f, 0.3f, 0.2f, 0.15f, 0.1f};//values to tested with several images + //float meath[8]={700.f, 1400.f, 1900.f, 2200.f, 2800.f, 3500.f, 4500.f, 6000.f};//values to tested with several images + float meath[9]={1000.f, 1500.f, 2000.f, 2500.f, 3000.f, 3500.f, 4000.f, 4500.f, 6000.f};//values to tested with several images + float ampli[9]={1.2f, 1.4f, 1.7f, 2.2f, 2.5f, 3.f, 3.5f, 4.f, 4.5f}; + float mea[9]; + float tr=cp.th;//suppress 2 slider + tr=90.f; + + for(int j=0;j<9;j++) mea[j]=meath[j]*(1.f+(ampli[j]-1.f)*(tr/100.f)); + // + //float uni=(float) cp.unif; + float uni = 95.f; + float bbet=1.f; + float abet[9]; + for(int h=0;h<9;h++) abet[h]=((k[h]-1.f)/100.f)*uni+bbet; + float beta; + + bool skinControl = (skinprot != 0.f); + bool useChromAndHue = (skinprot != 0.f || cp.HSmet); + float modchro, kLlev; + + for (int i=0; iL[ii*2][jj*2]; + LL100=LL/327.68f; + float modhue = varhue[ii][jj]; + modchro = varchrom[ii*2][jj*2]; + // hue chroma skin with initial lab datas + scale=1.f; + if(skinprot > 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); //0 for skin and extand + } else if(skinprot < 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); + if (scale == 1.f) + scale=factorHard; + else + scale=1.f; + } + } + //linear transition HL + float alpha = (1024.f + 15.f *(float) cpMul*scale*beta)/1024.f ; + if(cp.HSmet){ + float aaal=(1.f-alpha)/(cp.b_lhl-cp.t_lhl); + float bbal=1.f-aaal*cp.b_lhl; + float aaar=(alpha-1.f)/(cp.t_rhl-cp.b_rhl); + float bbbr=1.f-cp.b_rhl*aaar; + //linear transition Shadows + float aaalS=(1.f-alpha)/(cp.b_lsl-cp.t_lsl); + float bbalS=1.f-aaalS*cp.b_lsl; + float aaarS=(alpha-1.f)/(cp.t_rsl-cp.b_rsl); + float bbbrS=1.f-cp.b_rsl*aaarS; + if(level <=cp.numlevH) {//in function of levels + if((LL100 > cp.t_lhl && LL100 < cp.t_rhl)) kLlev=alpha; + else if((LL100 > cp.b_lhl && LL100 <= cp.t_lhl)) kLlev=aaal*LL100+bbal; + else if((LL100 > cp.t_rhl && LL100 <= cp.b_rhl)) kLlev=aaar*LL100+bbbr; + else kLlev=1.f; + } + if(level >=(9-cp.numlevS)) { + if((LL100 > cp.t_lsl && LL100 < cp.t_rsl)) kLlev=alpha; + else if((LL100 > cp.b_lsl && LL100 <= cp.t_lsl)) kLlev=aaalS*LL100+bbalS; + else if((LL100 > cp.t_rsl && LL100 <= cp.b_rsl)) kLlev=aaarS*LL100+bbbrS; + else kLlev=1.f; + } else + kLlev=alpha; + } + else kLlev=alpha; + WavCoeffs_L[dir][i]*=(kLlev); + } + } + + + + // to see each level of wavelet ...level from 0 to 7 + int choicelevel=0; + if(params->wavelet.Lmethod=="0_") choicelevel=0; + else if(params->wavelet.Lmethod=="1_") choicelevel=1; + else if(params->wavelet.Lmethod=="2_") choicelevel=2; + else if(params->wavelet.Lmethod=="3_") choicelevel=3; + else if(params->wavelet.Lmethod=="4_") choicelevel=4; + else if(params->wavelet.Lmethod=="5_") choicelevel=5; + else if(params->wavelet.Lmethod=="6_") choicelevel=6; + else if(params->wavelet.Lmethod=="7_") choicelevel=7; + else if(params->wavelet.Lmethod=="8_") choicelevel=8; + int choiceClevel=0; + if(params->wavelet.CLmethod=="one") choiceClevel=0; + else if(params->wavelet.CLmethod=="inf") choiceClevel=1; + else if(params->wavelet.CLmethod=="sup") choiceClevel=2; + else if(params->wavelet.CLmethod=="all") choiceClevel=3; + int choiceDir=0; + if(params->wavelet.Dirmethod=="one") choiceDir=1; + else if(params->wavelet.Dirmethod=="two") choiceDir=2; + else if(params->wavelet.Dirmethod=="thr") choiceDir=3; + else if(params->wavelet.Dirmethod=="all") choiceDir=0; + + // printf("LUm lev=%d clev=%d dir=%d\n",choicelevel,choiceClevel,choiceDir); + if(choiceClevel==0){ + if(choiceDir==0){ + if(level != choicelevel){ + for (int dir=1; dir<4; dir++) { + for (int i=0; i= choicelevel){ + for (int dir=1; dir<4; dir++) { + for (int i=0; i= choicelevel){ + + for (int i=0; iwavelet.thres; + float cpMul = cp.mul[level]; + if(cpMul != 0.f && cp.CHmet==2 && cp.chro != 0.f) { // cpMul == 0.f means all will be multiplied by 1.f, so we can skip this + const float skinprot = params->wavelet.skinprotect; + const float skinprotneg = -skinprot; + const float factorHard = (1.f - skinprotneg/100.f); + const float cpChrom = cp.chro; + + //to adjust increase contrast with local contrast + bool useChromAndHue = (skinprot != 0.f); + float modchro; + + for (int i=0; iL[ii*2][jj*2]; + float LL100=LL/327.68f; + float modhue = varhue[ii][jj]; + modchro = varchrom[ii*2][jj*2]; + // hue chroma skin with initial lab datas + scale=1.f; + if(skinprot > 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); //0 for skin and extand + } else if(skinprot < 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 0); + if (scale == 1.f) + scale=factorHard; + else + scale=1.f; + } + } + float alphaC =(1024.f + 15.f *cpMul*cpChrom*scale*scaleSK/50.f)/1024.f ; + WavCoeffs_ab[dir][i]*=alphaC; + } + } + //Curve chro + bool useOpacity; + float mulOpacity; + if(useChannelA) { + useOpacity = cp.opaRG; + mulOpacity = cp.mulopaRG[level]; + } + else { + useOpacity = cp.opaBY; + mulOpacity = cp.mulopaBY[level]; + } + if(cp.curv && cp.CHmet!=2 && level < 9) { + float modchro, modhue, kLlev, kClev; + float cpMulC = cp.mulC[level]; + const float skinprot = params->wavelet.skinprotect; + const float skinprotneg = -skinprot; + const float factorHard = (1.f - skinprotneg/100.f); + bool skinControl = (skinprot != 0.f); + + for (int i=0; iL[ii*2][jj*2]; + float LL100=LL/327.68f; + float scale=1.f; + modchro = varchrom[ii*2][jj*2]; + float modhue = varhue[ii][jj]; + + if(skinControl) { + // hue chroma skin with initial lab datas + modhue = varhue[ii][jj]; + + scale=1.f; + if(skinprot > 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 1); //1 for curve + } + else if(skinprot < 0.f){ + Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprotneg, scale, false, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 1); + if (scale == 1.f) { scale=factorHard;} + else scale=1.f; + } + } + float scaleSK =1.f; + float beta = (1024.f + 20.f *(float) cpMulC*scale*scaleSK)/1024.f ; + if(beta < 0.02f) beta=0.02f; + //linear for saturated + float aaal=(1.f-beta)/(cp.b_lsat-cp.t_lsat); + float bbal=1.f-aaal*cp.b_lsat; + float aaar=(beta-1.f)/(cp.t_rsat-cp.b_rsat); + float bbbr=1.f-cp.b_rsat*aaar; + //linear for pastel + float aaalS=(1.f-beta)/(cp.b_lpast-cp.t_lpast); + float bbalS=1.f-aaalS*cp.b_lpast; + float aaarS=(beta-1.f)/(cp.t_rpast-cp.b_rpast); + float bbbrS=1.f-cp.b_rpast*aaarS; + kClev=beta; + if(cp.CHmet==1){ + if(level < cp.chrom) { + if((modchro > cp.t_lsat && modchro < cp.t_rsat)) kClev=beta; + else if((modchro > cp.b_lsat && modchro <= cp.t_lsat)) kClev=aaal*modchro+bbal; + else if((modchro > cp.t_rsat && modchro <= cp.b_rsat)) kClev=aaar*modchro+bbbr; + else kClev=1.f; + } + if(level >= cp.chrom) { + if((modchro > cp.t_lpast && modchro < cp.t_rpast)) kClev=beta; + else if((modchro > cp.b_lpast && modchro <= cp.t_lpast)) kClev=aaalS*modchro+bbalS; + else if((modchro > cp.t_rpast && modchro <= cp.b_rpast)) kClev=aaarS*modchro+bbbrS; + else kClev=1.f; + } + } + else if(cp.CHmet==0)kClev=beta; + WavCoeffs_ab[dir][i]*=kClev; + } + } + + if(useOpacity && level < 9) { //toning + float betaRG = (1024.f + 20.f *(float) mulOpacity)/1024.f ; + for (int i=0; iwavelet.Lmethod=="0_") choicelevel=0; + else if(params->wavelet.Lmethod=="1_") choicelevel=1; + else if(params->wavelet.Lmethod=="2_") choicelevel=2; + else if(params->wavelet.Lmethod=="3_") choicelevel=3; + else if(params->wavelet.Lmethod=="4_") choicelevel=4; + else if(params->wavelet.Lmethod=="5_") choicelevel=5; + else if(params->wavelet.Lmethod=="6_") choicelevel=6; + else if(params->wavelet.Lmethod=="7_") choicelevel=7; + else if(params->wavelet.Lmethod=="8_") choicelevel=8; + int choiceClevel=0; + if(params->wavelet.CLmethod=="one") choiceClevel=0; + else if(params->wavelet.CLmethod=="inf") choiceClevel=1; + else if(params->wavelet.CLmethod=="sup") choiceClevel=2; + else if(params->wavelet.CLmethod=="all") choiceClevel=3; + int choiceDir=0; + if(params->wavelet.Dirmethod=="one") choiceDir=1; + else if(params->wavelet.Dirmethod=="two") choiceDir=2; + else if(params->wavelet.Dirmethod=="thr") choiceDir=3; + else if(params->wavelet.Dirmethod=="all") choiceDir=0; + // printf("CHRO lev=%d clev=%d dir=%d\n",choicelevel,choiceClevel,choiceDir); + + + if(choiceClevel==0){ + if(choiceDir==0){ + if(level != choicelevel){ + for (int dir=1; dir<4; dir++) { + for (int i=0; i= choicelevel){ + for (int dir=1; dir<4; dir++) { + for (int i=0; i= choicelevel){ + + for (int i=0; i #include #include "rt_math.h" - #include "safegtk.h" #include "../rtgui/multilangmgr.h" #include "procparams.h" @@ -125,6 +124,7 @@ void ColorToningParams::getDefaultColorCurve(std::vector &curve) { curve.at(i) = v[i-1]; } + void ColorToningParams::getDefaultOpacityCurve(std::vector &curve) { double v[16]={ 0.00, 0.3, 0.35, 0.00, 0.25, 0.8, 0.35, 0.35, @@ -294,7 +294,6 @@ void ColorToningParams::mixerToCurve(std::vector &colorCurve, std::vecto - colorCurve.resize( medSat!=0.f ? 13 : 9 ); colorCurve.at(0) = FCT_MinMaxCPoints; opacityCurve.resize(13); @@ -414,6 +413,94 @@ void ColorToningParams::getCurves(ColorGradientCurve &colorCurveLUT, OpacityCurv } } +WaveletParams::WaveletParams (): hueskin(-5, 25, 170, 120, false), hueskin2(-260, -250, -130, -140, false), hllev(50, 75, 100, 98, false), bllev(0, 2, 50, 25, false), pastlev(0, 2, 30, 20, false), satlev(30, 45, 130, 100, false){ + setDefaults (); +} + +void WaveletParams::getDefaultOpacityCurveRG(std::vector &curve) { + double v[8]= { 0.0, 0.50,0.35,0.35, + 1.00, 0.50,0.35,0.35}; + + curve.resize(9); + curve.at(0) = double(FCT_MinMaxCPoints); + for (size_t i=1; i &curve) { + double v[8]= { 0.0, 0.50,0.35,0.35, + 1.00, 0.50,0.35,0.35}; + + curve.resize(9); + curve.at(0 ) = double(FCT_MinMaxCPoints); + for (size_t i=1; i &curve) { + double v[8]= { 0.0, 0.50,0.35,0.35, + 1.00, 0.50,0.35,0.35}; + curve.resize(9); + curve.at(0 ) = double(FCT_MinMaxCPoints); + for (size_t i=1; i GCurve; + // GCurve = this->colorCurve; + cCurve.Set(this->clvcurve); + opacityCurveLUTRG.Set(this->opacityCurveRG); + // colorCurveLUT.SetXYZ(GCurve, xyz_rgb, rgb_xyz, satur, lumin); + + opacityCurveLUTBY.Set(this->opacityCurveBY); +} + +void WaveletParams::setDefaults() { + getDefaultCLVCurve(clvcurve); + getDefaultOpacityCurveRG(opacityCurveRG); + getDefaultOpacityCurveBY(opacityCurveBY); + enabled = false; + display = true; + median = false; + avoid = false; + Lmethod = "4_"; + CHmethod = "without"; + HSmethod = "with"; + CLmethod = "all"; + Dirmethod = "all"; + Tilesmethod = "full"; + tiles = 14; + rescon = 0; + resconH = 0; + reschro = 0; + sky = 0.; + sup = 0; + thres = 7; + chroma = 5; + chro = 0; + unif = 0; + thr = 30; + thrH = 70; + skinprotect = 0.; + hueskin.setValues(-5, 25, 170, 120); + hueskin2.setValues(-260, -250, -130, -140); + threshold=5; + threshold2=4; + hllev.setValues(50, 75, 100, 98); + bllev.setValues(0, 2, 50, 25); + pastlev.setValues(0, 2, 30, 20); + satlev.setValues(30, 45, 130, 100); + + for(int i = 0; i < 9; i ++) + { + c[i] = 0; + } + +} + DirPyrDenoiseParams::DirPyrDenoiseParams () { setDefaults (); @@ -838,7 +925,7 @@ void ProcParams::setDefaults () { dirpyrequalizer.enabled = false; dirpyrequalizer.gamutlab = false; - for(int i = 0; i < 5; i ++) + for(int i = 0; i < 6; i ++) { dirpyrequalizer.mult[i] = 1.0; } @@ -1419,36 +1506,113 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol if (!pedited || pedited->icm.freegamma) keyFile.set_boolean ("Color Management", "Freegamma", icm.freegamma); if (!pedited || pedited->icm.gampos) keyFile.set_double ("Color Management", "GammaValue", icm.gampos); if (!pedited || pedited->icm.slpos) keyFile.set_double ("Color Management", "GammaSlope", icm.slpos); + + + + // save wavelet parameters + if (!pedited || pedited->wavelet.enabled) keyFile.set_boolean ("Wavelet", "Enabled", wavelet.enabled); + if (!pedited || pedited->wavelet.display) keyFile.set_boolean ("Wavelet", "Display", wavelet.display); + if (!pedited || pedited->wavelet.thres) keyFile.set_integer ("Wavelet", "MaxLev", wavelet.thres); + if (!pedited || pedited->wavelet.Tilesmethod) keyFile.set_string ("Wavelet", "TilesMethod", wavelet.Tilesmethod); + if (!pedited || pedited->wavelet.CLmethod) keyFile.set_string ("Wavelet", "ChoiceLevMethod", wavelet.CLmethod); + if (!pedited || pedited->wavelet.Lmethod) keyFile.set_string ("Wavelet", "LevMethod", wavelet.Lmethod); + if (!pedited || pedited->wavelet.Dirmethod) keyFile.set_string ("Wavelet", "DirMethod", wavelet.Dirmethod); + // if (!pedited || pedited->wavelet.tiles) keyFile.set_integer ("Wavelet", "Tiles", wavelet.tiles); + for(int i = 0; i < 9; i++) + { + std::stringstream ss; + ss << "Contrast" << i; + if (!pedited || pedited->wavelet.c[i]) keyFile.set_integer("Wavelet", ss.str(), wavelet.c[i]); + } + if (!pedited || pedited->wavelet.sup) keyFile.set_integer ("Wavelet", "ContExtra", wavelet.sup); + if (!pedited || pedited->wavelet.HSmethod) keyFile.set_string ("Wavelet", "HSMethod", wavelet.HSmethod); + if (!pedited || pedited->wavelet.hllev) { + Glib::ArrayHandle thresh (wavelet.hllev.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "HLRange", thresh); + } + if (!pedited || pedited->wavelet.bllev) { + Glib::ArrayHandle thresh (wavelet.bllev.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "SHRange", thresh); + } + if (!pedited || pedited->wavelet.threshold) keyFile.set_integer ("Wavelet", "ThresholdHighlight", wavelet.threshold); + if (!pedited || pedited->wavelet.threshold2) keyFile.set_integer ("Wavelet", "ThresholdShadow", wavelet.threshold2); + if (!pedited || pedited->wavelet.chroma) keyFile.set_integer ("Wavelet", "ThresholdChroma", wavelet.chroma); + if (!pedited || pedited->wavelet.CHmethod) keyFile.set_string ("Wavelet", "CHromaMethod", wavelet.CHmethod); + if (!pedited || pedited->wavelet.chro) keyFile.set_integer ("Wavelet", "ChromaLink", wavelet.chro); + // if (!pedited || pedited->wavelet.unif) keyFile.set_integer ("Wavelet", "Unif", wavelet.unif); + if (!pedited || pedited->wavelet.clvcurve) { + Glib::ArrayHandle clvcurve = wavelet.clvcurve; + keyFile.set_double_list("Wavelet", "ChromaCurve", clvcurve); + } + if (!pedited || pedited->wavelet.pastlev) { + Glib::ArrayHandle thresh (wavelet.pastlev.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "Pastlev", thresh); + } + if (!pedited || pedited->wavelet.satlev) { + Glib::ArrayHandle thresh (wavelet.satlev.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "Satlev", thresh); + } + + if (!pedited || pedited->wavelet.opacityCurveRG) { + Glib::ArrayHandle curve = wavelet.opacityCurveRG; + keyFile.set_double_list("Wavelet", "OpacityCurveRG", curve); + } + if (!pedited || pedited->wavelet.opacityCurveBY) { + Glib::ArrayHandle curve = wavelet.opacityCurveBY; + keyFile.set_double_list("Wavelet", "OpacityCurveBY", curve); + } + + + if (!pedited || pedited->wavelet.median) keyFile.set_boolean ("Wavelet", "Median", wavelet.median); + if (!pedited || pedited->wavelet.skinprotect) keyFile.set_double ("Wavelet", "Skinprotect", wavelet.skinprotect); + if (!pedited || pedited->wavelet.hueskin) { + Glib::ArrayHandle thresh (wavelet.hueskin.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "Hueskin", thresh); + } + + if (!pedited || pedited->wavelet.avoid) keyFile.set_boolean ("Wavelet", "AvoidColorShift", wavelet.avoid); + + if (!pedited || pedited->wavelet.rescon) keyFile.set_integer ("Wavelet", "ResidualcontShadow", wavelet.rescon); + if (!pedited || pedited->wavelet.resconH) keyFile.set_integer ("Wavelet", "ResidualcontHighlight", wavelet.resconH); + if (!pedited || pedited->wavelet.thr) keyFile.set_integer ("Wavelet", "ThresholdResidShadow", wavelet.thr); + if (!pedited || pedited->wavelet.thrH) keyFile.set_integer ("Wavelet", "ThresholdResidHighLight", wavelet.thrH); + if (!pedited || pedited->wavelet.reschro) keyFile.set_integer ("Wavelet", "Residualchroma", wavelet.reschro); + if (!pedited || pedited->wavelet.sky) keyFile.set_double ("Wavelet", "HueRangeResidual", wavelet.sky); + if (!pedited || pedited->wavelet.hueskin2) { + Glib::ArrayHandle thresh (wavelet.hueskin2.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "HueRange", thresh); + } + - // save directional pyramid equalizer parameters - if (!pedited || pedited->dirpyrequalizer.enabled) keyFile.set_boolean ("Directional Pyramid Equalizer", "Enabled", dirpyrequalizer.enabled); - if (!pedited || pedited->dirpyrequalizer.gamutlab) keyFile.set_boolean ("Directional Pyramid Equalizer", "Gamutlab", dirpyrequalizer.gamutlab); - for(int i = 0; i < 5; i++) + // save directional pyramid wavelet parameters + if (!pedited || pedited->dirpyrequalizer.enabled) keyFile.set_boolean ("Directional Pyramid Wavelet", "Enabled", dirpyrequalizer.enabled); + if (!pedited || pedited->dirpyrequalizer.gamutlab) keyFile.set_boolean ("Directional Pyramid Wavelet", "Gamutlab", dirpyrequalizer.gamutlab); + for(int i = 0; i < 6; i++) { std::stringstream ss; ss << "Mult" << i; - if (!pedited || pedited->dirpyrequalizer.mult[i]) keyFile.set_double("Directional Pyramid Equalizer", ss.str(), dirpyrequalizer.mult[i]); + if (!pedited || pedited->dirpyrequalizer.mult[i]) keyFile.set_double("Directional Pyramid Wavelet", ss.str(), dirpyrequalizer.mult[i]); } - if (!pedited || pedited->dirpyrequalizer.threshold) keyFile.set_double ("Directional Pyramid Equalizer", "Threshold", dirpyrequalizer.threshold); - if (!pedited || pedited->dirpyrequalizer.skinprotect) keyFile.set_double ("Directional Pyramid Equalizer", "Skinprotect", dirpyrequalizer.skinprotect); - // if (!pedited || pedited->dirpyrequalizer.algo) keyFile.set_string ("Directional Pyramid Equalizer", "Algorithm", dirpyrequalizer.algo); + if (!pedited || pedited->dirpyrequalizer.threshold) keyFile.set_double ("Directional Pyramid Wavelet", "Threshold", dirpyrequalizer.threshold); + if (!pedited || pedited->dirpyrequalizer.skinprotect) keyFile.set_double ("Directional Pyramid Wavelet", "Skinprotect", dirpyrequalizer.skinprotect); + // if (!pedited || pedited->dirpyrequalizer.algo) keyFile.set_string ("Directional Pyramid Wavelet", "Algorithm", dirpyrequalizer.algo); if (!pedited || pedited->dirpyrequalizer.hueskin) { Glib::ArrayHandle thresh (dirpyrequalizer.hueskin.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Directional Pyramid Equalizer", "Hueskin", thresh); + keyFile.set_integer_list("Directional Pyramid Wavelet", "Hueskin", thresh); } - // save hsv equalizer parameters + // save hsv wavelet parameters if (!pedited || pedited->hsvequalizer.hcurve) { Glib::ArrayHandle hcurve = hsvequalizer.hcurve; - keyFile.set_double_list("HSV Equalizer", "HCurve", hcurve); + keyFile.set_double_list("HSV Wavelet", "HCurve", hcurve); } if (!pedited || pedited->hsvequalizer.scurve) { Glib::ArrayHandle scurve = hsvequalizer.scurve; - keyFile.set_double_list("HSV Equalizer", "SCurve", scurve); + keyFile.set_double_list("HSV Wavelet", "SCurve", scurve); } if (!pedited || pedited->hsvequalizer.vcurve) { Glib::ArrayHandle vcurve = hsvequalizer.vcurve; - keyFile.set_double_list("HSV Equalizer", "VCurve", vcurve); + keyFile.set_double_list("HSV Wavelet", "VCurve", vcurve); } //save film simulation parameters @@ -2132,15 +2296,86 @@ if (keyFile.has_group ("Color Management")) { if (keyFile.has_key ("Color Management", "GammaValue")) { icm.gampos = keyFile.get_double ("Color Management", "GammaValue"); if (pedited) pedited->icm.gampos = true; } if (keyFile.has_key ("Color Management", "GammaSlope")) { icm.slpos = keyFile.get_double ("Color Management", "GammaSlope"); if (pedited) pedited->icm.slpos = true; } +} + // load wavelet wavelet parameters +if (keyFile.has_group ("Wavelet")) { + if (keyFile.has_key ("Wavelet", "Enabled")) { wavelet.enabled = keyFile.get_boolean ("Wavelet", "Enabled"); if (pedited) pedited->wavelet.enabled = true; } + + if (keyFile.has_key ("Wavelet", "Display")){ wavelet.display = keyFile.get_boolean ("Wavelet", "Display");if (pedited) pedited->wavelet.display = true;} + if (keyFile.has_key ("Wavelet", "Median")) {wavelet.median = keyFile.get_boolean ("Wavelet", "Median");if (pedited) pedited->wavelet.median = true;} + if (keyFile.has_key ("Wavelet", "AvoidColorShift")) {wavelet.avoid = keyFile.get_boolean ("Wavelet", "AvoidColorShift");if (pedited) pedited->wavelet.avoid = true;} + if (keyFile.has_key ("Wavelet", "LevMethod")) {wavelet.Lmethod = keyFile.get_string ("Wavelet", "LevMethod"); if (pedited) pedited->wavelet.Lmethod = true; } + if (keyFile.has_key ("Wavelet", "ChoiceLevMethod")) {wavelet.CLmethod = keyFile.get_string ("Wavelet", "ChoiceLevMethod"); if (pedited) pedited->wavelet.CLmethod = true; } + if (keyFile.has_key ("Wavelet", "TilesMethod")) {wavelet.Tilesmethod = keyFile.get_string ("Wavelet", "TilesMethod"); if (pedited) pedited->wavelet.Tilesmethod = true; } + if (keyFile.has_key ("Wavelet", "CHromaMethod")) {wavelet.CHmethod = keyFile.get_string ("Wavelet", "CHromaMethod"); if (pedited) pedited->wavelet.CHmethod = true; } + if (keyFile.has_key ("Wavelet", "HSMethod")) {wavelet.HSmethod = keyFile.get_string ("Wavelet", "HSMethod"); if (pedited) pedited->wavelet.HSmethod = true; } + if (keyFile.has_key ("Wavelet", "DirMethod")) {wavelet.Dirmethod = keyFile.get_string ("Wavelet", "DirMethod"); if (pedited) pedited->wavelet.Dirmethod = true; } + if (keyFile.has_key ("Wavelet", "Tiles")) {wavelet.tiles = keyFile.get_integer ("Wavelet", "Tiles"); if (pedited) pedited->wavelet.tiles = true; } + if (keyFile.has_key ("Wavelet", "ResidualcontShadow")) {wavelet.rescon = keyFile.get_integer ("Wavelet", "ResidualcontShadow"); if (pedited) pedited->wavelet.rescon = true; } + if (keyFile.has_key ("Wavelet", "ResidualcontHighLight")) {wavelet.resconH = keyFile.get_integer ("Wavelet", "ResidualcontHighLight"); if (pedited) pedited->wavelet.resconH = true; } + if (keyFile.has_key ("Wavelet", "Residualchroma")) {wavelet.reschro = keyFile.get_integer ("Wavelet", "Residualchroma"); if (pedited) pedited->wavelet.reschro = true; } + if (keyFile.has_key ("Wavelet", "ContExtra")) {wavelet.sup = keyFile.get_integer ("Wavelet", "ContExtra"); if (pedited) pedited->wavelet.sup = true; } + if (keyFile.has_key ("Wavelet", "HueRangeResidual")) {wavelet.sky = keyFile.get_double ("Wavelet", "HueRangeResidual"); if (pedited) pedited->wavelet.sky = true; } + if (keyFile.has_key ("Wavelet", "MaxLev")) {wavelet.thres = keyFile.get_integer ("Wavelet", "MaxLev"); if (pedited) pedited->wavelet.thres = true; } + if (keyFile.has_key ("Wavelet", "ThresholdHighLight")) {wavelet.threshold = keyFile.get_integer ("Wavelet", "ThresholdHighLight"); if (pedited) pedited->wavelet.threshold = true; } + if (keyFile.has_key ("Wavelet", "ThresholdShadow")) {wavelet.threshold2 = keyFile.get_integer ("Wavelet", "ThresholdShadow"); if (pedited) pedited->wavelet.threshold2 = true; } + if (keyFile.has_key ("Wavelet", "ThresholdChroma")) {wavelet.chroma = keyFile.get_integer ("Wavelet", "ThresholdChroma"); if (pedited) pedited->wavelet.chroma = true; } + if (keyFile.has_key ("Wavelet", "ChromaLink")) {wavelet.chro = keyFile.get_integer ("Wavelet", "ChromaLink"); if (pedited) pedited->wavelet.chro = true; } + if (keyFile.has_key ("Wavelet", "Unif")) {wavelet.unif = keyFile.get_integer ("Wavelet", "Unif"); if (pedited) pedited->wavelet.unif = true; } + if (keyFile.has_key ("Wavelet", "ThresholdResidShadow")) {wavelet.thr = keyFile.get_integer ("Wavelet", "ThresholdResidShadow"); if (pedited) pedited->wavelet.thr = true; } + if (keyFile.has_key ("Wavelet", "ThresholdResidHighLight")) {wavelet.thr = keyFile.get_integer ("Wavelet", "ThresholdResidHighLight"); if (pedited) pedited->wavelet.thrH = true; } + if (keyFile.has_key ("Wavelet", "ChromaCurve")) {wavelet.clvcurve = keyFile.get_double_list ("Wavelet", "ChromaCurve"); if (pedited) pedited->wavelet.clvcurve = true; } + if (keyFile.has_key ("Wavelet", "OpacityCurveRG")) { wavelet.opacityCurveRG = keyFile.get_double_list ("Wavelet", "OpacityCurveRG"); if (pedited) pedited->wavelet.opacityCurveRG = true; } + if (keyFile.has_key ("Wavelet", "OpacityCurveBY")) { wavelet.opacityCurveBY = keyFile.get_double_list ("Wavelet", "OpacityCurveBY"); if (pedited) pedited->wavelet.opacityCurveBY = true; } + if (keyFile.has_key ("Wavelet", "Hueskin")) { + Glib::ArrayHandle thresh = keyFile.get_integer_list ("Wavelet", "Hueskin"); + wavelet.hueskin.setValues(thresh.data()[0], thresh.data()[1], min(thresh.data()[2], 300), min(thresh.data()[3], 300)); + if (pedited) pedited->wavelet.hueskin = true; + } + if (keyFile.has_key ("Wavelet", "HueRange")) { + Glib::ArrayHandle thresh = keyFile.get_integer_list ("Wavelet", "HueRange"); + wavelet.hueskin2.setValues(thresh.data()[0], thresh.data()[1], min(thresh.data()[2], 300), min(thresh.data()[3], 300)); + if (pedited) pedited->wavelet.hueskin2 = true; + } + + if (keyFile.has_key ("Wavelet", "HLRange")) { + Glib::ArrayHandle thresh = keyFile.get_integer_list ("Wavelet", "HLRange"); + wavelet.hllev.setValues(thresh.data()[0], thresh.data()[1], min(thresh.data()[2], 300), min(thresh.data()[3], 300)); + if (pedited) pedited->wavelet.hllev = true; + } + if (keyFile.has_key ("Wavelet", "SHRange")) { + Glib::ArrayHandle thresh = keyFile.get_integer_list ("Wavelet", "SHRange"); + wavelet.bllev.setValues(thresh.data()[0], thresh.data()[1], min(thresh.data()[2], 300), min(thresh.data()[3], 300)); + if (pedited) pedited->wavelet.bllev = true; + } + if (keyFile.has_key ("Wavelet", "Pastlev")) { + Glib::ArrayHandle thresh = keyFile.get_integer_list ("Wavelet", "Pastlev"); + wavelet.pastlev.setValues(thresh.data()[0], thresh.data()[1], min(thresh.data()[2], 300), min(thresh.data()[3], 300)); + if (pedited) pedited->wavelet.pastlev = true; + } + if (keyFile.has_key ("Wavelet", "Satlev")) { + Glib::ArrayHandle thresh = keyFile.get_integer_list ("Wavelet", "Satlev"); + wavelet.satlev.setValues(thresh.data()[0], thresh.data()[1], min(thresh.data()[2], 300), min(thresh.data()[3], 300)); + if (pedited) pedited->wavelet.satlev = true; + } + + + if(keyFile.has_key ("Wavelet", "Skinprotect")) { wavelet.skinprotect = keyFile.get_double ("Wavelet", "Skinprotect"); if (pedited) pedited->wavelet.skinprotect = true; } + for(int i = 0; i < 9; i ++) + { + std::stringstream ss; + ss << "Contrast" << i; + if(keyFile.has_key ("Wavelet", ss.str())) {wavelet.c[i] = keyFile.get_integer ("Wavelet", ss.str()); if (pedited) pedited->wavelet.c[i] = true;} + } } - // load directional pyramid equalizer parameters -if (keyFile.has_group ("Directional Pyramid Equalizer")) { - if (keyFile.has_key ("Directional Pyramid Equalizer", "Enabled")) { dirpyrequalizer.enabled = keyFile.get_boolean ("Directional Pyramid Equalizer", "Enabled"); if (pedited) pedited->dirpyrequalizer.enabled = true; } - if (keyFile.has_key ("Directional Pyramid Equalizer", "Gamutlab")) { dirpyrequalizer.gamutlab = keyFile.get_boolean ("Directional Pyramid Equalizer", "Gamutlab"); if (pedited) pedited->dirpyrequalizer.gamutlab = true; } - // if (keyFile.has_key ("Directional Pyramid Equalizer", "Algorithm")) { dirpyrequalizer.algo = keyFile.get_string ("Directional Pyramid Equalizer", "Algorithm"); if (pedited) pedited->dirpyrequalizer.algo = true; } - if (keyFile.has_key ("Directional Pyramid Equalizer", "Hueskin")) { - Glib::ArrayHandle thresh = keyFile.get_integer_list ("Directional Pyramid Equalizer", "Hueskin"); + // load directional pyramid wavelet parameters +if (keyFile.has_group ("Directional Pyramid Wavelet")) { + if (keyFile.has_key ("Directional Pyramid Wavelet", "Enabled")) { dirpyrequalizer.enabled = keyFile.get_boolean ("Directional Pyramid Wavelet", "Enabled"); if (pedited) pedited->dirpyrequalizer.enabled = true; } + if (keyFile.has_key ("Directional Pyramid Wavelet", "Gamutlab")) { dirpyrequalizer.gamutlab = keyFile.get_boolean ("Directional Pyramid Wavelet", "Gamutlab"); if (pedited) pedited->dirpyrequalizer.gamutlab = true; } + // if (keyFile.has_key ("Directional Pyramid Wavelet", "Algorithm")) { dirpyrequalizer.algo = keyFile.get_string ("Directional Pyramid Wavelet", "Algorithm"); if (pedited) pedited->dirpyrequalizer.algo = true; } + if (keyFile.has_key ("Directional Pyramid Wavelet", "Hueskin")) { + Glib::ArrayHandle thresh = keyFile.get_integer_list ("Directional Pyramid Wavelet", "Hueskin"); dirpyrequalizer.hueskin.setValues(thresh.data()[0], thresh.data()[1], min(thresh.data()[2], 300), min(thresh.data()[3], 300)); if (pedited) pedited->dirpyrequalizer.hueskin = true; } @@ -2149,22 +2384,22 @@ if (keyFile.has_group ("Directional Pyramid Equalizer")) { for(int i = 0; i < 5; i ++) { std::stringstream ss; ss << "Mult" << i; - if(keyFile.has_key ("Directional Pyramid Equalizer", ss.str())) { - if(i==4) { dirpyrequalizer.threshold = keyFile.get_double ("Directional Pyramid Equalizer", ss.str()); if (pedited) pedited->dirpyrequalizer.threshold = true; } - else { dirpyrequalizer.mult[i] = keyFile.get_double ("Directional Pyramid Equalizer", ss.str()); if (pedited) pedited->dirpyrequalizer.mult[i] = true; } + if(keyFile.has_key ("Directional Pyramid Wavelet", ss.str())) { + if(i==4) { dirpyrequalizer.threshold = keyFile.get_double ("Directional Pyramid Wavelet", ss.str()); if (pedited) pedited->dirpyrequalizer.threshold = true; } + else { dirpyrequalizer.mult[i] = keyFile.get_double ("Directional Pyramid Wavelet", ss.str()); if (pedited) pedited->dirpyrequalizer.mult[i] = true; } } } dirpyrequalizer.mult[4] = 1.0; } else { - // 5 level equalizer + dedicated threshold parameter - for(int i = 0; i < 5; i ++) { + // 5 level wavelet + dedicated threshold parameter + for(int i = 0; i < 6; i ++) { std::stringstream ss; ss << "Mult" << i; - if(keyFile.has_key ("Directional Pyramid Equalizer", ss.str())) { dirpyrequalizer.mult[i] = keyFile.get_double ("Directional Pyramid Equalizer", ss.str()); if (pedited) pedited->dirpyrequalizer.mult[i] = true; } + if(keyFile.has_key ("Directional Pyramid Wavelet", ss.str())) { dirpyrequalizer.mult[i] = keyFile.get_double ("Directional Pyramid Wavelet", ss.str()); if (pedited) pedited->dirpyrequalizer.mult[i] = true; } } - if(keyFile.has_key ("Directional Pyramid Equalizer", "Threshold")) { dirpyrequalizer.threshold = keyFile.get_double ("Directional Pyramid Equalizer", "Threshold"); if (pedited) pedited->dirpyrequalizer.threshold = true; } - if(keyFile.has_key ("Directional Pyramid Equalizer", "Skinprotect")) { dirpyrequalizer.skinprotect = keyFile.get_double ("Directional Pyramid Equalizer", "Skinprotect"); if (pedited) pedited->dirpyrequalizer.skinprotect = true; } + if(keyFile.has_key ("Directional Pyramid Wavelet", "Threshold")) { dirpyrequalizer.threshold = keyFile.get_double ("Directional Pyramid Wavelet", "Threshold"); if (pedited) pedited->dirpyrequalizer.threshold = true; } + if(keyFile.has_key ("Directional Pyramid Wavelet", "Skinprotect")) { dirpyrequalizer.skinprotect = keyFile.get_double ("Directional Pyramid Wavelet", "Skinprotect"); if (pedited) pedited->dirpyrequalizer.skinprotect = true; } } } @@ -2182,12 +2417,12 @@ if ( keyFile.has_group( "Film Simulation" ) ) } } - // load HSV equalizer parameters -if (keyFile.has_group ("HSV Equalizer")) { + // load HSV wavelet parameters +if (keyFile.has_group ("HSV Wavelet")) { if (ppVersion>=300) { - if (keyFile.has_key ("HSV Equalizer", "HCurve")) { hsvequalizer.hcurve = keyFile.get_double_list ("HSV Equalizer", "HCurve"); if (pedited) pedited->hsvequalizer.hcurve = true; } - if (keyFile.has_key ("HSV Equalizer", "SCurve")) { hsvequalizer.scurve = keyFile.get_double_list ("HSV Equalizer", "SCurve"); if (pedited) pedited->hsvequalizer.scurve = true; } - if (keyFile.has_key ("HSV Equalizer", "VCurve")) { hsvequalizer.vcurve = keyFile.get_double_list ("HSV Equalizer", "VCurve"); if (pedited) pedited->hsvequalizer.vcurve = true; } + if (keyFile.has_key ("HSV Wavelet", "HCurve")) { hsvequalizer.hcurve = keyFile.get_double_list ("HSV Wavelet", "HCurve"); if (pedited) pedited->hsvequalizer.hcurve = true; } + if (keyFile.has_key ("HSV Wavelet", "SCurve")) { hsvequalizer.scurve = keyFile.get_double_list ("HSV Wavelet", "SCurve"); if (pedited) pedited->hsvequalizer.scurve = true; } + if (keyFile.has_key ("HSV Wavelet", "VCurve")) { hsvequalizer.vcurve = keyFile.get_double_list ("HSV Wavelet", "VCurve"); if (pedited) pedited->hsvequalizer.vcurve = true; } } } @@ -2364,11 +2599,24 @@ if (keyFile.has_group ("IPTC")) { const Glib::ustring ColorManagementParams::NoICMString = Glib::ustring("No ICM: sRGB output"); +bool operator==(const WaveletParams & a, const WaveletParams & b) { + if(a.enabled != b.enabled) + return false; + + for(int i = 0; i < 9; i++) { + if(a.c[i] != b.c[i]) + return false; + } + return true; +} + + + bool operator==(const DirPyrEqualizerParams & a, const DirPyrEqualizerParams & b) { if(a.enabled != b.enabled) return false; - for(int i = 0; i < 5; i++) { + for(int i = 0; i < 6; i++) { if(a.mult[i] != b.mult[i]) return false; } @@ -2641,6 +2889,38 @@ bool ProcParams::operator== (const ProcParams& other) { && icm.freegamma == other.icm.freegamma && icm.gampos == other.icm.gampos && icm.slpos == other.icm.slpos + && wavelet == other.wavelet + && wavelet.Lmethod == other.wavelet.Lmethod + && wavelet.CLmethod == other.wavelet.CLmethod + && wavelet.Tilesmethod == other.wavelet.Tilesmethod + && wavelet.CHmethod == other.wavelet.CHmethod + && wavelet.HSmethod == other.wavelet.HSmethod + && wavelet.Dirmethod == other.wavelet.Dirmethod + && wavelet.tiles == other.wavelet.tiles + && wavelet.rescon == other.wavelet.rescon + && wavelet.resconH == other.wavelet.resconH + && wavelet.reschro == other.wavelet.reschro + && wavelet.sup == other.wavelet.sup + && wavelet.sky == other.wavelet.sky + && wavelet.thres == other.wavelet.thres + && wavelet.threshold == other.wavelet.threshold + && wavelet.chroma == other.wavelet.chroma + && wavelet.chro == other.wavelet.chro + && wavelet.unif == other.wavelet.unif + && wavelet.thr == other.wavelet.thr + && wavelet.thrH == other.wavelet.thrH + && wavelet.threshold == other.wavelet.threshold + && wavelet.threshold2 == other.wavelet.threshold2 + && wavelet.hueskin == other.wavelet.hueskin + && wavelet.hueskin2 == other.wavelet.hueskin2 + && wavelet.hllev == other.wavelet.hllev + && wavelet.bllev == other.wavelet.bllev + && wavelet.pastlev == other.wavelet.pastlev + && wavelet.satlev == other.wavelet.satlev + && wavelet.opacityCurveRG == other.wavelet.opacityCurveRG + && wavelet.opacityCurveBY == other.wavelet.opacityCurveBY + && wavelet.clvcurve == other.wavelet.clvcurve + && wavelet.skinprotect == other.wavelet.skinprotect && dirpyrequalizer == other.dirpyrequalizer // && dirpyrequalizer.algo == other.dirpyrequalizer.algo && dirpyrequalizer.hueskin == other.dirpyrequalizer.hueskin diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 95751ffc4..be190ad6f 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -33,6 +33,9 @@ namespace rtengine { class ColorGradientCurve; class OpacityCurve; class NoiseCurve; +class WavCurve; +class WavOpacityCurveRG; +class WavOpacityCurveBY; namespace procparams { @@ -47,7 +50,6 @@ class Threshold { #ifndef NDEBUG unsigned int part[5]; #endif - public: Threshold (T bottom, T top, bool startAtOne) { initEq1 = startAtOne; @@ -218,6 +220,7 @@ class ToneCurveParams { static bool HLReconstructionNecessary(LUTu &histRedRaw, LUTu &histGreenRaw, LUTu &histBlueRaw); }; + /** * Parameters of the luminance curve */ @@ -849,6 +852,57 @@ typedef std::map ExifPairs; */ typedef std::map > IPTCPairs; + +class WaveletParams { + + public: + std::vector clvcurve; + std::vector opacityCurveRG; + std::vector opacityCurveBY; + bool enabled; + bool display; + bool median; + bool avoid; + int c[9]; + Glib::ustring Lmethod; + Glib::ustring CLmethod; + Glib::ustring Tilesmethod; + Glib::ustring CHmethod; + Glib::ustring Dirmethod; + Glib::ustring HSmethod; + int tiles; + int rescon; + int resconH; + int reschro; + int sup; + double sky; + int thres; + int chroma; + int chro; + int threshold; + int threshold2; + int unif; + int thr; + int thrH; + double skinprotect; + Threshold hueskin; + Threshold hueskin2; + Threshold hllev; + Threshold bllev; + Threshold pastlev; + Threshold satlev; + + + WaveletParams (); + void setDefaults(); + void getCurves(WavCurve &cCurve,WavOpacityCurveRG &opacityCurveLUTRG , WavOpacityCurveBY &opacityCurveLUTBY) const; + static void getDefaultCLVCurve(std::vector &curve); + static void getDefaultOpacityCurveRG(std::vector &curve); + static void getDefaultOpacityCurveBY(std::vector &curve); + +}; + + /** * Directional pyramid equalizer params */ @@ -857,7 +911,7 @@ class DirPyrEqualizerParams { public: bool enabled; bool gamutlab; - double mult[5]; + double mult[6]; double threshold; double skinprotect; Threshold hueskin; @@ -1023,8 +1077,9 @@ class ProcParams { ResizeParams resize; ///< Resize parameters ColorManagementParams icm; ///< profiles/color spaces used during the image processing RAWParams raw; ///< RAW parameters before demosaicing - DirPyrEqualizerParams dirpyrequalizer; ///< directional pyramid equalizer parameters - HSVEqualizerParams hsvequalizer; ///< hsv equalizer parameters + WaveletParams wavelet; ///< wavelet wavelet parameters + DirPyrEqualizerParams dirpyrequalizer; ///< directional pyramid wavelet parameters + HSVEqualizerParams hsvequalizer; ///< hsv wavelet parameters FilmSimulationParams filmSimulation; ///< film simulation parameters char rank; ///< Custom image quality ranking char colorlabel; ///< Custom color label diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 0542e4356..16fce5218 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -324,8 +324,41 @@ ALLNORAW, //EvDPDNCCCurve ALLNORAW, //EvDPDNautochroma ALLNORAW, // EvDPDNLmet ALLNORAW, // EvDPDNCmet -ALLNORAW // EvDPDNC2met - +ALLNORAW, // EvDPDNC2met +DIRPYREQUALIZER, // EvWavelet +DIRPYREQUALIZER, // EvEnabled +DIRPYREQUALIZER, // EvWavLmethod +DIRPYREQUALIZER, // EvWavCLmethod +DIRPYREQUALIZER, // EvWavDirmethod +DIRPYREQUALIZER, // EvWavtiles +DIRPYREQUALIZER, // EvWavsky +DIRPYREQUALIZER, // EvWavthres +DIRPYREQUALIZER, // EvWavthr +DIRPYREQUALIZER, // EvWavchroma +DIRPYREQUALIZER, // EvWavmedian +DIRPYREQUALIZER, // EvWavunif +DIRPYREQUALIZER, // EvWavSkin +DIRPYREQUALIZER, // EvWavHueSkin +DIRPYREQUALIZER, // EvWavThreshold +DIRPYREQUALIZER, // EvWavlhl +DIRPYREQUALIZER, // EvWavbhl +DIRPYREQUALIZER, // EvWavThresHold2 +DIRPYREQUALIZER, // EvWavavoid +DIRPYREQUALIZER, // EvWavCLVCurve +DIRPYREQUALIZER, // EvWavpast +DIRPYREQUALIZER, // EvWavsat +DIRPYREQUALIZER, // EvWavCHmet +DIRPYREQUALIZER, // EvWavHSmet +DIRPYREQUALIZER, // EvWavchro +DIRPYREQUALIZER, // EvWavColor +DIRPYREQUALIZER, // EvWavOpac +DIRPYREQUALIZER, // EvWavsup +DIRPYREQUALIZER, // EvWavTilesmet +DIRPYREQUALIZER, // EvWavrescon +DIRPYREQUALIZER, // EvWavreschro +DIRPYREQUALIZER, // EvWavresconH +DIRPYREQUALIZER, // EvWavthrH +DIRPYREQUALIZER // EvWavHueskin2 }; diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 5ce79c3ae..dbd54063d 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -282,6 +282,13 @@ namespace rtengine { virtual void BWChanged (double redbw, double greenbw, double bluebw) {} }; + + class WaveletListener { + public : + virtual ~WaveletListener() {} + virtual void wavChanged (double nlevel) {} + + }; /** This class represents a detailed part of the image (looking through a kind of window). @@ -373,6 +380,7 @@ namespace rtengine { virtual void setAutoBWListener (AutoBWListener* l) =0; virtual void setAutoColorTonListener (AutoColorTonListener* l) =0; virtual void setAutoChromaListener (AutoChromaListener* l) =0; + virtual void setWaveletListener (WaveletListener* l) =0; virtual ~StagedImageProcessor () {} diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 75f4ea147..84b4877cf 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -22,7 +22,7 @@ #include "improcfun.h" #include "curves.h" #include "iccstore.h" -#include "clutstore.h" +#include "clutstore.h" #include "processingjob.h" #include #include "../rtgui/options.h" @@ -676,7 +676,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // if clut was used and size of clut cache == 1 we free the memory used by the clutstore (default clut cache size = 1 for 32 bit OS) if ( params.filmSimulation.enabled && !params.filmSimulation.clutFilename.empty() && options.clutCacheSize == 1) - clutStore.clearCache(); + clutStore.clearCache(); // freeing up some memory customToneCurve1.Reset(); @@ -775,9 +775,19 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p delete [] buffer[i]; delete [] buffer; } - // directional pyramid equalizer - if((params.colorappearance.enabled && !settings->autocielab) || !params.colorappearance.enabled) ipf.dirpyrequalizer (labView, 1);//TODO: this is the luminance tonecurve, not the RGB one + WaveletParams WaveParams = params.wavelet; + WavCurve wavCLVCurve; + WavOpacityCurveRG waOpacityCurveRG; + WavOpacityCurveBY waOpacityCurveBY; + params.wavelet.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY); + + // directional pyramid wavelet + if((params.colorappearance.enabled && !settings->autocielab) || !params.colorappearance.enabled) ipf.dirpyrequalizer (labView, 1);//TODO: this is the luminance tonecurve, not the RGB one + int kall=2; + if((params.wavelet.enabled)) ipf.ip_wavelet(labView, labView, kall, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, 1); + wavCLVCurve.Reset(); + //Colorappearance and tone-mapping associated int f_w=1,f_h=1; diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index e394c6626..ce5e10cc2 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -27,7 +27,7 @@ set (BASESOURCEFILES batchqueuebuttonset.cc browserfilter.cc exiffiltersettings.cc profilestore.cc partialpastedlg.cc sensorbayer.cc sensorxtrans.cc preprocess.cc bayerpreprocess.cc bayerprocess.cc bayerrawexposure.cc xtransprocess.cc xtransrawexposure.cc - darkframe.cc flatfield.cc rawcacorrection.cc rawexposure.cc + darkframe.cc flatfield.cc rawcacorrection.cc rawexposure.cc wavelet.cc dirpyrequalizer.cc hsvequalizer.cc defringe.cc popupcommon.cc popupbutton.cc popuptogglebutton.cc sharpenedge.cc sharpenmicro.cc colorappearance.cc filmsimulation.cc) diff --git a/rtgui/addsetids.h b/rtgui/addsetids.h index 74a49b747..94443e042 100644 --- a/rtgui/addsetids.h +++ b/rtgui/addsetids.h @@ -85,8 +85,21 @@ #define ADDSET_DIRPYRDN_PASSES 77 #define ADDSET_RAWFFCLIPCONTROL 78 #define ADDSET_FILMSIMULATION_STRENGTH 79 - +#define ADDSET_WA 80 +#define ADDSET_WA_SKINPROTECT 81 +#define ADDSET_WA_THRR 82 +#define ADDSET_WA_THRRH 83 +#define ADDSET_WA_THRES 84 +#define ADDSET_WA_THRESHOLD 85 +#define ADDSET_WA_THRESHOLD2 86 +#define ADDSET_WA_CHRO 87 +#define ADDSET_WA_CHROMA 88 +#define ADDSET_WA_UNIF 89 +#define ADDSET_WA_RESCON 90 +#define ADDSET_WA_RESCONH 91 +#define ADDSET_WA_RESCHRO 92 +#define ADDSET_WA_SKYPROTECT 93 // When adding items, make sure to update ADDSET_PARAM_NUM -#define ADDSET_PARAM_NUM 80 // THIS IS USED AS A DELIMITER!! +#define ADDSET_PARAM_NUM 94 // THIS IS USED AS A DELIMITER!! #endif diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 5663a257b..c6a46146a 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -148,6 +148,7 @@ void BatchToolPanelCoordinator::initSession () { shadowshighlights->setAdjusterBehavior (false, false, false); dirpyrequalizer->setAdjusterBehavior (false, false, false); + wavelet->setAdjusterBehavior (false, false, false,false,false,false,false,false,false,false,false,false,false,false); dirpyrdenoise->setAdjusterBehavior (false, false,false,false,false,false, false); bayerpreprocess->setAdjusterBehavior (false, false); rawcacorrection->setAdjusterBehavior (false); @@ -185,6 +186,7 @@ void BatchToolPanelCoordinator::initSession () { blackwhite->setAdjusterBehavior (options.baBehav[ADDSET_BLACKWHITE_HUES],options.baBehav[ADDSET_BLACKWHITE_GAMMA]); shadowshighlights->setAdjusterBehavior (options.baBehav[ADDSET_SH_HIGHLIGHTS], options.baBehav[ADDSET_SH_SHADOWS], options.baBehav[ADDSET_SH_LOCALCONTRAST]); dirpyrequalizer->setAdjusterBehavior (options.baBehav[ADDSET_DIRPYREQ], options.baBehav[ADDSET_DIRPYREQ_THRESHOLD], options.baBehav[ADDSET_DIRPYREQ_SKINPROTECT]); + wavelet->setAdjusterBehavior (options.baBehav[ADDSET_WA], options.baBehav[ADDSET_WA_THRESHOLD], options.baBehav[ADDSET_WA_THRESHOLD2],options.baBehav[ADDSET_WA_THRES],options.baBehav[ADDSET_WA_CHRO],options.baBehav[ADDSET_WA_CHROMA],options.baBehav[ADDSET_WA_UNIF],options.baBehav[ADDSET_WA_SKINPROTECT],options.baBehav[ADDSET_WA_RESCHRO],options.baBehav[ADDSET_WA_RESCON],options.baBehav[ADDSET_WA_RESCONH],options.baBehav[ADDSET_WA_THRR],options.baBehav[ADDSET_WA_THRRH],options.baBehav[ADDSET_WA_SKYPROTECT] ); dirpyrdenoise->setAdjusterBehavior (options.baBehav[ADDSET_DIRPYRDN_LUMA],options.baBehav[ADDSET_DIRPYRDN_LUMDET],options.baBehav[ADDSET_DIRPYRDN_CHROMA],options.baBehav[ADDSET_DIRPYRDN_CHROMARED],options.baBehav[ADDSET_DIRPYRDN_CHROMABLUE], options.baBehav[ADDSET_DIRPYRDN_GAMMA], options.baBehav[ADDSET_DIRPYRDN_PASSES]); bayerpreprocess->setAdjusterBehavior (options.baBehav[ADDSET_PREPROCESS_LINEDENOISE], options.baBehav[ADDSET_PREPROCESS_GREENEQUIL]); rawcacorrection->setAdjusterBehavior (options.baBehav[ADDSET_RAWCACORR]); @@ -281,10 +283,25 @@ void BatchToolPanelCoordinator::initSession () { if (options.baBehav[ADDSET_VIGN_CENTER]) pparams.vignetting.centerX = 0; if (options.baBehav[ADDSET_VIGN_CENTER]) pparams.vignetting.centerY = 0; - if (options.baBehav[ADDSET_DIRPYREQ]) for (int i=0; i<5; i++) pparams.dirpyrequalizer.mult[i] = 0; + if (options.baBehav[ADDSET_DIRPYREQ]) for (int i=0; i<6; i++) pparams.dirpyrequalizer.mult[i] = 0; if (options.baBehav[ADDSET_DIRPYREQ_THRESHOLD]) pparams.dirpyrequalizer.threshold = 0; if (options.baBehav[ADDSET_DIRPYREQ_SKINPROTECT]) pparams.dirpyrequalizer.skinprotect = 0; + if (options.baBehav[ADDSET_WA]) for (int i=0; i<8; i++) pparams.wavelet.c[i] = 0; + if (options.baBehav[ADDSET_WA_THRESHOLD]) pparams.wavelet.threshold = 0; + if (options.baBehav[ADDSET_WA_THRESHOLD2]) pparams.wavelet.threshold2 = 0; + if (options.baBehav[ADDSET_WA_SKINPROTECT]) pparams.wavelet.skinprotect = 0; + if (options.baBehav[ADDSET_WA_CHRO]) pparams.wavelet.chro = 0; + if (options.baBehav[ADDSET_WA_CHROMA]) pparams.wavelet.chroma = 0; + if (options.baBehav[ADDSET_WA_UNIF]) pparams.wavelet.unif = 0; + if (options.baBehav[ADDSET_WA_THRES]) pparams.wavelet.thres = 0; + if (options.baBehav[ADDSET_WA_RESCON]) pparams.wavelet.rescon = 0; + if (options.baBehav[ADDSET_WA_RESCONH]) pparams.wavelet.resconH = 0; + if (options.baBehav[ADDSET_WA_RESCHRO]) pparams.wavelet.reschro = 0; + if (options.baBehav[ADDSET_WA_THRR]) pparams.wavelet.thr = 0; + if (options.baBehav[ADDSET_WA_THRRH]) pparams.wavelet.thrH = 0; + if (options.baBehav[ADDSET_WA_SKYPROTECT]) pparams.wavelet.sky = 0; + if (options.baBehav[ADDSET_DIRPYRDN_LUMA]) pparams.dirpyrDenoise.luma = 0; if (options.baBehav[ADDSET_DIRPYRDN_CHROMA]) pparams.dirpyrDenoise.chroma = 0; diff --git a/rtgui/dirpyrequalizer.cc b/rtgui/dirpyrequalizer.cc index 7bed81aaf..67ea468fa 100644 --- a/rtgui/dirpyrequalizer.cc +++ b/rtgui/dirpyrequalizer.cc @@ -68,12 +68,12 @@ DirPyrEqualizer::DirPyrEqualizer () : FoldableToolPanel(this) { Gtk::HSeparator *separator2 = Gtk::manage (new Gtk::HSeparator()); pack_start(*separator2, Gtk::PACK_SHRINK, 2); - for(int i = 0; i < 5; i++) + for(int i = 0; i < 6; i++) { Glib::ustring ss; ss = Glib::ustring::format(i); if (i == 0) ss += Glib::ustring::compose(" (%1)", M("TP_DIRPYREQUALIZER_LUMAFINEST")); - else if(i == 4) ss += Glib::ustring::compose(" (%1)", M("TP_DIRPYREQUALIZER_LUMACOARSEST")); + else if(i == 5) ss += Glib::ustring::compose(" (%1)", M("TP_DIRPYREQUALIZER_LUMACOARSEST")); multiplier[i] = Gtk::manage ( new Adjuster (ss, 0, 4, 0.01, 1.0) ); multiplier[i]->setAdjusterListener(this); pack_start(*multiplier[i]); @@ -141,7 +141,7 @@ void DirPyrEqualizer::read (const ProcParams* pp, const ParamsEdited* pedited) { enabled->set_inconsistent (!pedited->dirpyrequalizer.enabled); gamutlab->set_inconsistent (!pedited->dirpyrequalizer.gamutlab); - for(int i = 0; i < 5; i++) { + for(int i = 0; i < 6; i++) { multiplier[i]->setEditedState (pedited->dirpyrequalizer.mult[i] ? Edited : UnEdited); } threshold->setEditedState (pedited->dirpyrequalizer.threshold ? Edited : UnEdited); @@ -169,7 +169,7 @@ void DirPyrEqualizer::read (const ProcParams* pp, const ParamsEdited* pedited) { gamutlabConn.block (false); lastgamutlab = pp->dirpyrequalizer.gamutlab; - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 6; i++) { multiplier[i]->setValue(pp->dirpyrequalizer.mult[i]); } threshold->setValue(pp->dirpyrequalizer.threshold); @@ -185,7 +185,7 @@ void DirPyrEqualizer::write (ProcParams* pp, ParamsEdited* pedited) { pp->dirpyrequalizer.gamutlab = gamutlab->get_active (); pp->dirpyrequalizer.hueskin = hueskin->getValue (); - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 6; i++) { pp->dirpyrequalizer.mult[i] = multiplier[i]->getValue(); } pp->dirpyrequalizer.threshold = threshold->getValue(); @@ -196,7 +196,7 @@ void DirPyrEqualizer::write (ProcParams* pp, ParamsEdited* pedited) { pedited->dirpyrequalizer.enabled = !enabled->get_inconsistent(); pedited->dirpyrequalizer.hueskin = hueskin->getEditedState (); - for(int i = 0; i < 5; i++) { + for(int i = 0; i < 6; i++) { pedited->dirpyrequalizer.mult[i] = multiplier[i]->getEditedState(); } pedited->dirpyrequalizer.threshold = threshold->getEditedState(); @@ -217,14 +217,14 @@ void DirPyrEqualizer::algoChanged () { */ void DirPyrEqualizer::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 6; i++) { multiplier[i]->setDefault(defParams->dirpyrequalizer.mult[i]); } threshold->setDefault(defParams->dirpyrequalizer.threshold); hueskin->setDefault (defParams->dirpyrequalizer.hueskin); if (pedited) { - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 6; i++) { multiplier[i]->setDefaultEditedState(pedited->dirpyrequalizer.mult[i] ? Edited : UnEdited); } threshold->setDefaultEditedState(pedited->dirpyrequalizer.threshold ? Edited : UnEdited); @@ -232,7 +232,7 @@ void DirPyrEqualizer::setDefaults (const ProcParams* defParams, const ParamsEdit hueskin->setDefaultEditedState (pedited->dirpyrequalizer.hueskin ? Edited : UnEdited); } else { - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 6; i++) { multiplier[i]->setDefaultEditedState(Irrelevant); } threshold->setDefaultEditedState(Irrelevant); @@ -252,7 +252,7 @@ void DirPyrEqualizer::setBatchMode (bool batchMode) { ToolPanel::setBatchMode (batchMode); - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 6; i++) { multiplier[i]->showEditedCB(); } threshold->showEditedCB(); @@ -278,12 +278,13 @@ void DirPyrEqualizer::adjusterChanged (Adjuster* a, double newval) { } else { listener->panelChanged (EvDirPyrEqualizer, - Glib::ustring::compose("%1, %2, %3, %4, %5", + Glib::ustring::compose("%1, %2, %3, %4, %5, %6", Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[0]->getValue()), Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[1]->getValue()), Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[2]->getValue()), Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[3]->getValue()), - Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[4]->getValue())) + Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[4]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[5]->getValue())) ); } } @@ -337,7 +338,7 @@ void DirPyrEqualizer::gamutlabToggled () { void DirPyrEqualizer::lumaneutralPressed () { - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 6; i++) { multiplier[i]->setValue(1.0); adjusterChanged(multiplier[i], 1.0); } @@ -346,8 +347,8 @@ void DirPyrEqualizer::lumaneutralPressed () { void DirPyrEqualizer::lumacontrastPlusPressed () { - for (int i = 0; i < 5; i++) { - float inc = 0.05 * (5 - i); + for (int i = 0; i < 6; i++) { + float inc = 0.05 * (6 - i); multiplier[i]->setValue(multiplier[i]->getValue() + inc); adjusterChanged(multiplier[i], multiplier[i]->getValue()); } @@ -356,8 +357,8 @@ void DirPyrEqualizer::lumacontrastPlusPressed () { void DirPyrEqualizer::lumacontrastMinusPressed () { - for (int i = 0; i < 5; i++) { - float inc = -0.05 * (5 - i); + for (int i = 0; i < 6; i++) { + float inc = -0.05 * (6 - i); multiplier[i]->setValue(multiplier[i]->getValue() + inc); adjusterChanged(multiplier[i], multiplier[i]->getValue()); } @@ -365,7 +366,7 @@ void DirPyrEqualizer::lumacontrastMinusPressed () { void DirPyrEqualizer::setAdjusterBehavior (bool multiplieradd, bool thresholdadd, bool skinadd) { - for (int i=0; i<5; i++) + for (int i=0; i<6; i++) multiplier[i]->setAddMode(multiplieradd); threshold->setAddMode(thresholdadd); skinprotect->setAddMode(skinadd); @@ -373,7 +374,7 @@ void DirPyrEqualizer::setAdjusterBehavior (bool multiplieradd, bool thresholdadd void DirPyrEqualizer::trimValues (rtengine::procparams::ProcParams* pp) { - for (int i=0; i<5; i++) + for (int i=0; i<6; i++) multiplier[i]->trimValue(pp->dirpyrequalizer.mult[i]); threshold->trimValue(pp->dirpyrequalizer.threshold); skinprotect->trimValue(pp->dirpyrequalizer.skinprotect); diff --git a/rtgui/dirpyrequalizer.h b/rtgui/dirpyrequalizer.h index 56c26724d..86a6b996a 100644 --- a/rtgui/dirpyrequalizer.h +++ b/rtgui/dirpyrequalizer.h @@ -33,7 +33,7 @@ protected: Gtk::CheckButton * enabled; Gtk::CheckButton * gamutlab; - Adjuster* multiplier[5]; + Adjuster* multiplier[6]; Adjuster* threshold; Adjuster* skinprotect; ThresholdAdjuster* hueskin; diff --git a/rtgui/exportpanel.cc b/rtgui/exportpanel.cc index 579fb1015..cb9c0f817 100644 --- a/rtgui/exportpanel.cc +++ b/rtgui/exportpanel.cc @@ -21,7 +21,7 @@ #include "multilangmgr.h" #include "options.h" #include "rtimage.h" - + using namespace rtengine; using namespace rtengine::procparams; @@ -49,6 +49,7 @@ ExportPanel::ExportPanel () : listener (NULL) { bypass_dirpyrDenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DIRPYRDENOISE"))); bypass_sh_hq = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SH_HQ"))); bypass_dirpyrequalizer = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DIRPYREQUALIZER"))); + bypass_wavelet = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_EQUALIZER"))); bypass_raw_ccSteps = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_CCSTEPS"))); bypass_raw_ca = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_CA"))); bypass_raw_df = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_DF"))); @@ -103,6 +104,7 @@ ExportPanel::ExportPanel () : listener (NULL) { pack_start(*bypass_dirpyrDenoise, Gtk::PACK_SHRINK, 4); pack_start(*bypass_sh_hq , Gtk::PACK_SHRINK, 4); pack_start(*bypass_dirpyrequalizer , Gtk::PACK_SHRINK, 4); + pack_start(*bypass_wavelet , Gtk::PACK_SHRINK, 4); bayerFrameVBox->pack_start(*hb_raw_bayer_method, Gtk::PACK_SHRINK, 4); //bayerFrameVBox->pack_start(*bypass_raw_all_enhance , Gtk::PACK_SHRINK, 4); @@ -190,6 +192,7 @@ ExportPanel::ExportPanel () : listener (NULL) { bypass_dirpyrDenoiseConn = bypass_dirpyrDenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); bypass_sh_hqConn = bypass_sh_hq->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); bypass_dirpyrequalizerConn = bypass_dirpyrequalizer->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); + bypass_waveletConn = bypass_wavelet->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); //bypass_raw_all_enhanceConn = bypass_raw_bayer_all_enhance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); bypass_raw_bayer_dcb_iterationsConn = bypass_raw_bayer_dcb_iterations->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); bypass_raw_bayer_dcb_enhanceConn = bypass_raw_bayer_dcb_enhance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true)); @@ -230,6 +233,7 @@ void ExportPanel::SaveSettingsAsDefault(){ options.fastexport_bypass_dirpyrDenoise = bypass_dirpyrDenoise->get_active (); options.fastexport_bypass_sh_hq = bypass_sh_hq->get_active (); options.fastexport_bypass_dirpyrequalizer = bypass_dirpyrequalizer->get_active (); + options.fastexport_bypass_wavelet = bypass_wavelet->get_active (); //options.fastexport_bypass_raw_bayer_all_enhance = bypass_raw_all_enhance->get_active (); options.fastexport_bypass_raw_bayer_dcb_iterations = bypass_raw_bayer_dcb_iterations->get_active (); options.fastexport_bypass_raw_bayer_dcb_enhance = bypass_raw_bayer_dcb_enhance->get_active (); @@ -289,6 +293,7 @@ void ExportPanel::LoadDefaultSettings(){ bypass_dirpyrDenoise->set_active (options.fastexport_bypass_dirpyrDenoise ); bypass_sh_hq->set_active (options.fastexport_bypass_sh_hq ); bypass_dirpyrequalizer->set_active (options.fastexport_bypass_dirpyrequalizer ); + bypass_wavelet->set_active (options.fastexport_bypass_wavelet ); //bypass_raw_bayer_all_enhance->set_active (options.fastexport_bypass_raw_bayer_all_enhance ); bypass_raw_bayer_dcb_iterations->set_active (options.fastexport_bypass_raw_bayer_dcb_iterations ); bypass_raw_bayer_dcb_enhance->set_active (options.fastexport_bypass_raw_bayer_dcb_enhance ); @@ -367,6 +372,7 @@ void ExportPanel::bypassALL_Toggled(){ bypass_dirpyrDenoiseConn.block (true); bypass_sh_hqConn.block (true); bypass_dirpyrequalizerConn.block (true); + bypass_waveletConn.block (true); //bypass_raw_bayer_all_enhanceConn.block (true); bypass_raw_bayer_dcb_iterationsConn.block (true); bypass_raw_bayer_dcb_enhanceConn.block (true); @@ -389,6 +395,7 @@ void ExportPanel::bypassALL_Toggled(){ bypass_dirpyrDenoise->set_active(bypass_ALL->get_active()); bypass_sh_hq->set_active(bypass_ALL->get_active()); bypass_dirpyrequalizer->set_active(bypass_ALL->get_active()); + bypass_wavelet->set_active(bypass_ALL->get_active()); //bypass_raw_bayer_all_enhance->set_active(bypass_ALL->get_active()); bypass_raw_bayer_dcb_iterations->set_active(bypass_ALL->get_active()); bypass_raw_bayer_dcb_enhance->set_active(bypass_ALL->get_active()); @@ -409,6 +416,7 @@ void ExportPanel::bypassALL_Toggled(){ bypass_dirpyrDenoiseConn.block (false); bypass_sh_hqConn.block (false); bypass_dirpyrequalizerConn.block (false); + bypass_waveletConn.block (false); //bypass_raw_bayer_all_enhanceConn.block (false); bypass_raw_bayer_dcb_iterationsConn.block (false); bypass_raw_bayer_dcb_enhanceConn.block (false); diff --git a/rtgui/exportpanel.h b/rtgui/exportpanel.h index cea3f0db5..1e58d66bf 100644 --- a/rtgui/exportpanel.h +++ b/rtgui/exportpanel.h @@ -19,7 +19,7 @@ */ #ifndef _EXPORTPANEL_ #define _EXPORTPANEL_ - + #include #include "guiutils.h" #include "adjuster.h" @@ -52,6 +52,7 @@ class ExportPanel : public Gtk::VBox { */ Gtk::CheckButton* bypass_dirpyrequalizer; // also could leave untouched but disable only small radius adjustments //Gtk::CheckButton* bypass_raw_all_enhance; + Gtk::CheckButton* bypass_wavelet; // also could leave untouched but disable only small radius adjustments MyComboBoxText* raw_bayer_method; @@ -88,6 +89,7 @@ class ExportPanel : public Gtk::VBox { sigc::connection bypass_dirpyrDenoiseConn ; sigc::connection bypass_sh_hqConn ; sigc::connection bypass_dirpyrequalizerConn ; + sigc::connection bypass_waveletConn ; //sigc::connection bypass_raw_bayer_all_enhanceConn ; sigc::connection bypass_raw_bayer_dcb_iterationsConn ; sigc::connection bypass_raw_bayer_dcb_enhanceConn ; diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index c48537db9..5722bd271 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -21,7 +21,7 @@ #include #include #include "../rtengine/rt_math.h" - + #include "filecatalog.h" #include "filepanel.h" #include "options.h" @@ -924,6 +924,7 @@ void FileCatalog::developRequested (std::vector tbe, bool fas if (options.fastexport_bypass_dirpyrDenoise ) params.dirpyrDenoise.enabled = false; if (options.fastexport_bypass_sh_hq ) params.sh.hq = false; if (options.fastexport_bypass_dirpyrequalizer ) params.dirpyrequalizer.enabled = false; + if (options.fastexport_bypass_wavelet ) params.wavelet.enabled = false; //if (options.fastexport_bypass_raw_bayer_all_enhance ) params.raw.bayersensor.all_enhance = false; if (options.fastexport_bypass_raw_bayer_dcb_iterations ) params.raw.bayersensor.dcb_iterations = 0; if (options.fastexport_bypass_raw_bayer_dcb_enhance ) params.raw.bayersensor.dcb_enhance = false; @@ -1014,9 +1015,9 @@ void FileCatalog::renameRequested (std::vector tbe) { else { success = true; if (!safe_g_rename (ofname, nfname)) { - cacheMgr->renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); + cacheMgr->renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); safe_g_remove(ofname + paramFileExtension); - reparseDirectory (); + reparseDirectory (); } } } @@ -1783,11 +1784,11 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) { bool ctrl = event->state & GDK_CONTROL_MASK; bool shift = event->state & GDK_SHIFT_MASK; - bool alt = event->state & GDK_MOD1_MASK; + bool alt = event->state & GDK_MOD1_MASK; #ifdef __WIN32__ - bool altgr = event->state & GDK_MOD2_MASK; -#else - bool altgr = event->state & GDK_MOD5_MASK; + bool altgr = event->state & GDK_MOD2_MASK; +#else + bool altgr = event->state & GDK_MOD5_MASK; #endif modifierKey = event->state; @@ -1816,8 +1817,8 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) { return true; } } - -#ifdef __WIN32__ + +#ifdef __WIN32__ if (!alt && !shift && !altgr) { // shift is reserved for ranking switch(event->hardware_keycode) { case 0x30: @@ -1886,8 +1887,8 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) { categoryButtonToggled(bRecentlySaved[1],false); return true; } - } -#else + } +#else if (!alt && !shift && !altgr) { // shift is reserved for ranking switch(event->hardware_keycode) { case 0x13: @@ -1956,7 +1957,7 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) { categoryButtonToggled(bRecentlySaved[1],false); return true; } - } + } #endif if (!ctrl && !alt) { switch(event->keyval) { diff --git a/rtgui/options.cc b/rtgui/options.cc index f350af0a4..8cb840a2e 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -25,13 +25,14 @@ #include "addsetids.h" #include "guiutils.h" #include "../rtengine/safegtk.h" -#include "version.h" - +#include "version.h" + #ifdef _OPENMP #include #endif + #ifdef WIN32 #include // for GCC32 @@ -153,6 +154,9 @@ void Options::updatePaths() { lastLabCurvesDir = preferredPath; if (lastDenoiseCurvesDir.empty() || !safe_file_test (lastDenoiseCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastDenoiseCurvesDir, Glib::FILE_TEST_IS_DIR)) lastDenoiseCurvesDir = preferredPath; + if (lastWaveletCurvesDir.empty() || !safe_file_test (lastWaveletCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastWaveletCurvesDir, Glib::FILE_TEST_IS_DIR)) + lastWaveletCurvesDir = preferredPath; + if (lastPFCurvesDir.empty() || !safe_file_test (lastPFCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastPFCurvesDir, Glib::FILE_TEST_IS_DIR)) lastPFCurvesDir = preferredPath; if (lastHsvCurvesDir.empty() || !safe_file_test (lastHsvCurvesDir, Glib::FILE_TEST_EXISTS) || !safe_file_test (lastHsvCurvesDir, Glib::FILE_TEST_IS_DIR)) @@ -358,10 +362,10 @@ void Options::setDefaults () { histogramBar = true; histogramFullMode = false; - rgbDenoiseThreadLimit = 0; -#if defined( _OPENMP ) && defined( __x86_64__ ) + rgbDenoiseThreadLimit = 0; +#if defined( _OPENMP ) && defined( __x86_64__ ) clutCacheSize = omp_get_num_procs(); -#else +#else clutCacheSize = 1; #endif filledProfile = false; @@ -388,6 +392,7 @@ void Options::setDefaults () { fastexport_bypass_dirpyrDenoise = true; fastexport_bypass_sh_hq = true; fastexport_bypass_dirpyrequalizer = true; + fastexport_bypass_wavelet = true; fastexport_raw_bayer_method = "fast"; //fastexport_bypass_raw_bayer_all_enhance = true; fastexport_bypass_raw_bayer_dcb_iterations = true; @@ -509,6 +514,21 @@ void Options::setDefaults () { 0, //ADDSET_DIRPYRDN_PASSES 0, // ADDSET_RAWFFCLIPCONTROL 0, // ADDSET_FILMSIMULATION_STRENGTH + 0, //ADDSET_WA + 0, //ADDSET_WA_THRESHOLD + 0, //ADDSET_WA_THRESHOLD2 + 0, //ADDSET_WA_THRES + 0, //ADDSET_WA_CHRO + 0, //ADDSET_WA_CHROMA + 0, //ADDSET_WA_UNIF + 0, //ADDSET_WA_SKINPROTECT + 0, //ADDSET_WA_RESCHRO + 0, //ADDSET_WA_RESCON + 0, //ADDSET_WA_RESCONH + 0, //ADDSET_WA_THRR + 0, //ADDSET_WA_THRRH + 0, //ADDSET_WA_SKYPROTECT + }; baBehav = std::vector (babehav, babehav+ADDSET_PARAM_NUM); @@ -583,6 +603,7 @@ void Options::setDefaults () { lastRgbCurvesDir = ""; lastLabCurvesDir = ""; lastDenoiseCurvesDir = ""; + lastWaveletCurvesDir = ""; lastPFCurvesDir = ""; lastHsvCurvesDir = ""; lastToneCurvesDir = ""; @@ -867,6 +888,7 @@ if (keyFile.has_group ("Fast Export")) { if (keyFile.has_key ("Fast Export", "fastexport_bypass_dirpyrDenoise" )) fastexport_bypass_dirpyrDenoise = keyFile.get_boolean ("Fast Export", "fastexport_bypass_dirpyrDenoise" ); if (keyFile.has_key ("Fast Export", "fastexport_bypass_sh_hq" )) fastexport_bypass_sh_hq = keyFile.get_boolean ("Fast Export", "fastexport_bypass_sh_hq" ); if (keyFile.has_key ("Fast Export", "fastexport_bypass_dirpyrequalizer" )) fastexport_bypass_dirpyrequalizer = keyFile.get_boolean ("Fast Export", "fastexport_bypass_dirpyrequalizer" ); + if (keyFile.has_key ("Fast Export", "fastexport_bypass_wavelet" )) fastexport_bypass_wavelet = keyFile.get_boolean ("Fast Export", "fastexport_bypass_wavelet" ); if (keyFile.has_key ("Fast Export", "fastexport_raw_dmethod" )) fastexport_raw_bayer_method = keyFile.get_string ("Fast Export", "fastexport_raw_dmethod" ); if (keyFile.has_key ("Fast Export", "fastexport_raw_bayer_method" )) fastexport_raw_bayer_method = keyFile.get_string ("Fast Export", "fastexport_raw_bayer_method" ); //if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_all_enhance" )) fastexport_bypass_raw_bayer_all_enhance = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_all_enhance" ); @@ -905,6 +927,7 @@ if (keyFile.has_group ("Dialogs")) { safeDirGet(keyFile, "Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir); safeDirGet(keyFile, "Dialogs", "LastLabCurvesDir", lastLabCurvesDir); safeDirGet(keyFile, "Dialogs", "LastDenoiseCurvesDir", lastDenoiseCurvesDir); + safeDirGet(keyFile, "Dialogs", "LastWaveletCurvesDir", lastWaveletCurvesDir); safeDirGet(keyFile, "Dialogs", "LastPFCurvesDir", lastPFCurvesDir); safeDirGet(keyFile, "Dialogs", "LastHsvCurvesDir", lastHsvCurvesDir); safeDirGet(keyFile, "Dialogs", "LastBWCurvesDir", lastBWCurvesDir); @@ -1180,6 +1203,7 @@ int Options::saveToFile (Glib::ustring fname) { keyFile.set_boolean ("Fast Export", "fastexport_bypass_dirpyrDenoise" , fastexport_bypass_dirpyrDenoise ); keyFile.set_boolean ("Fast Export", "fastexport_bypass_sh_hq" , fastexport_bypass_sh_hq ); keyFile.set_boolean ("Fast Export", "fastexport_bypass_dirpyrequalizer" , fastexport_bypass_dirpyrequalizer ); + keyFile.set_boolean ("Fast Export", "fastexport_bypass_wavelet" , fastexport_bypass_wavelet ); keyFile.set_string ("Fast Export", "fastexport_raw_bayer_method" , fastexport_raw_bayer_method ); //keyFile.set_boolean ("Fast Export", "fastexport_bypass_bayer_raw_all_enhance" , fastexport_bypass_raw_bayer_all_enhance ); keyFile.set_boolean ("Fast Export", "fastexport_bypass_raw_bayer_dcb_iterations" , fastexport_bypass_raw_bayer_dcb_iterations ); @@ -1210,6 +1234,7 @@ int Options::saveToFile (Glib::ustring fname) { keyFile.set_string ("Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir); keyFile.set_string ("Dialogs", "LastLabCurvesDir", lastLabCurvesDir); keyFile.set_string ("Dialogs", "LastDenoiseCurvesDir", lastDenoiseCurvesDir); + keyFile.set_string ("Dialogs", "LastWaveletCurvesDir", lastWaveletCurvesDir); keyFile.set_string ("Dialogs", "LastPFCurvesDir", lastPFCurvesDir); keyFile.set_string ("Dialogs", "LastHsvCurvesDir", lastHsvCurvesDir); keyFile.set_string ("Dialogs", "LastBWCurvesDir", lastBWCurvesDir); diff --git a/rtgui/options.h b/rtgui/options.h index c32f67730..97a1ec4be 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -37,7 +37,7 @@ #define DEFPROFILE_IMG "Neutral" // Profile name to use for internal values' profile #define DEFPROFILE_INTERNAL "Neutral" - + class SaveFormat { public: @@ -239,6 +239,7 @@ class Options { bool fastexport_bypass_dirpyrDenoise; bool fastexport_bypass_sh_hq; bool fastexport_bypass_dirpyrequalizer; + bool fastexport_bypass_wavelet; Glib::ustring fastexport_raw_bayer_method; //bool fastexport_bypass_raw_bayer_all_enhance; bool fastexport_bypass_raw_bayer_dcb_iterations; @@ -270,6 +271,7 @@ class Options { Glib::ustring lastRgbCurvesDir; Glib::ustring lastLabCurvesDir; Glib::ustring lastDenoiseCurvesDir; + Glib::ustring lastWaveletCurvesDir; Glib::ustring lastPFCurvesDir; Glib::ustring lastHsvCurvesDir; Glib::ustring lastToneCurvesDir; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 585f690e8..6a6017140 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -31,7 +31,6 @@ void ParamsEdited::set (bool v) { general.rank = v; general.colorlabel = v; general.intrash = v; - toneCurve.curve = v; toneCurve.curve2 = v; toneCurve.curveMode = v; @@ -284,6 +283,7 @@ void ParamsEdited::set (bool v) { blackwhite.autoc = v; blackwhite.algo = v; + resize.scale = v; resize.appliesTo = v; resize.method = v; @@ -335,10 +335,48 @@ void ParamsEdited::set (bool v) { raw.ff_clipControl = v; raw.exPos = v; raw.exPreser = v; + wavelet.enabled = v; + wavelet.display = v; + wavelet.median = v; + wavelet.avoid = v; + wavelet.Lmethod = v; + wavelet.CLmethod = v; + wavelet.Tilesmethod = v; + wavelet.CHmethod = v; + wavelet.HSmethod = v; + wavelet.Dirmethod = v; + wavelet.tiles = v; + wavelet.rescon = v; + wavelet.resconH = v; + wavelet.reschro = v; + wavelet.sup = v; + wavelet.sky = v; + wavelet.thres = v; + wavelet.threshold = v; + wavelet.threshold2 = v; + wavelet.chroma = v; + wavelet.chro = v; + wavelet.unif = v; + wavelet.thr = v; + wavelet.thrH = v; + wavelet.skinprotect = v; + wavelet.hueskin = v; + wavelet.hueskin2 = v; + wavelet.hllev = v; + wavelet.bllev = v; + wavelet.clvcurve = v; + wavelet.opacityCurveRG = v; + wavelet.opacityCurveBY = v; + wavelet.pastlev = v; + wavelet.satlev = v; + + for(int i = 0; i < 9; i++) { + wavelet.c[i] = v; + } dirpyrequalizer.enabled = v; dirpyrequalizer.gamutlab = v; - for(int i = 0; i < 5; i++) { + for(int i = 0; i < 6; i++) { dirpyrequalizer.mult[i] = v; } dirpyrequalizer.threshold = v; @@ -673,10 +711,47 @@ void ParamsEdited::initFrom (const std::vector raw.ff_clipControl = raw.ff_clipControl && p.raw.ff_clipControl == other.raw.ff_clipControl; raw.exPos = raw.exPos && p.raw.expos == other.raw.expos; raw.exPreser = raw.exPreser && p.raw.preser == other.raw.preser; + wavelet.enabled = wavelet.enabled && p.wavelet.enabled == other.wavelet.enabled; + wavelet.display = wavelet.display && p.wavelet.display == other.wavelet.display; + wavelet.median = wavelet.median && p.wavelet.median == other.wavelet.median; + wavelet.avoid = wavelet.avoid && p.wavelet.avoid == other.wavelet.avoid; + wavelet.Lmethod = wavelet.Lmethod && p.wavelet.Lmethod == other.wavelet.Lmethod; + wavelet.CLmethod = wavelet.CLmethod && p.wavelet.CLmethod == other.wavelet.CLmethod; + wavelet.Tilesmethod = wavelet.Tilesmethod && p.wavelet.Tilesmethod == other.wavelet.Tilesmethod; + wavelet.CHmethod = wavelet.CHmethod && p.wavelet.CHmethod == other.wavelet.CHmethod; + wavelet.HSmethod = wavelet.HSmethod && p.wavelet.HSmethod == other.wavelet.HSmethod; + wavelet.Dirmethod = wavelet.Dirmethod && p.wavelet.Dirmethod == other.wavelet.Dirmethod; + wavelet.tiles = wavelet.tiles && p.wavelet.tiles == other.wavelet.tiles; + wavelet.rescon = wavelet.rescon && p.wavelet.rescon == other.wavelet.rescon; + wavelet.resconH = wavelet.resconH && p.wavelet.resconH == other.wavelet.resconH; + wavelet.reschro = wavelet.reschro && p.wavelet.reschro == other.wavelet.reschro; + wavelet.sup = wavelet.sup && p.wavelet.sup == other.wavelet.sup; + wavelet.sky = wavelet.sky && p.wavelet.sky == other.wavelet.sky; + wavelet.threshold = wavelet.threshold && p.wavelet.threshold == other.wavelet.threshold; + wavelet.threshold2 = wavelet.threshold2 && p.wavelet.threshold2 == other.wavelet.threshold2; + wavelet.thres = wavelet.thres && p.wavelet.thres == other.wavelet.thres; + wavelet.chroma = wavelet.chroma && p.wavelet.chroma == other.wavelet.chroma; + wavelet.chro = wavelet.chro && p.wavelet.chro == other.wavelet.chro; + wavelet.unif = wavelet.unif && p.wavelet.unif == other.wavelet.unif; + wavelet.thr = wavelet.thr && p.wavelet.thr == other.wavelet.thr; + wavelet.thrH = wavelet.thrH && p.wavelet.thrH == other.wavelet.thrH; + wavelet.hueskin = wavelet.hueskin && p.wavelet.hueskin == other.wavelet.hueskin; + wavelet.hueskin2 = wavelet.hueskin2 && p.wavelet.hueskin2 == other.wavelet.hueskin2; + wavelet.hllev = wavelet.hllev && p.wavelet.hllev == other.wavelet.hllev; + wavelet.bllev = wavelet.bllev && p.wavelet.bllev == other.wavelet.bllev; + wavelet.pastlev = wavelet.pastlev && p.wavelet.pastlev == other.wavelet.pastlev; + wavelet.satlev = wavelet.satlev && p.wavelet.satlev == other.wavelet.satlev; + wavelet.clvcurve = wavelet.clvcurve && p.wavelet.clvcurve == other.wavelet.clvcurve; + wavelet.opacityCurveRG = wavelet.opacityCurveRG && p.wavelet.opacityCurveRG == other.wavelet.opacityCurveRG; + wavelet.opacityCurveBY = wavelet.opacityCurveBY && p.wavelet.opacityCurveBY == other.wavelet.opacityCurveBY; + wavelet.skinprotect = wavelet.skinprotect && p.wavelet.skinprotect == other.wavelet.skinprotect; + for(int i = 0; i < 9; i++) { + wavelet.c[i] = wavelet.c[i] && p.wavelet.c[i] == other.wavelet.c[i]; + } dirpyrequalizer.enabled = dirpyrequalizer.enabled && p.dirpyrequalizer.enabled == other.dirpyrequalizer.enabled; dirpyrequalizer.gamutlab = dirpyrequalizer.gamutlab && p.dirpyrequalizer.gamutlab == other.dirpyrequalizer.gamutlab; - for(int i = 0; i < 5; i++) { + for(int i = 0; i < 6; i++) { dirpyrequalizer.mult[i] = dirpyrequalizer.mult[i] && p.dirpyrequalizer.mult[i] == other.dirpyrequalizer.mult[i]; } dirpyrequalizer.threshold = dirpyrequalizer.threshold && p.dirpyrequalizer.threshold == other.dirpyrequalizer.threshold; @@ -743,7 +818,6 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (colorToning.colorCurve) toEdit.colorToning.colorCurve = mods.colorToning.colorCurve; if (colorToning.enabled) toEdit.colorToning.enabled = mods.colorToning.enabled; if (colorToning.opacityCurve) toEdit.colorToning.opacityCurve = mods.colorToning.opacityCurve; - if (colorToning.colorCurve) toEdit.colorToning.colorCurve = mods.colorToning.colorCurve; if (colorToning.satprotectionthreshold) toEdit.colorToning.satProtectionThreshold = dontforceSet && options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD] ? toEdit.colorToning.satProtectionThreshold + mods.colorToning.satProtectionThreshold : mods.colorToning.satProtectionThreshold; if (colorToning.autosat) toEdit.colorToning.autosat = mods.colorToning.autosat; if (colorToning.saturatedopacity) toEdit.colorToning.saturatedOpacity = dontforceSet && options.baBehav[ADDSET_COLORTONING_SATOPACITY] ? toEdit.colorToning.saturatedOpacity + mods.colorToning.saturatedOpacity : mods.colorToning.saturatedOpacity; @@ -1018,10 +1092,46 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (raw.ff_BlurType) toEdit.raw.ff_BlurType = mods.raw.ff_BlurType; if (raw.ff_AutoClipControl) toEdit.raw.ff_AutoClipControl = mods.raw.ff_AutoClipControl; if (raw.ff_clipControl) toEdit.raw.ff_clipControl = dontforceSet && options.baBehav[ADDSET_RAWFFCLIPCONTROL] ? toEdit.raw.ff_clipControl + mods.raw.ff_clipControl : mods.raw.ff_clipControl; + if (wavelet.enabled) toEdit.wavelet.enabled = mods.wavelet.enabled; + if (wavelet.display) toEdit.wavelet.display = mods.wavelet.display; + if (wavelet.median) toEdit.wavelet.median = mods.wavelet.median; + if (wavelet.avoid) toEdit.wavelet.avoid = mods.wavelet.avoid; + if (wavelet.Lmethod) toEdit.wavelet.Lmethod = mods.wavelet.Lmethod; + if (wavelet.CLmethod) toEdit.wavelet.CLmethod = mods.wavelet.CLmethod; + if (wavelet.Tilesmethod) toEdit.wavelet.Tilesmethod = mods.wavelet.Tilesmethod; + if (wavelet.CHmethod) toEdit.wavelet.CHmethod = mods.wavelet.CHmethod; + if (wavelet.HSmethod) toEdit.wavelet.HSmethod = mods.wavelet.HSmethod; + if (wavelet.Dirmethod) toEdit.wavelet.Dirmethod = mods.wavelet.Dirmethod; + if (wavelet.sky) toEdit.wavelet.sky= dontforceSet && options.baBehav[ADDSET_WA_SKYPROTECT] ? toEdit.wavelet.sky + mods.wavelet.sky : mods.wavelet.sky; + if (wavelet.thr)toEdit.wavelet.thr= dontforceSet && options.baBehav[ADDSET_WA_THRR] ? toEdit.wavelet.thr + mods.wavelet.thr : mods.wavelet.thr; + if (wavelet.thrH)toEdit.wavelet.thrH= dontforceSet && options.baBehav[ADDSET_WA_THRRH] ? toEdit.wavelet.thrH + mods.wavelet.thrH : mods.wavelet.thrH; + if (wavelet.sup) toEdit.wavelet.sup = mods.wavelet.sup; + if (wavelet.hllev) toEdit.wavelet.hllev = mods.wavelet.hllev; + if (wavelet.bllev) toEdit.wavelet.bllev = mods.wavelet.bllev; + if (wavelet.pastlev) toEdit.wavelet.pastlev = mods.wavelet.pastlev; + if (wavelet.satlev) toEdit.wavelet.satlev = mods.wavelet.satlev; + if (wavelet.clvcurve) toEdit.wavelet.clvcurve = mods.wavelet.clvcurve; + if (wavelet.opacityCurveRG) toEdit.wavelet.opacityCurveRG = mods.wavelet.opacityCurveRG; + if (wavelet.opacityCurveBY) toEdit.wavelet.opacityCurveBY = mods.wavelet.opacityCurveBY; + for(int i = 0; i < 9; i++) { + if(wavelet.c[i]) toEdit.wavelet.c[i] = dontforceSet && options.baBehav[ADDSET_WA] ? toEdit.wavelet.c[i] + mods.wavelet.c[i] : mods.wavelet.c[i]; + } + if (wavelet.skinprotect)toEdit.wavelet.skinprotect= dontforceSet && options.baBehav[ADDSET_WA_SKINPROTECT] ? toEdit.wavelet.skinprotect + mods.wavelet.skinprotect : mods.wavelet.skinprotect; + if (wavelet.hueskin) toEdit.wavelet.hueskin = mods.wavelet.hueskin; + if (wavelet.hueskin2) toEdit.wavelet.hueskin2 = mods.wavelet.hueskin2; + if (wavelet.resconH)toEdit.wavelet.resconH= dontforceSet && options.baBehav[ADDSET_WA_RESCONH] ? toEdit.wavelet.resconH + mods.wavelet.resconH : mods.wavelet.resconH; + if (wavelet.reschro)toEdit.wavelet.reschro= dontforceSet && options.baBehav[ADDSET_WA_RESCHRO] ? toEdit.wavelet.reschro + mods.wavelet.reschro : mods.wavelet.reschro; + if (wavelet.rescon)toEdit.wavelet.rescon= dontforceSet && options.baBehav[ADDSET_WA_RESCON] ? toEdit.wavelet.rescon + mods.wavelet.rescon : mods.wavelet.rescon; + if (wavelet.thres)toEdit.wavelet.thres= dontforceSet && options.baBehav[ADDSET_WA_THRES] ? toEdit.wavelet.thres + mods.wavelet.thres : mods.wavelet.thres; + if (wavelet.threshold)toEdit.wavelet.threshold= dontforceSet && options.baBehav[ADDSET_WA_THRESHOLD] ? toEdit.wavelet.threshold + mods.wavelet.threshold : mods.wavelet.threshold; + if (wavelet.threshold2)toEdit.wavelet.threshold2= dontforceSet && options.baBehav[ADDSET_WA_THRESHOLD2] ? toEdit.wavelet.threshold2 + mods.wavelet.threshold2 : mods.wavelet.threshold2; + if (wavelet.chro)toEdit.wavelet.chro= dontforceSet && options.baBehav[ADDSET_WA_CHRO] ? toEdit.wavelet.chro + mods.wavelet.chro : mods.wavelet.chro; + if (wavelet.chroma)toEdit.wavelet.chroma= dontforceSet && options.baBehav[ADDSET_WA_CHROMA] ? toEdit.wavelet.chroma + mods.wavelet.chroma : mods.wavelet.chroma; + if (wavelet.unif)toEdit.wavelet.unif= dontforceSet && options.baBehav[ADDSET_WA_UNIF] ? toEdit.wavelet.unif + mods.wavelet.unif : mods.wavelet.unif; if (dirpyrequalizer.enabled) toEdit.dirpyrequalizer.enabled = mods.dirpyrequalizer.enabled; if (dirpyrequalizer.gamutlab) toEdit.dirpyrequalizer.gamutlab = mods.dirpyrequalizer.gamutlab; - for(int i = 0; i < 5; i++) { + for(int i = 0; i < 6; i++) { if(dirpyrequalizer.mult[i]) toEdit.dirpyrequalizer.mult[i] = dontforceSet && options.baBehav[ADDSET_DIRPYREQ] ? toEdit.dirpyrequalizer.mult[i] + mods.dirpyrequalizer.mult[i] : mods.dirpyrequalizer.mult[i]; } if (dirpyrequalizer.threshold) toEdit.dirpyrequalizer.threshold= dontforceSet && options.baBehav[ADDSET_DIRPYREQ_THRESHOLD] ? toEdit.dirpyrequalizer.threshold + mods.dirpyrequalizer.threshold : mods.dirpyrequalizer.threshold; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index aeac5bb74..e131c91f4 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -54,7 +54,6 @@ class ToneCurveParamsEdited { }; class LCurveParamsEdited { - public: bool brightness; bool contrast; @@ -131,6 +130,7 @@ class SharpenMicroParamsEdited { bool matrix; bool amount; bool uniformity; + }; class SharpeningParamsEdited { @@ -472,13 +472,53 @@ class ColorManagementParamsEdited { bool gamfree; bool freegamma; }; +class WaveletParamsEdited { + + public: + bool enabled; + bool display; + bool median; + bool avoid; + bool c[9]; + bool Lmethod; + bool CHmethod; + bool HSmethod; + bool CLmethod; + bool Tilesmethod; + bool Dirmethod; + bool tiles; + bool rescon; + bool resconH; + bool reschro; + bool sup; + bool sky; + bool thres; + bool threshold; + bool threshold2; + bool chroma; + bool chro; + bool unif; + bool thr; + bool thrH; + bool skinprotect; + bool hueskin; + bool hueskin2; + bool hllev; + bool bllev; + bool clvcurve; + bool opacityCurveBY; + bool opacityCurveRG; + bool pastlev; + bool satlev; +}; class DirPyrEqualizerParamsEdited { public: bool enabled; bool gamutlab; - bool mult[5]; + bool mult[6]; + bool threshold; bool skinprotect; bool hueskin; @@ -598,6 +638,7 @@ class ParamsEdited { ColorManagementParamsEdited icm; RAWParamsEdited raw; DirPyrEqualizerParamsEdited dirpyrequalizer; + WaveletParamsEdited wavelet; HSVEqualizerParamsEdited hsvequalizer; FilmSimulationParamsEdited filmSimulation; bool exif; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index f25caf2a2..e5bdba1af 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -60,6 +60,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { impden = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_IMPULSEDENOISE"))); dirpyreq = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DIRPYREQUALIZER"))); defringe = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DEFRINGE"))); + wavelet = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EQUALIZER"))); // options in color: vibrance = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_VIBRANCE"))); @@ -147,6 +148,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { vboxes[1]->pack_start (*defringe, Gtk::PACK_SHRINK, 2); vboxes[1]->pack_start (*dirpyreq, Gtk::PACK_SHRINK, 2); //vboxes[1]->pack_start (*waveq, Gtk::PACK_SHRINK, 2); + vboxes[1]->pack_start (*wavelet, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*color, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*hseps[2], Gtk::PACK_SHRINK, 2); @@ -282,6 +284,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { dirpyreqConn = dirpyreq->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); //waveqConn = waveq->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); defringeConn = defringe->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); + waveletConn = wavelet->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); vibranceConn = vibrance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); chmixerConn = chmixer->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); @@ -509,6 +512,7 @@ void PartialPasteDlg::detailToggled () { defringe->set_active (detail->get_active ()); dirpyreq->set_active (detail->get_active ()); //waveq->set_active (detail->get_active ()); + wavelet->set_active (detail->get_active ()); sharpenConn.block (false); gradsharpenConn.block(false); @@ -657,6 +661,7 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param if (!dirpyreq->get_active ()) filterPE.dirpyrequalizer = falsePE.dirpyrequalizer; if (!defringe->get_active ()) filterPE.defringe = falsePE.defringe; if (!dirpyrden->get_active ()) filterPE.dirpyrDenoise = falsePE.dirpyrDenoise; + if (!wavelet->get_active ()) filterPE.wavelet = falsePE.wavelet; if (!vibrance->get_active ()) filterPE.vibrance = falsePE.vibrance; if (!chmixer->get_active ()) filterPE.chmixer = falsePE.chmixer; diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index a5098ec9d..403bf645e 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -58,6 +58,7 @@ class PartialPasteDlg : public Gtk::Dialog { Gtk::CheckButton* dirpyrden; Gtk::CheckButton* defringe; Gtk::CheckButton* dirpyreq; + Gtk::CheckButton* wavelet; // options in color: Gtk::CheckButton* vibrance; @@ -118,7 +119,7 @@ class PartialPasteDlg : public Gtk::Dialog { sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaicmConn, rawConn; sigc::connection wbConn, exposureConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn; - sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, waveqConn, defringeConn, epdConn, dirpyreqConn; + sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, waveqConn, defringeConn, epdConn, dirpyreqConn, waveletConn; sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn, chmixerbwConn, colortoningConn, filmSimulationConn; sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn; sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, perspectiveConn, commonTransConn; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index f95d8c414..fe12ccd1c 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -299,6 +299,23 @@ Gtk::Widget* Preferences::getBatchProcPanel () { appendBehavList (mi, M("TP_DIRPYREQUALIZER_THRESHOLD"), ADDSET_DIRPYREQ_THRESHOLD, true); appendBehavList (mi, M("TP_DIRPYREQUALIZER_SKIN"), ADDSET_DIRPYREQ_SKINPROTECT, true); + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_WAVELET_LABEL")); + appendBehavList (mi, M("TP_WAVELET_THRES"), ADDSET_WA_THRES, true); + appendBehavList (mi, M("TP_WAVELET_CONTRAST"), ADDSET_WA, true); + // appendBehavList (mi, M("TP_WAVELET_UNIF"), ADDSET_WA_UNIF, true); + appendBehavList (mi, M("TP_WAVELET_THRESHOLD"), ADDSET_WA_THRESHOLD, true); + appendBehavList (mi, M("TP_WAVELET_THRESHOLD2"), ADDSET_WA_THRESHOLD2, true); + appendBehavList (mi, M("TP_WAVELET_CHRO"), ADDSET_WA_CHRO, true); + appendBehavList (mi, M("TP_WAVELET_CHR"), ADDSET_WA_CHROMA, true); + appendBehavList (mi, M("TP_WAVELET_SKIN"), ADDSET_WA_SKINPROTECT, true); + appendBehavList (mi, M("TP_WAVELET_RESCON"), ADDSET_WA_RESCON, true); + appendBehavList (mi, M("TP_WAVELET_THR"), ADDSET_WA_THRR, true); + appendBehavList (mi, M("TP_WAVELET_RESCONH"), ADDSET_WA_RESCONH, true); + appendBehavList (mi, M("TP_WAVELET_THRH"), ADDSET_WA_THRRH, true); + appendBehavList (mi, M("TP_WAVELET_RESCHRO"), ADDSET_WA_RESCHRO, true); + appendBehavList (mi, M("TP_WAVELET_SKY"), ADDSET_WA_SKYPROTECT, true); + mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_PREPROCESS_LABEL")); appendBehavList (mi, M("TP_PREPROCESS_GREENEQUIL"), ADDSET_PREPROCESS_GREENEQUIL, false); @@ -595,6 +612,7 @@ Gtk::Widget* Preferences::getPerformancePanel () { clutCacheSizeSB->set_increments (1, 5); clutCacheSizeSB->set_max_length(2); // Will this be sufficient? :) + #ifdef _OPENMP clutCacheSizeSB->set_range (1, 2*omp_get_num_procs()); #else diff --git a/rtgui/sharpening.cc b/rtgui/sharpening.cc index 93a08e934..4bc66a71a 100644 --- a/rtgui/sharpening.cc +++ b/rtgui/sharpening.cc @@ -130,7 +130,6 @@ Sharpening::Sharpening () : FoldableToolPanel(this) { diter->setAdjusterListener (this); radius->setAdjusterListener (this); amount->setAdjusterListener (this); - threshold->setAdjusterListener (this); eradius->setAdjusterListener (this); etolerance->setAdjusterListener (this); hcamount->setAdjusterListener (this); diff --git a/rtgui/thresholdadjuster.cc b/rtgui/thresholdadjuster.cc index 6b413294b..bf99a631c 100644 --- a/rtgui/thresholdadjuster.cc +++ b/rtgui/thresholdadjuster.cc @@ -301,16 +301,20 @@ void ThresholdAdjuster::sendToListener () { if (tSelector.getPrecision() > 0) { // if precision is >0, then we assume that the listener is waiting for doubles rtengine::procparams::Threshold t = tSelector.getPositions(); - if (tSelector.isDouble()) + if (tSelector.isDouble()){ adjusterListener->adjusterChanged (this, t.value[0], t.value[1], t.value[2], t.value[3]); + adjusterListener->adjusterChanged2 (this, t.value[0], t.value[1], t.value[2], t.value[3]); + } else adjusterListener->adjusterChanged (this, t.value[0], t.value[1]); } else { // if precision is equal to 0, then we assume that the listener is waiting for integers rtengine::procparams::Threshold t = tSelector.getPositions(); - if (tSelector.isDouble()) + if (tSelector.isDouble()){ adjusterListener->adjusterChanged (this, t.value[0], t.value[1], t.value[2], t.value[3]); + adjusterListener->adjusterChanged2 (this, t.value[0], t.value[1], t.value[2], t.value[3]); + } else adjusterListener->adjusterChanged (this, t.value[0], t.value[1]); } diff --git a/rtgui/thresholdadjuster.h b/rtgui/thresholdadjuster.h index 63cc02b74..3967223f1 100644 --- a/rtgui/thresholdadjuster.h +++ b/rtgui/thresholdadjuster.h @@ -40,6 +40,7 @@ class ThresholdAdjusterListener { virtual void adjusterChanged (ThresholdAdjuster* a, int newBottom, int newTop) {} // to be used by listener that has created a ThresholdAdjuster with with double threshold and precision == 0 virtual void adjusterChanged (ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight) {} + virtual void adjusterChanged2 (ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR) {} }; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index eba820e93..8724c48f4 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -71,6 +71,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { icm = Gtk::manage (new ICMPanel ()); exifpanel = Gtk::manage (new ExifPanel ()); iptcpanel = Gtk::manage (new IPTCPanel ()); + wavelet = Gtk::manage (new Wavelet ()); dirpyrequalizer = Gtk::manage (new DirPyrEqualizer ()); hsvequalizer = Gtk::manage (new HSVEqualizer ()); filmSimulation = Gtk::manage (new FilmSimulation ()); @@ -118,6 +119,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { addPanel (detailsPanel, dirpyrdenoise, M("TP_DIRPYRDENOISE_LABEL"), true); toolPanels.push_back (dirpyrdenoise); addPanel (detailsPanel, defringe, M("TP_DEFRINGE_LABEL"), true); toolPanels.push_back (defringe); addPanel (detailsPanel, dirpyrequalizer, M("TP_DIRPYREQUALIZER_LABEL"), true); toolPanels.push_back (dirpyrequalizer); + addPanel (detailsPanel, wavelet, M("TP_WAVELET_LABEL"),true); toolPanels.push_back (wavelet); addPanel (transformPanel, crop, M("TP_CROP_LABEL")); toolPanels.push_back (crop); addPanel (transformPanel, resize, M("TP_RESIZE_LABEL")); toolPanels.push_back (resize); addPanel (transformPanel, lensgeom, M("TP_LENSGEOM_LABEL")); toolPanels.push_back (lensgeom); @@ -392,6 +394,7 @@ void ToolPanelCoordinator::initImage (rtengine::StagedImageProcessor* ipc_, bool ipc->setAutoBWListener (blackwhite); ipc->setAutoColorTonListener (colortoning); ipc->setAutoChromaListener (dirpyrdenoise); + ipc->setWaveletListener (wavelet); ipc->setSizeListener (crop); ipc->setSizeListener (resize); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index eadcc3ce0..f637669b8 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -57,6 +57,7 @@ #include "lensgeom.h" #include "lensgeomlistener.h" #include "dirselectionlistener.h" +#include "wavelet.h" #include "dirpyrequalizer.h" #include "hsvequalizer.h" #include "preprocess.h" @@ -123,7 +124,8 @@ class ToolPanelCoordinator : public ToolPanelListener, LCurve* lcurve; RGBCurves* rgbcurves; ColorToning* colortoning; - DirPyrEqualizer* dirpyrequalizer; + Wavelet * wavelet; + DirPyrEqualizer* dirpyrequalizer; HSVEqualizer* hsvequalizer; FilmSimulation *filmSimulation; SensorBayer * sensorbayer; diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc new file mode 100644 index 000000000..d216d6746 --- /dev/null +++ b/rtgui/wavelet.cc @@ -0,0 +1,1347 @@ +/* + * This file is part of RawTherapee. + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * 2014 Jacques Desmis + */ + +#include "wavelet.h" +#include +#include +#include "edit.h" +#include "guiutils.h" + +using namespace rtengine; +using namespace rtengine::procparams; +extern Options options; + +Wavelet::Wavelet () : FoldableToolPanel(this) { + std::vector milestones; + CurveListener::setMulti(true); + nextnlevel=7.; + float r, g, b; + //from -PI to +PI (radians) convert to hsv and draw bottombar + Color::hsv2rgb01(0.4199, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.0 , r, g, b) ); // hsv: 0.4199 rad: -3.14 + Color::hsv2rgb01(0.5000, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.054 , r, g, b) ); // hsv: 0.5 rad: -2.8 + Color::hsv2rgb01(0.6000, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.1336, r, g, b) ); // hsv: 0.60 rad: -2.3 + Color::hsv2rgb01(0.7500, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.3567, r, g, b) ); // hsv: 0.75 rad: -0.9 + Color::hsv2rgb01(0.8560, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.4363, r, g, b) ); // hsv: 0.856 rad: -0.4 + Color::hsv2rgb01(0.9200, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.4841, r, g, b) ); // hsv: 0.92 rad: -0.1 + Color::hsv2rgb01(0.9300, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.5000, r, g, b) ); // hsv: 0.93 rad: 0 + Color::hsv2rgb01(0.9600, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.5366, r, g, b) ); // hsv: 0.96 rad: 0.25 + Color::hsv2rgb01(1.0000, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.5955, r, g, b) ); // hsv: 1. rad: 0.6 + Color::hsv2rgb01(0.0675, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.6911, r, g, b) ); // hsv: 0.0675 rad: 1.2 + Color::hsv2rgb01(0.0900, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.7229, r, g, b) ); // hsv: 0.09 rad: 1.4 + Color::hsv2rgb01(0.1700, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.7707, r, g, b) ); // hsv: 0.17 rad: 1.7 + Color::hsv2rgb01(0.2650, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.8503, r, g, b) ); // hsv: 0.265 rad: 2.1 + Color::hsv2rgb01(0.3240, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.8981, r, g, b) ); // hsv: 0.324 rad: 2.5 + Color::hsv2rgb01(0.4197, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(1. , r, g, b) ); // hsv: 0.419 rad: 3.14 + + std::vector milestones2; + milestones2.push_back( GradientMilestone(0.0, 0.0, 0.0, 0.0) ); + milestones2.push_back( GradientMilestone(1.0, 1.0, 1.0, 1.0) ); + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + enabled->set_active (true); + pack_start(*enabled); + enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &Wavelet::enabledToggled) ); + std::vector defaultCurve; + + Gtk::Frame* residualFrame = Gtk::manage (new Gtk::Frame (M("TP_WAVELET_RESID")) ); + residualFrame->set_border_width(0); + residualFrame->set_label_align(0.025, 0.5); + + Gtk::VBox * resBox = Gtk::manage (new Gtk::VBox()); + resBox->set_border_width(4); + resBox->set_spacing(2); + + rescon = Gtk::manage (new Adjuster (M("TP_WAVELET_RESCON"), -100, 100, 1, 0)); + resBox->pack_start(*rescon, Gtk::PACK_SHRINK); + rescon->setAdjusterListener (this); + + thr = Gtk::manage (new Adjuster (M("TP_WAVELET_THR"), 0, 100, 1, 30)); + resBox->pack_start(*thr); + thr->setAdjusterListener (this); + + resconH = Gtk::manage (new Adjuster (M("TP_WAVELET_RESCONH"), -100, 100, 1, 0)); + resBox->pack_start(*resconH, Gtk::PACK_SHRINK); + resconH->setAdjusterListener (this); + + thrH = Gtk::manage (new Adjuster (M("TP_WAVELET_THRH"), 0, 100, 1, 70)); + resBox->pack_start(*thrH,Gtk::PACK_SHRINK); + thrH->setAdjusterListener (this); + + reschro = Gtk::manage (new Adjuster (M("TP_WAVELET_RESCHRO"), -100, 100, 1, 0)); + resBox->pack_start(*reschro); + reschro->setAdjusterListener (this); + + + hueskin2 = Gtk::manage (new ThresholdAdjuster (M("TP_WAVELET_HUESKY"), -314., 314., -260., -250, -130., -140., 0, false)); + hueskin2->set_tooltip_markup (M("TP_WAVELET_HUESKY_TOOLTIP")); + + hueskin2->setBgGradient(milestones); + resBox->pack_start(*hueskin2); + hueskin2->setAdjusterListener (this); + + sky = Gtk::manage (new Adjuster (M("TP_WAVELET_SKY"), -100., 100.0, 1., 0.)); + sky->set_tooltip_text (M("TP_WAVELET_SKY_TOOLTIP")); + sky->setAdjusterListener (this); + resBox->pack_start(*sky); + + + Gtk::Frame* levelFrame = Gtk::manage (new Gtk::Frame (M("TP_WAVELET_LEVF")) ); + levelFrame->set_border_width(0); + levelFrame->set_label_align(0.025, 0.5); + + Gtk::Frame* chromaFrame = Gtk::manage (new Gtk::Frame (M("TP_WAVELET_LEVCH")) ); + chromaFrame->set_border_width(0); + chromaFrame->set_label_align(0.025, 0.5); + + toningFrame = Gtk::manage (new Gtk::Frame (M("TP_WAVELET_TON")) ); + toningFrame->set_border_width(0); + toningFrame->set_label_align(0.025, 0.5); + + Gtk::Frame* controlFrame = Gtk::manage (new Gtk::Frame (M("TP_WAVELET_CONTR")) ); + controlFrame->set_border_width(0); + controlFrame->set_label_align(0.025, 0.5); + + Gtk::HSeparator *separator1 = Gtk::manage (new Gtk::HSeparator()); + pack_start(*separator1, Gtk::PACK_SHRINK, 2); + + Gtk::VBox * buBox = Gtk::manage (new Gtk::VBox()); + buBox->set_border_width(4); + buBox->set_spacing(2); + + Gtk::VBox * levBox = Gtk::manage (new Gtk::VBox()); + levBox->set_border_width(4); + levBox->set_spacing(2); + + Gtk::VBox * conBox = Gtk::manage (new Gtk::VBox()); + conBox->set_border_width(4); + conBox->set_spacing(2); + + Gtk::VBox * chBox = Gtk::manage (new Gtk::VBox()); + chBox->set_border_width(4); + chBox->set_spacing(2); + + Gtk::VBox * tonBox = Gtk::manage (new Gtk::VBox()); + tonBox->set_border_width(4); + tonBox->set_spacing(2); + + Gtk::HBox * buttonBox = Gtk::manage (new Gtk::HBox()); + wavLabels = Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER)); + + levBox->pack_start(*buttonBox, Gtk::PACK_SHRINK, 2); + + Gtk::Button * contrastMinusButton = Gtk::manage (new Gtk::Button(M("TP_WAVELET_CONTRAST_MINUS"))); + buttonBox->pack_start(*contrastMinusButton, Gtk::PACK_SHRINK, 2); + contrastMinusPressedConn = contrastMinusButton->signal_pressed().connect( sigc::mem_fun(*this, &Wavelet::contrastMinusPressed)); + + Gtk::Button * neutralButton = Gtk::manage (new Gtk::Button(M("TP_WAVELET_NEUTRAL"))); + buttonBox->pack_start(*neutralButton, Gtk::PACK_SHRINK, 2); + neutralPressedConn = neutralButton->signal_pressed().connect( sigc::mem_fun(*this, &Wavelet::neutralPressed)); + + Gtk::Button * contrastPlusButton = Gtk::manage (new Gtk::Button(M("TP_WAVELET_CONTRAST_PLUS"))); + buttonBox->pack_start(*contrastPlusButton, Gtk::PACK_SHRINK, 2); + contrastPlusPressedConn = contrastPlusButton->signal_pressed().connect( sigc::mem_fun(*this, &Wavelet::contrastPlusPressed)); + + buttonBox->show_all_children(); + + Gtk::HSeparator *separator2 = Gtk::manage (new Gtk::HSeparator()); + levBox->pack_start(*separator2, Gtk::PACK_SHRINK, 2); + + unif = Gtk::manage (new Adjuster (M("TP_WAVELET_UNIF"), 0, 100, 1, 0)); + unif->set_tooltip_text (M("TP_WAVELET_UNIF_TOOLTIP")); + //levBox->pack_start(*unif); //keep the possibility to reinstall + unif->setAdjusterListener (this); + + + Gtk::HSeparator *separatorU = Gtk::manage (new Gtk::HSeparator()); + levBox->pack_start(*separatorU, Gtk::PACK_SHRINK, 2); + + for(int i = 0; i < 9; i++) + { + Glib::ustring ss; + switch( i ){ + case 0: + ss =Glib::ustring::compose( "%1 (%2)",i, M("TP_WAVELET_FINEST"));break; + case 8: + ss =Glib::ustring::compose( "%1 (%2)",i, M("TP_WAVELET_LARGEST"));break; + default: + ss =Glib::ustring::compose( "%1",i); + } + + correction[i] = Gtk::manage ( new Adjuster (ss, -100, 150, 1, 0) ); + correction[i]->setAdjusterListener(this); + levBox->pack_start(*correction[i]); + } + sup = Gtk::manage (new Adjuster (M("TP_WAVELET_SUPE"), -100, 150, 1, 0)); + levBox->pack_start(*sup); + sup->setAdjusterListener (this); + wavLabels->show(); + levBox->pack_start (*wavLabels); + + + Gtk::HSeparator *separatorC = Gtk::manage (new Gtk::HSeparator()); + levBox->pack_start(*separatorC, Gtk::PACK_SHRINK, 2); + + + HSmethod = Gtk::manage (new MyComboBoxText ()); + HSmethod->append_text (M("TP_WAVELET_HS1")); + HSmethod->append_text (M("TP_WAVELET_HS2")); + HSmethodconn = HSmethod->signal_changed().connect ( sigc::mem_fun(*this, &Wavelet::HSmethodChanged) ); + levBox->pack_start(*HSmethod); + + avoid = Gtk::manage (new Gtk::CheckButton (M("TP_WAVELET_AVOID"))); + avoid->set_active (true); + avoidConn = avoid->signal_toggled().connect( sigc::mem_fun(*this, &Wavelet::avoidToggled) ); + + + hllev = Gtk::manage (new ThresholdAdjuster (M("TP_WAVELET_HIGHLIGHT"), 0., 100., 50., 75., 100., 98., 0, false)); + hllev->setAdjusterListener (this); + hllev->setBgGradient(milestones2); + levBox->pack_start(*hllev); + + threshold = Gtk::manage (new Adjuster (M("TP_WAVELET_THRESHOLD"), 1, 9, 1, 5)); + levBox->pack_start(*threshold); + threshold->setAdjusterListener (this); + threshold->set_tooltip_text (M("TP_WAVELET_THRESHOLD_TOOLTIP")); + + bllev = Gtk::manage (new ThresholdAdjuster (M("TP_WAVELET_LOWLIGHT"), 0., 100., 0., 2., 50., 25., 0, false)); + bllev->setAdjusterListener (this); + bllev->setBgGradient(milestones2); + levBox->pack_start(*bllev); + + threshold2 = Gtk::manage (new Adjuster (M("TP_WAVELET_THRESHOLD2"), 1, 9, 1, 4)); + levBox->pack_start(*threshold2); + threshold2->setAdjusterListener (this); + threshold2->set_tooltip_text (M("TP_WAVELET_THRESHOLD2_TOOLTIP")); + + + CHmethod = Gtk::manage (new MyComboBoxText ()); + CHmethod->append_text (M("TP_WAVELET_CH1")); + CHmethod->append_text (M("TP_WAVELET_CH2")); + CHmethod->append_text (M("TP_WAVELET_CH3")); + CHmethodconn = CHmethod->signal_changed().connect ( sigc::mem_fun(*this, &Wavelet::CHmethodChanged) ); + chBox->pack_start(*CHmethod); + + chroma = Gtk::manage (new Adjuster (M("TP_WAVELET_CHRO"), 1, 9, 1, 5)); + chroma->set_tooltip_text (M("TP_WAVELET_CHRO_TOOLTIP")); + chBox->pack_start(*chroma); + chroma->setAdjusterListener (this); + + satlev = Gtk::manage (new ThresholdAdjuster (M("TP_WAVELET_SAT"), 0., 130., 30., 45., 130., 100., 0, false)); + satlev->setAdjusterListener (this); + satlev->setBgGradient(milestones2); + + pastlev = Gtk::manage (new ThresholdAdjuster (M("TP_WAVELET_PASTEL"), 0., 70., 0., 2., 30., 20., 0, false)); + pastlev->setAdjusterListener (this); + pastlev->setBgGradient(milestones2); + chBox->pack_start(*pastlev); + chBox->pack_start(*satlev); + + chro = Gtk::manage (new Adjuster (M("TP_WAVELET_CHR"), 0., 100., 1., 0.)); + chro->set_tooltip_text (M("TP_WAVELET_CHR_TOOLTIP")); + chBox->pack_start(*chro); + chro->setAdjusterListener (this); + + CLVcurveEditorG = new CurveEditorGroup (options.lastWaveletCurvesDir, M("TP_WAVELET_CLVCURVE")); + CLVcurveEditorG->setCurveListener (this); + rtengine::WaveletParams::getDefaultCLVCurve(defaultCurve); + ccshape = static_cast(CLVcurveEditorG->addCurve(CT_Flat, "", NULL, false)); + ccshape->setIdentityValue(0.); + ccshape->setResetCurve(FlatCurveType(defaultCurve.at(0)), defaultCurve); + ccshape->setTooltip(M("TP_WAVELET_CURVEEDITOR_CLV_TOOLTIP")); +// ccshape->setBottomBarColorProvider(this, 2); + + CLVcurveEditorG->curveListComplete(); + chBox->pack_start(*CLVcurveEditorG, Gtk::PACK_SHRINK, 4); + + + //----------- Color Opacity curve RG ------------------------------ + + + opaCurveEditorG = new CurveEditorGroup (options.lastWaveletCurvesDir, M("TP_WAVELET_COLORT")); + opaCurveEditorG->setCurveListener (this); + std::vector defaultCCurve; + + rtengine::WaveletParams::getDefaultOpacityCurveRG(defaultCCurve); + opacityShapeRG = static_cast(opaCurveEditorG->addCurve(CT_Flat, "", NULL, false)); + opacityShapeRG->setIdentityValue(0.); + opacityShapeRG->setResetCurve(FlatCurveType(defaultCurve.at(0)), defaultCCurve); + + // This will add the reset button at the end of the curveType buttons + opaCurveEditorG->curveListComplete(); + opaCurveEditorG->show(); + + + tonBox->pack_start( *opaCurveEditorG, Gtk::PACK_SHRINK, 2); + + //----------- Opacity curve BY------------------------------ + + opacityCurveEditorG = new CurveEditorGroup (options.lastWaveletCurvesDir, M("TP_WAVELET_OPACITY")); + opacityCurveEditorG->setCurveListener (this); + std::vector defaultCCBurve; + + rtengine::WaveletParams::getDefaultOpacityCurveBY(defaultCCBurve); + opacityShapeBY = static_cast(opacityCurveEditorG->addCurve(CT_Flat, "", NULL, false)); + opacityShapeBY->setIdentityValue(0.); + opacityShapeBY->setResetCurve(FlatCurveType(defaultCurve.at(0)), defaultCCBurve); +// opacityShape->setBottomBarBgGradient(milestones); +// milestones.push_back( GradientMilestone(1., 1., 1., 0.) ); +// milestones.push_back( GradientMilestone(0., 0., 0., 1.) ); +// opacityShapeBY->setLeftBarBgGradient(milestones); + + // This will add the reset button at the end of the curveType buttons + opacityCurveEditorG->curveListComplete(); + opacityCurveEditorG->show(); + + tonBox->pack_start( *opacityCurveEditorG, Gtk::PACK_SHRINK, 2); + + + + +//------------------------------------------------- + + median = Gtk::manage (new Gtk::CheckButton (M("TP_WAVELET_MEDI"))); + median->set_active (true); + medianConn = median->signal_toggled().connect( sigc::mem_fun(*this, &Wavelet::medianToggled) ); + conBox->pack_start(*median); + + skinprotect = Gtk::manage ( new Adjuster (M("TP_WAVELET_SKIN"), -100, 100, 1, 0.) ); + skinprotect->setAdjusterListener(this); + conBox->pack_start(*skinprotect); + skinprotect->set_tooltip_markup (M("TP_WAVELET_SKIN_TOOLTIP")); + + hueskin = Gtk::manage (new ThresholdAdjuster (M("TP_WAVELET_HUESKIN"), -314., 314., -5., 25., 170., 120., 0, false)); + hueskin->set_tooltip_markup (M("TP_WAVELET_HUESKIN_TOOLTIP")); + + hueskin->setBgGradient(milestones); + conBox->pack_start(*hueskin); + hueskin->setAdjusterListener (this); + + Gtk::VBox * utiBox = Gtk::manage (new Gtk::VBox()); + utiBox->set_border_width(4); + utiBox->set_spacing(2); + + Gtk::VBox * diBox = Gtk::manage (new Gtk::VBox()); + diBox->set_border_width(4); + diBox->set_spacing(2); + + utilFrame = Gtk::manage (new Gtk::Frame (M("TP_WAVELET_UTIL")) ); + utilFrame->set_border_width(0); + utilFrame->set_label_align(0.025, 0.5); + + display = Gtk::manage (new Gtk::CheckButton (M("TP_WAVELET_DISPLAY"))); + display->set_active (true); + displayConn = display->signal_toggled().connect( sigc::mem_fun(*this, &Wavelet::displayToggled) ); + + thres = Gtk::manage (new Adjuster (M("TP_WAVELET_THRES"), 4, 9, 1, 7)); + thres->set_tooltip_text (M("TP_WAVELET_THRES_TOOLTIP")); + Tilesmethod = Gtk::manage (new MyComboBoxText ()); + Tilesmethod->append_text (M("TP_WAVELET_TILESFULL")); + Tilesmethod->append_text (M("TP_WAVELET_TILESBIG")); + Tilesmethod->append_text (M("TP_WAVELET_TILESLIT")); + Tilesmethodconn = Tilesmethod->signal_changed().connect ( sigc::mem_fun(*this, &Wavelet::TilesmethodChanged) ); + Tilesmethod->set_tooltip_text (M("TP_WAVELET_TILES_TOOLTIP")); + + + tiles = Gtk::manage (new Adjuster (M("TP_WAVELET_TILES"), 12, 22, 1, 14)); + //tiles->set_tooltip_text (M("TP_WAVELET_TILES_TOOLTIP")); + thres->setAdjusterListener (this); + tiles->setAdjusterListener (this); + utiBox->pack_start (*thres); +// utiBox->pack_start (*tiles); + utiBox->pack_start (*Tilesmethod); + + dispFrame = Gtk::manage (new Gtk::Frame (M("TP_WAVELET_DISP")) ); + dispFrame->set_border_width(0); + dispFrame->set_label_align(0.025, 0.5); + + + CLmethod = Gtk::manage (new MyComboBoxText ()); + CLmethod->append_text (M("TP_WAVELET_ONE")); + CLmethod->append_text (M("TP_WAVELET_INF")); + CLmethod->append_text (M("TP_WAVELET_SUP")); + CLmethod->append_text (M("TP_WAVELET_ALL")); + CLmethodconn = CLmethod->signal_changed().connect ( sigc::mem_fun(*this, &Wavelet::CLmethodChanged) ); + diBox->pack_start (*CLmethod); + + Lmethod = Gtk::manage (new MyComboBoxText ()); + Lmethod->append_text (M("TP_WAVELET_0")); + Lmethod->append_text (M("TP_WAVELET_1")); + Lmethod->append_text (M("TP_WAVELET_2")); + Lmethod->append_text (M("TP_WAVELET_3")); + Lmethod->append_text (M("TP_WAVELET_4")); + Lmethod->append_text (M("TP_WAVELET_5")); + Lmethod->append_text (M("TP_WAVELET_6")); + Lmethod->append_text (M("TP_WAVELET_7")); + Lmethod->append_text (M("TP_WAVELET_8")); + Lmethod->set_active(0); + Lmethodconn = Lmethod->signal_changed().connect ( sigc::mem_fun(*this, &Wavelet::LmethodChanged) ); + diBox->pack_start (*Lmethod); + + + Dirmethod = Gtk::manage (new MyComboBoxText ()); + Dirmethod->append_text (M("TP_WAVELET_DONE")); + Dirmethod->append_text (M("TP_WAVELET_DTWO")); + Dirmethod->append_text (M("TP_WAVELET_DTHR")); + Dirmethod->append_text (M("TP_WAVELET_DALL")); + Dirmethodconn = Dirmethod->signal_changed().connect ( sigc::mem_fun(*this, &Wavelet::DirmethodChanged) ); + diBox->pack_start (*Dirmethod); + + pack_start(*display); + utilFrame->add(*utiBox); + pack_start (*utilFrame); + dispFrame->add(*diBox); + pack_start (*dispFrame); + + + levelFrame->add(*levBox); + pack_start (*levelFrame, Gtk::PACK_EXPAND_WIDGET, 4); + chromaFrame->add(*chBox); + pack_start (*chromaFrame, Gtk::PACK_EXPAND_WIDGET, 4); + toningFrame->add(*tonBox); + pack_start (*toningFrame, Gtk::PACK_EXPAND_WIDGET, 4); + + conBox->pack_start(*avoid); + controlFrame->add(*conBox); + pack_start (*controlFrame, Gtk::PACK_EXPAND_WIDGET, 4); + + residualFrame->add(*resBox); + pack_start(*residualFrame, Gtk::PACK_EXPAND_WIDGET, 4); + show_all_children (); +} + +Wavelet::~Wavelet () { + delete CLVcurveEditorG; + delete opaCurveEditorG; + delete opacityCurveEditorG; +} +int wavChangedUI (void* data) { + GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected + (static_cast(data))->wavComputed_ (); + return 0; +} + +void Wavelet::wavChanged (double nlevel) +{ + nextnlevel=nlevel; + g_idle_add (wavChangedUI, this); +} +bool Wavelet::wavComputed_ () { + + disableListener (); + enableListener (); + updatewavLabel (); + return false; +} +void Wavelet::updatewavLabel () { + if (!batchMode) { + float lv; + lv=nextnlevel; + { + wavLabels->set_text( + Glib::ustring::compose(M("TP_WAVELET_LEVLABEL"), + Glib::ustring::format(std::fixed, std::setprecision(0), lv)) + + ); + } + } +} + +void Wavelet::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + Lmethodconn.block(true); + CLmethodconn.block(true); + Tilesmethodconn.block(true); + Dirmethodconn.block(true); + CHmethodconn.block(true); + HSmethodconn.block(true); + HSmethod->set_active (1); + if (pp->wavelet.HSmethod=="without") + HSmethod->set_active (0); + else if (pp->wavelet.HSmethod=="with") + HSmethod->set_active (1); + HSmethodChanged(); + + CHmethod->set_active (1); + if (pp->wavelet.CHmethod=="without") + CHmethod->set_active (0); + else if (pp->wavelet.CHmethod=="with") + CHmethod->set_active (1); + else if (pp->wavelet.CHmethod=="link") + CHmethod->set_active (2); + CHmethodChanged(); + + CLmethod->set_active (3); + if (pp->wavelet.CLmethod=="one") + CLmethod->set_active (0); + else if (pp->wavelet.CLmethod=="inf") + CLmethod->set_active (1); + else if (pp->wavelet.CLmethod=="sup") + CLmethod->set_active (2); + else if (pp->wavelet.CLmethod=="all") + CLmethod->set_active (3); + CLmethodChanged(); + + Tilesmethod->set_active (2); + if (pp->wavelet.Tilesmethod=="full") + Tilesmethod->set_active (0); + else if (pp->wavelet.Tilesmethod=="big") + Tilesmethod->set_active (1); + else if (pp->wavelet.Tilesmethod=="lit") + Tilesmethod->set_active (2); + TilesmethodChanged(); + + Dirmethod->set_active (3); + if (pp->wavelet.Dirmethod=="one") + Dirmethod->set_active (0); + else if (pp->wavelet.Dirmethod=="two") + Dirmethod->set_active (1); + else if (pp->wavelet.Dirmethod=="thr") + Dirmethod->set_active (2); + else if (pp->wavelet.Dirmethod=="all") + Dirmethod->set_active (3); + DirmethodChanged(); + + Lmethod->set_active (4); + if (pp->wavelet.Lmethod=="0_") + Lmethod->set_active (0); + else if (pp->wavelet.Lmethod=="1_") + Lmethod->set_active (1); + else if (pp->wavelet.Lmethod=="2_") + Lmethod->set_active (2); + else if (pp->wavelet.Lmethod=="3_") + Lmethod->set_active (3); + else if (pp->wavelet.Lmethod=="4_") + Lmethod->set_active (4); + else if (pp->wavelet.Lmethod=="5_") + Lmethod->set_active (5); + else if (pp->wavelet.Lmethod=="6_") + Lmethod->set_active (6); + else if (pp->wavelet.Lmethod=="7_") + Lmethod->set_active (7); + else if (pp->wavelet.Lmethod=="8_") + Lmethod->set_active (8); + + LmethodChanged(); + + if (pedited) { + if (!pedited->wavelet.Lmethod) + Lmethod->set_active (8); + if (!pedited->wavelet.CLmethod) + CLmethod->set_active (3); + if (!pedited->wavelet.Tilesmethod) + Tilesmethod->set_active (2); + if (!pedited->wavelet.Dirmethod) + Dirmethod->set_active (3); + if (!pedited->wavelet.CHmethod) + CHmethod->set_active (1); + if (!pedited->wavelet.HSmethod) + HSmethod->set_active (1); + + enabled->set_inconsistent (!pedited->wavelet.enabled); + ccshape->setUnChanged (!pedited->wavelet.clvcurve); + opacityShapeRG->setCurve (pp->wavelet.opacityCurveRG); + opacityShapeBY->setCurve (pp->wavelet.opacityCurveBY); + avoid->set_inconsistent (!pedited->wavelet.avoid); + tiles->setEditedState (pedited->wavelet.tiles ? Edited : UnEdited); + rescon->setEditedState (pedited->wavelet.rescon ? Edited : UnEdited); + resconH->setEditedState (pedited->wavelet.resconH ? Edited : UnEdited); + reschro->setEditedState (pedited->wavelet.reschro ? Edited : UnEdited); + sup->setEditedState (pedited->wavelet.sup ? Edited : UnEdited); + sky->setEditedState (pedited->wavelet.sky ? Edited : UnEdited); + thres->setEditedState (pedited->wavelet.thres ? Edited : UnEdited); + threshold->setEditedState (pedited->wavelet.threshold ? Edited : UnEdited); + threshold2->setEditedState (pedited->wavelet.threshold2 ? Edited : UnEdited); + display->set_inconsistent (!pedited->wavelet.display); + chroma->setEditedState (pedited->wavelet.chroma ? Edited : UnEdited); + chro->setEditedState (pedited->wavelet.chro ? Edited : UnEdited); + median->set_inconsistent (!pedited->wavelet.median); + unif->setEditedState (pedited->wavelet.unif ? Edited : UnEdited); + thr->setEditedState (pedited->wavelet.thr ? Edited : UnEdited); + thrH->setEditedState (pedited->wavelet.thrH ? Edited : UnEdited); + skinprotect->setEditedState (pedited->wavelet.skinprotect ? Edited : UnEdited); + hueskin->setEditedState (pedited->wavelet.hueskin ? Edited : UnEdited); + hueskin2->setEditedState (pedited->wavelet.hueskin2 ? Edited : UnEdited); + hllev->setEditedState (pedited->wavelet.hllev ? Edited : UnEdited); + bllev->setEditedState (pedited->wavelet.bllev ? Edited : UnEdited); + pastlev->setEditedState (pedited->wavelet.pastlev ? Edited : UnEdited); + satlev->setEditedState (pedited->wavelet.satlev ? Edited : UnEdited); + + for(int i = 0; i < 9; i++) { + correction[i]->setEditedState (pedited->wavelet.c[i] ? Edited : UnEdited); + } + } + ccshape->setCurve (pp->wavelet.clvcurve); + opacityShapeRG->setCurve (pp->wavelet.opacityCurveRG); + opacityShapeBY->setCurve (pp->wavelet.opacityCurveBY); + + enaConn.block (true); + enabled->set_active (pp->wavelet.enabled); + enaConn.block (false); + avoidConn.block (true); + avoid->set_active (pp->wavelet.avoid); + avoidConn.block (false); + displayConn.block (true); + display->set_active (pp->wavelet.display); + displayConn.block (false); + lastdisplay = pp->wavelet.display; + medianConn.block (true); + median->set_active (pp->wavelet.median); + medianConn.block (false); + lastmedian = pp->wavelet.median; + lastEnabled = pp->wavelet.enabled; + lastavoid = pp->wavelet.avoid; + tiles->setValue (pp->wavelet.tiles); + rescon->setValue (pp->wavelet.rescon); + resconH->setValue (pp->wavelet.resconH); + reschro->setValue (pp->wavelet.reschro); + sup->setValue (pp->wavelet.sup); + sky->setValue (pp->wavelet.sky); + thres->setValue (pp->wavelet.thres); + chroma->setValue (pp->wavelet.chroma); + chro->setValue (pp->wavelet.chro); + unif->setValue (pp->wavelet.unif); + thr->setValue (pp->wavelet.thr); + thrH->setValue (pp->wavelet.thrH); + skinprotect->setValue(pp->wavelet.skinprotect); + hueskin->setValue(pp->wavelet.hueskin); + hueskin2->setValue(pp->wavelet.hueskin2); + threshold->setValue(pp->wavelet.threshold); + threshold2->setValue(pp->wavelet.threshold2); + hllev->setValue(pp->wavelet.hllev); + bllev->setValue(pp->wavelet.bllev); + pastlev->setValue(pp->wavelet.pastlev); + satlev->setValue(pp->wavelet.satlev); + + for (int i = 0; i < 9; i++) { + correction[i]->setValue(pp->wavelet.c[i]); + } + int y; + y=thres->getValue(); + int z; +// for(z=y;z<9;z++) correction[z]->set_sensitive (false); +// for(z=0;zset_sensitive (true); + for(z=y;z<9;z++) correction[z]->hide(); + for(z=0;zshow(); + if(z==9) sup->show(); else sup->hide(); + Lmethodconn.block(false); + CLmethodconn.block(false); + Tilesmethodconn.block(false); + CHmethodconn.block(false); + HSmethodconn.block(false); + Dirmethodconn.block(false); + + enableListener (); +} +void Wavelet::setEditProvider (EditDataProvider *provider) { + ccshape->setEditProvider(provider); +} +void Wavelet::autoOpenCurve () { + ccshape->openIfNonlinear(); + //opacityShapeRG->openIfNonlinear(); + //opacityShapeBY->openIfNonlinear(); +} + +void Wavelet::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->wavelet.enabled = enabled->get_active (); + pp->wavelet.avoid = avoid->get_active (); + pp->wavelet.tiles = tiles->getValue(); + pp->wavelet.rescon = rescon->getValue(); + pp->wavelet.resconH = resconH->getValue(); + pp->wavelet.reschro = reschro->getValue(); + pp->wavelet.sup = sup->getValue(); + pp->wavelet.sky = sky->getValue(); + pp->wavelet.thres = thres->getValue(); + pp->wavelet.display = display->get_active (); + pp->wavelet.chroma = chroma->getValue(); + pp->wavelet.chro = chro->getValue(); + pp->wavelet.median = median->get_active (); + pp->wavelet.unif = unif->getValue(); + pp->wavelet.thr = thr->getValue(); + pp->wavelet.thrH = thrH->getValue(); + pp->wavelet.hueskin = hueskin->getValue (); + pp->wavelet.hueskin2 = hueskin2->getValue (); + pp->wavelet.skinprotect = skinprotect->getValue(); + pp->wavelet.threshold = threshold->getValue(); + pp->wavelet.threshold2 = threshold2->getValue(); + pp->wavelet.hllev = hllev->getValue (); + pp->wavelet.bllev = bllev->getValue (); + pp->wavelet.clvcurve = ccshape->getCurve (); + pp->wavelet.opacityCurveRG = opacityShapeRG->getCurve (); + pp->wavelet.opacityCurveBY = opacityShapeBY->getCurve (); + pp->wavelet.pastlev = pastlev->getValue (); + pp->wavelet.satlev = satlev->getValue (); + + for (int i = 0; i < 9; i++) { + pp->wavelet.c[i] = (int) correction[i]->getValue(); + } + + if (pedited) { + pedited->wavelet.enabled = !enabled->get_inconsistent(); + pedited->wavelet.avoid = !avoid->get_inconsistent(); + pedited->wavelet.display = !display->get_inconsistent(); + pedited->wavelet.median = !median->get_inconsistent(); + pedited->wavelet.Lmethod = Lmethod->get_active_row_number() != 8; + pedited->wavelet.CLmethod = CLmethod->get_active_row_number() != 3; + pedited->wavelet.Tilesmethod = Tilesmethod->get_active_row_number() != 2; + pedited->wavelet.CHmethod = CHmethod->get_active_row_number() != 2; + pedited->wavelet.HSmethod = HSmethod->get_active_row_number() != 1; + pedited->wavelet.Dirmethod = Dirmethod->get_active_row_number() != 3; + pedited->wavelet.tiles = tiles->getEditedState(); + pedited->wavelet.rescon = rescon->getEditedState(); + pedited->wavelet.resconH = resconH->getEditedState(); + pedited->wavelet.reschro = reschro->getEditedState(); + pedited->wavelet.sup = sup->getEditedState(); + pedited->wavelet.sky = sky->getEditedState(); + pedited->wavelet.thres = thres->getEditedState(); + pedited->wavelet.threshold = threshold->getEditedState(); + pedited->wavelet.threshold2 = threshold2->getEditedState(); + pedited->wavelet.chroma = chroma->getEditedState(); + pedited->wavelet.chro = chro->getEditedState(); + pedited->wavelet.unif = unif->getEditedState(); + pedited->wavelet.thr = thr->getEditedState(); + pedited->wavelet.thrH = thrH->getEditedState(); + pedited->wavelet.hueskin = hueskin->getEditedState (); + pedited->wavelet.hueskin2 = hueskin2->getEditedState (); + pedited->wavelet.skinprotect = skinprotect->getEditedState(); + pedited->wavelet.hllev = hllev->getEditedState (); + pedited->wavelet.clvcurve = !ccshape->isUnChanged (); + pedited->wavelet.opacityCurveRG = !opacityShapeRG->isUnChanged (); + pedited->wavelet.opacityCurveBY = !opacityShapeBY->isUnChanged (); + pedited->wavelet.bllev = bllev->getEditedState (); + pedited->wavelet.pastlev = pastlev->getEditedState (); + pedited->wavelet.satlev = satlev->getEditedState (); + + for(int i = 0; i < 9; i++) { + pedited->wavelet.c[i] = correction[i]->getEditedState(); + } + } + if (CHmethod->get_active_row_number()==0) + pp->wavelet.CHmethod = "without"; + else if (CHmethod->get_active_row_number()==1) + pp->wavelet.CHmethod = "with"; + else if (CHmethod->get_active_row_number()==2) + pp->wavelet.CHmethod = "link"; + + if (HSmethod->get_active_row_number()==0) + pp->wavelet.HSmethod = "without"; + else if (HSmethod->get_active_row_number()==1) + pp->wavelet.HSmethod = "with"; + + if (CLmethod->get_active_row_number()==0) + pp->wavelet.CLmethod = "one"; + else if (CLmethod->get_active_row_number()==1) + pp->wavelet.CLmethod = "inf"; + else if (CLmethod->get_active_row_number()==2) + pp->wavelet.CLmethod = "sup"; + else if (CLmethod->get_active_row_number()==3) + pp->wavelet.CLmethod = "all"; + + if (Tilesmethod->get_active_row_number()==0) + pp->wavelet.Tilesmethod = "full"; + else if (Tilesmethod->get_active_row_number()==1) + pp->wavelet.Tilesmethod = "big"; + else if (Tilesmethod->get_active_row_number()==2) + pp->wavelet.Tilesmethod = "lit"; + + if (Dirmethod->get_active_row_number()==0) + pp->wavelet.Dirmethod = "one"; + else if (Dirmethod->get_active_row_number()==1) + pp->wavelet.Dirmethod = "two"; + else if (Dirmethod->get_active_row_number()==2) + pp->wavelet.Dirmethod = "thr"; + else if (Dirmethod->get_active_row_number()==3) + pp->wavelet.Dirmethod = "all"; + + if (Lmethod->get_active_row_number()==0) + pp->wavelet.Lmethod = "0_"; + else if (Lmethod->get_active_row_number()==1) + pp->wavelet.Lmethod = "1_"; + else if (Lmethod->get_active_row_number()==2) + pp->wavelet.Lmethod = "2_"; + else if (Lmethod->get_active_row_number()==3) + pp->wavelet.Lmethod = "3_"; + else if (Lmethod->get_active_row_number()==4) + pp->wavelet.Lmethod = "4_"; + else if (Lmethod->get_active_row_number()==5) + pp->wavelet.Lmethod = "5_"; + else if (Lmethod->get_active_row_number()==6) + pp->wavelet.Lmethod = "6_"; + else if (Lmethod->get_active_row_number()==7) + pp->wavelet.Lmethod = "7_"; + else if (Lmethod->get_active_row_number()==8) + pp->wavelet.Lmethod = "8_"; + + + +} +void Wavelet::curveChanged (CurveEditor* ce) { + + if (listener && enabled->get_active()) { + if (ce == ccshape) + listener->panelChanged (EvWavCLVCurve, M("HISTORY_CUSTOMCURVE")); + else if (ce == opacityShapeRG) + listener->panelChanged (EvWavColor, M("HISTORY_CUSTOMCURVE")); + else if (ce == opacityShapeBY) + listener->panelChanged (EvWavOpac, M("HISTORY_CUSTOMCURVE")); + } +} + +void Wavelet::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + for (int i = 0; i < 9; i++) { + correction[i]->setDefault(defParams->wavelet.c[i]); + } + tiles->setDefault (defParams->wavelet.tiles); + rescon->setDefault (defParams->wavelet.rescon); + resconH->setDefault (defParams->wavelet.resconH); + reschro->setDefault (defParams->wavelet.reschro); + sup->setDefault (defParams->wavelet.sup); + sky->setDefault (defParams->wavelet.sky); + thres->setDefault (defParams->wavelet.thres); + threshold->setDefault (defParams->wavelet.threshold); + threshold2->setDefault (defParams->wavelet.threshold2); + chroma->setDefault (defParams->wavelet.chroma); + chro->setDefault (defParams->wavelet.chro); + unif->setDefault (defParams->wavelet.unif); + thr->setDefault (defParams->wavelet.thr); + thrH->setDefault (defParams->wavelet.thrH); + hueskin->setDefault (defParams->wavelet.hueskin); + hueskin2->setDefault (defParams->wavelet.hueskin2); + hllev->setDefault (defParams->wavelet.hllev); + bllev->setDefault (defParams->wavelet.bllev); + pastlev->setDefault (defParams->wavelet.pastlev); + satlev->setDefault (defParams->wavelet.satlev); + + if (pedited) { + tiles->setDefault (defParams->wavelet.tiles); + rescon->setDefault (defParams->wavelet.rescon); + resconH->setDefault (defParams->wavelet.resconH); + reschro->setDefault (defParams->wavelet.reschro); + sup->setDefault (defParams->wavelet.sup); + sky->setDefaultEditedState(pedited->wavelet.sky ? Edited : UnEdited); + thres->setDefaultEditedState(pedited->wavelet.thres ? Edited : UnEdited); + threshold->setDefaultEditedState(pedited->wavelet.threshold ? Edited : UnEdited); + threshold2->setDefaultEditedState(pedited->wavelet.threshold2 ? Edited : UnEdited); + chroma->setDefaultEditedState(pedited->wavelet.chroma ? Edited : UnEdited); + chro->setDefaultEditedState(pedited->wavelet.chro ? Edited : UnEdited); + unif->setDefaultEditedState(pedited->wavelet.unif ? Edited : UnEdited); + thr->setDefaultEditedState(pedited->wavelet.thr ? Edited : UnEdited); + thrH->setDefaultEditedState(pedited->wavelet.thrH ? Edited : UnEdited); + skinprotect->setDefaultEditedState(pedited->wavelet.skinprotect ? Edited : UnEdited); + hueskin->setDefaultEditedState (pedited->wavelet.hueskin ? Edited : UnEdited); + hueskin2->setDefaultEditedState (pedited->wavelet.hueskin2 ? Edited : UnEdited); + hllev->setDefaultEditedState (pedited->wavelet.hllev ? Edited : UnEdited); + bllev->setDefaultEditedState (pedited->wavelet.bllev ? Edited : UnEdited); + pastlev->setDefaultEditedState (pedited->wavelet.pastlev ? Edited : UnEdited); + satlev->setDefaultEditedState (pedited->wavelet.satlev ? Edited : UnEdited); + + for (int i = 0; i < 9; i++) { + correction[i]->setDefaultEditedState(pedited->wavelet.c[i] ? Edited : UnEdited); + } + } + else { + tiles->setDefaultEditedState(Irrelevant); + rescon->setDefaultEditedState(Irrelevant); + resconH->setDefaultEditedState(Irrelevant); + reschro->setDefaultEditedState(Irrelevant); + sup->setDefaultEditedState(Irrelevant); + sky->setDefaultEditedState(Irrelevant); + thres->setDefaultEditedState(Irrelevant); + threshold->setDefaultEditedState(Irrelevant); + threshold2->setDefaultEditedState(Irrelevant); + chroma->setDefaultEditedState(Irrelevant); + chro->setDefaultEditedState(Irrelevant); + unif->setDefaultEditedState(Irrelevant); + thr->setDefaultEditedState(Irrelevant); + thrH->setDefaultEditedState(Irrelevant); + skinprotect->setDefaultEditedState(Irrelevant); + hueskin->setDefaultEditedState (Irrelevant); + hueskin2->setDefaultEditedState (Irrelevant); + hllev->setDefaultEditedState (Irrelevant); + bllev->setDefaultEditedState (Irrelevant); + pastlev->setDefaultEditedState (Irrelevant); + satlev->setDefaultEditedState (Irrelevant); + + for (int i = 0; i < 9; i++) { + correction[i]->setDefaultEditedState(Irrelevant); + } + } +} + + +void Wavelet::adjusterChanged2 (ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR) { + if (listener && (multiImage||enabled->get_active()) ) { + if(a==hueskin) { + listener->panelChanged (EvWavHueskin,hueskin->getHistoryString()); + } + else if(a==hueskin2) { + listener->panelChanged (EvWavHueskin2,hueskin2->getHistoryString()); + } + else if(a==hllev) { + listener->panelChanged (EvWavlhl,hllev->getHistoryString()); + } + else if(a==bllev) { + listener->panelChanged (EvWavlbl,bllev->getHistoryString()); + } + else if(a==pastlev) { + listener->panelChanged (EvWavpast,pastlev->getHistoryString()); + } + else if(a==satlev) { + listener->panelChanged (EvWavsat,satlev->getHistoryString()); + } + + } +} +void Wavelet::HSmethodChanged() { + if (!batchMode) { + if(HSmethod->get_active_row_number()==0) {//without + hllev->hide(); + bllev->hide(); + threshold->hide(); + threshold2->hide(); + } + else {//with + hllev->show(); + bllev->show(); + threshold->show(); + threshold2->show(); + } + } + + if (listener && (multiImage||enabled->get_active()) ) { + listener->panelChanged (EvWavHSmet, HSmethod->get_active_text ()); + } +} + +void Wavelet::CHmethodChanged() { + if (!batchMode) { + if(CHmethod->get_active_row_number()==0) {//without + pastlev->hide(); + satlev->hide(); + chroma->hide(); + chro->hide(); + CLVcurveEditorG->show(); + } + else if(CHmethod->get_active_row_number()==1) {//with + pastlev->show(); + satlev->show(); + chroma->show(); + chro->hide(); + CLVcurveEditorG->show(); + } + else {//link + chro->show(); + pastlev->hide(); + satlev->hide(); + chroma->hide(); + CLVcurveEditorG->hide(); + } + } + + if (listener && (multiImage||enabled->get_active()) ) { + listener->panelChanged (EvWavCHmet, CHmethod->get_active_text ()); + } +} + +void Wavelet::CLmethodChanged() { + if (!batchMode) { + } + if (listener && (multiImage||enabled->get_active()) ) { + listener->panelChanged (EvWavCLmet, CLmethod->get_active_text ()); + } +} + +void Wavelet::TilesmethodChanged() { + if (!batchMode) { + } + if (listener && (multiImage||enabled->get_active()) ) { + listener->panelChanged (EvWavTilesmet, Tilesmethod->get_active_text ()); + } +} + +void Wavelet::DirmethodChanged() { + if (!batchMode) { + } + if (listener && (multiImage||enabled->get_active()) ) { + listener->panelChanged (EvWavDirmeto, Dirmethod->get_active_text ()); + } +} + +void Wavelet::LmethodChanged() { + if (!batchMode) { + } + if (listener && (multiImage||enabled->get_active()) ) { + listener->panelChanged (EvWavLmet, Lmethod->get_active_text ()); + } +} + +void Wavelet::setBatchMode (bool batchMode) { + Lmethod->append_text (M("GENERAL_UNCHANGED")); + CLmethod->append_text (M("GENERAL_UNCHANGED")); + Tilesmethod->append_text (M("GENERAL_UNCHANGED")); + CHmethod->append_text (M("GENERAL_UNCHANGED")); + HSmethod->append_text (M("GENERAL_UNCHANGED")); + Dirmethod->append_text (M("GENERAL_UNCHANGED")); + CLVcurveEditorG->setBatchMode (batchMode); + opaCurveEditorG->setBatchMode (batchMode); + opacityCurveEditorG->setBatchMode (batchMode); + tiles->showEditedCB (); + rescon->showEditedCB (); + resconH->showEditedCB (); + reschro->showEditedCB (); + sup->showEditedCB (); + sky->showEditedCB (); + thres->showEditedCB (); + threshold->showEditedCB (); + threshold2->showEditedCB (); + chroma->showEditedCB (); + chro->showEditedCB (); + unif->showEditedCB (); + thr->showEditedCB (); + thrH->showEditedCB (); + skinprotect->showEditedCB(); + hueskin->showEditedCB (); + hueskin2->showEditedCB (); + hllev->showEditedCB (); + bllev->showEditedCB (); + pastlev->showEditedCB (); + satlev->showEditedCB (); + ToolPanel::setBatchMode (batchMode); + + for (int i = 0; i < 9; i++) { + correction[i]->showEditedCB(); + } +} + +void Wavelet::adjusterChanged (Adjuster* a, double newval) { + if (listener && enabled->get_active()) { + if (a == tiles) { + listener->panelChanged (EvWavtiles, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), tiles->getValue())) + ); + } + else if (a == rescon ) { + listener->panelChanged (EvWavrescon, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), rescon->getValue())) + ); + } + else if (a == resconH ) { + listener->panelChanged (EvWavresconH, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), resconH->getValue())) + ); + } + + else if (a == reschro ) { + listener->panelChanged (EvWavreschro, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), reschro->getValue())) + ); + } + + else if (a == sky ) { + listener->panelChanged (EvWavsky, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(2), sky->getValue())) + ); + } + else if (a == sup ) { + listener->panelChanged (EvWavsup, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), sup->getValue())) + ); + } + + else if (a == chroma ) { + listener->panelChanged (EvWavchroma, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), chroma->getValue())) + ); + } + else if (a == chro ) { + listener->panelChanged (EvWavchro, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), chro->getValue())) + ); + } + else if (a == unif ) { + listener->panelChanged (EvWavunif, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), unif->getValue())) + ); + } + else if (a == thr ) { + listener->panelChanged (EvWavthr, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), thr->getValue())) + ); + } + else if (a == thrH ) { + listener->panelChanged (EvWavthrH, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), thrH->getValue())) + ); + } + else if (a == threshold ) { + listener->panelChanged (EvWavThreshold, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), threshold->getValue())) + ); + } + else if (a == threshold2 ) { + listener->panelChanged (EvWavThreshold2, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), threshold2->getValue())) + ); + } + + else if (a == thres ) { + int y; + y=thres->getValue(); + int z; + // for(z=y;z<9;z++) correction[z]->set_sensitive (false);; + // for(z=0;zset_sensitive (true);; + for(z=y;z<9;z++) correction[z]->hide(); + for(z=0;zshow(); + if(z==9) sup->show(); else sup->hide(); + + listener->panelChanged (EvWavthres, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(0), thres->getValue())) + ); + } + else if (a == skinprotect) { + listener->panelChanged (EvWavSkin, + Glib::ustring::compose("%1", + Glib::ustring::format(std::fixed, std::setprecision(2), skinprotect->getValue())) + ); + } + + + else { + listener->panelChanged (EvWavelet, + Glib::ustring::compose("%1, %2, %3, %4, %5, %6, %7, %8, %9", + Glib::ustring::format(std::fixed, std::setprecision(0), correction[0]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(0), correction[1]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(0), correction[2]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(0), correction[3]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(0), correction[4]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(0), correction[5]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(0), correction[6]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(0), correction[7]->getValue()), + Glib::ustring::format(std::fixed, std::setprecision(0), correction[8]->getValue())) + ); + } + } +} + +void Wavelet::enabledToggled () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + enaConn.block (true); + enabled->set_active (false); + enaConn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + else { + int y=thres->getValue(); + int z; + for(z=y;z<9;z++) correction[z]->hide(); + for(z=0;zshow(); + if(z==9) sup->show(); else sup->hide(); + } + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvWavEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvWavEnabled, M("GENERAL_DISABLED")); + } +} + +void Wavelet::medianToggled () { + + if (batchMode) { + if (median->get_inconsistent()) { + median->set_inconsistent (false); + medianConn.block (true); + median->set_active (false); + medianConn.block (false); + } + else if (lastmedian) + median->set_inconsistent (true); + + lastmedian = median->get_active (); + } + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvWavmedian, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvWavmedian, M("GENERAL_DISABLED")); + } +} + +void Wavelet::avoidToggled () { + + if (batchMode) { + if (avoid->get_inconsistent()) { + avoid->set_inconsistent (false); + avoidConn.block (true); + avoid->set_active (false); + avoidConn.block (false); + } + else if (lastavoid) + avoid->set_inconsistent (true); + + lastavoid = avoid->get_active (); + } + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvWavavoid, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvWavavoid, M("GENERAL_DISABLED")); + } +} + +void Wavelet::displayToggled () { + + if (batchMode) { + if (display->get_inconsistent()) { + display->set_inconsistent (false); + displayConn.block (true); + display->set_active (false); + displayConn.block (false); + } + else if (lastdisplay) + display->set_inconsistent (true); + + lastdisplay = display->get_active (); + } + if (display->get_active ()) { + utilFrame->show(); + dispFrame->show(); + } + else { + utilFrame->hide(); + dispFrame->hide(); + + } + /* + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvEqldisplay, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvEqldisplay, M("GENERAL_DISABLED")); + } + */ +} +void Wavelet::colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller) { + + float R, G, B; + + if (elemType==ColorCaller::CCET_VERTICAL_BAR) + valY = 0.5; + + if (callerId == 1) { // ch - main curve + + Color::hsv2rgb01(float(valX), float(valY), 0.5f, R, G, B); + } +/* else if (callerId == 2) { // cc - bottom bar + + // float value = (1.f - 0.7f) * float(valX) + 0.7f; + float value = (1.f - 0.7f) * float(valX) + 0.7f; + // whole hue range + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) + Color::hsv2rgb01(float(valY), float(valX), value, R, G, B); + } + */ + else if (callerId == 4) { // LH - bottom bar + Color::hsv2rgb01(float(valX), 0.5f, float(valY), R, G, B); + } + else if (callerId == 5) { // HH - bottom bar + float h = float((valY - 0.5) * 0.3 + valX); + if (h > 1.0f) + h -= 1.0f; + else if (h < 0.0f) + h += 1.0f; + Color::hsv2rgb01(h, 0.5f, 0.5f, R, G, B); + } + caller->ccRed = double(R); + caller->ccGreen = double(G); + caller->ccBlue = double(B); +} +void Wavelet::setAdjusterBehavior (bool multiplieradd, bool thresholdadd, bool threshold2add, bool thresadd, bool chroadd,bool chromaadd, bool unifadd, bool skinadd, bool reschroadd, bool resconadd, bool resconHadd, bool thradd, bool thrHadd, bool skyadd ) { + + for (int i=0; i<9; i++) + correction[i]->setAddMode(multiplieradd); + threshold->setAddMode(thresholdadd); + skinprotect->setAddMode(skinadd); + threshold2->setAddMode(threshold2add); + thres->setAddMode(thresadd); + chro->setAddMode(chroadd); + chroma->setAddMode(chromaadd); + unif->setAddMode(unifadd); + rescon->setAddMode(resconadd); + resconH->setAddMode(resconHadd); + reschro->setAddMode(reschroadd); + thr->setAddMode(thradd); + thrH->setAddMode(thrHadd); + sky->setAddMode(skyadd); + +} + + +void Wavelet::neutralPressed () { + + for (int i = 0; i < 9; i++) { + correction[i]->setValue(0); + adjusterChanged(correction[i], 0); + } +} + + +void Wavelet::contrastPlusPressed () { + + for (int i = 0; i < 9; i++) { + int inc = 1 * (9 - i); + correction[i]->setValue(correction[i]->getValue() + inc); + adjusterChanged(correction[i], correction[i]->getValue()); + } +} + + +void Wavelet::contrastMinusPressed () { + + for (int i = 0; i < 9; i++) { + int inc = -1 * (9 - i); + correction[i]->setValue(correction[i]->getValue() + inc); + adjusterChanged(correction[i], correction[i]->getValue()); + } +} + diff --git a/rtgui/wavelet.h b/rtgui/wavelet.h new file mode 100644 index 000000000..dba303664 --- /dev/null +++ b/rtgui/wavelet.h @@ -0,0 +1,139 @@ +/* + * This file is part of RawTherapee. + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + * + * 2014 Jacques Desmis + */ + +#ifndef WAVELET_H_INCLUDED +#define WAVELET_H_INCLUDED + +#include +#include "adjuster.h" +#include "toolpanel.h" +#include "curveeditor.h" +#include "curveeditorgroup.h" +#include "thresholdadjuster.h" +#include "colorprovider.h" +#include "guiutils.h" +#include "options.h" + +class Wavelet : public ToolParamBlock, public ThresholdAdjusterListener, public AdjusterListener, public CurveListener, public ColorProvider, public rtengine::WaveletListener, public FoldableToolPanel +{ +protected: + Glib::RefPtr bgTTips; + Glib::RefPtr srTTips; + Glib::RefPtr bgPixbuf; + Glib::RefPtr srPixbuf; + + CurveEditorGroup* CLVcurveEditorG; + Gtk::HSeparator* colorSep; + CurveEditorGroup* opaCurveEditorG; + FlatCurveEditor* opacityShapeRG; + CurveEditorGroup* opacityCurveEditorG; + FlatCurveEditor* opacityShapeBY; + + FlatCurveEditor* ccshape; + Gtk::CheckButton * enabled; + Gtk::CheckButton * display; + Gtk::CheckButton * median; + Gtk::CheckButton * avoid; + Adjuster* correction[9]; + Adjuster* tiles; + Adjuster* rescon; + Adjuster* resconH; + Adjuster* reschro; + Adjuster* sup; + Adjuster* sky; + Adjuster* thres; + Adjuster* chroma; + Adjuster* chro; + Adjuster* unif; + Adjuster* thr; + Adjuster* thrH; + Adjuster* skinprotect; + ThresholdAdjuster* hueskin; + ThresholdAdjuster* hueskin2; + ThresholdAdjuster* hllev; + ThresholdAdjuster* bllev; + ThresholdAdjuster* pastlev; + ThresholdAdjuster* satlev; + Adjuster* threshold; + Adjuster* threshold2; + MyComboBoxText* Lmethod; + sigc::connection Lmethodconn; + MyComboBoxText* CHmethod; + sigc::connection CHmethodconn; + MyComboBoxText* HSmethod; + sigc::connection HSmethodconn; + MyComboBoxText* CLmethod; + sigc::connection CLmethodconn; + MyComboBoxText* Tilesmethod; + sigc::connection Tilesmethodconn; + MyComboBoxText* Dirmethod; + sigc::connection Dirmethodconn; + Gtk::Frame* toningFrame; + Gtk::Frame* residualFrame; + Gtk::Frame* utilFrame; + Gtk::Frame* dispFrame; + Gtk::Label* colLabel; + Gtk::Label* interLabel; + Gtk::Label* wavLabels; + + sigc::connection enaConn, displayConn, medianConn, avoidConn; + sigc::connection neutralPressedConn; + sigc::connection contrastPlusPressedConn; + sigc::connection contrastMinusPressedConn; + + bool lastEnabled, lastdisplay, lastmedian, lastavoid; + int nextnlevel; + +public: + + Wavelet (); + virtual ~Wavelet (); + void curveChanged (CurveEditor* ce); + void setEditProvider (EditDataProvider *provider); + void autoOpenCurve (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void adjusterChanged2 (ThresholdAdjuster* a, int newBottomL, int newTopL, int newBottomR, int newTopR); + void setAdjusterBehavior (bool multiplieradd, bool thresholdadd, bool threshold2add, bool thresadd, bool chroadd,bool chromaadd, bool unifadd, bool skinadd, bool reschroadd, bool resconadd, bool resconHadd, bool thradd, bool thrHadd, bool skyadd); + + void adjusterChanged (Adjuster* a, double newval); + void enabledToggled (); + void displayToggled (); + void medianToggled (); + void avoidToggled (); + void neutralPressed (); + void contrastPlusPressed (); + void contrastMinusPressed (); + void LmethodChanged (); + void CHmethodChanged (); + void HSmethodChanged (); + void CLmethodChanged (); + void TilesmethodChanged (); + void DirmethodChanged (); + virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller); + void wavChanged (double nlevel); + bool wavComputed_ (); + void updatewavLabel (); + +}; + +#endif