From 1892bbf7724ddc01835a4e1e77fd793358c4389b Mon Sep 17 00:00:00 2001 From: Desmis Date: Sat, 7 Nov 2015 18:47:37 +0100 Subject: [PATCH 1/9] Init retinex add tone-mapping --- rtdata/languages/default | 10 +- rtengine/ipretinex.cc | 533 ++++++++++++++++++++++----------------- rtengine/procevents.h | 2 + rtengine/procparams.cc | 28 ++ rtengine/procparams.h | 2 + rtengine/refreshmap.cc | 5 +- rtgui/paramsedited.cc | 16 ++ rtgui/paramsedited.h | 2 + rtgui/retinex.cc | 70 ++++- rtgui/retinex.h | 2 + 10 files changed, 428 insertions(+), 242 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index ee6952559..aeb5664e8 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -641,7 +641,7 @@ HISTORY_MSG_408;Retinex - Neighboring HISTORY_MSG_409;Retinex - Gain HISTORY_MSG_410;Retinex - Offset HISTORY_MSG_411;Retinex - Strength -HISTORY_MSG_412;Retinex - Scales +HISTORY_MSG_412;Retinex - G. Gradient HISTORY_MSG_413;Retinex - Variance HISTORY_MSG_414;Retinex - Histogram - Lab HISTORY_MSG_415;Retinex - Transmission @@ -656,6 +656,8 @@ HISTORY_MSG_423;Retinex - Gamma slope HISTORY_MSG_424;Retinex - HL threshold HISTORY_MSG_425;Retinex - Log base HISTORY_MSG_426;Retinex - Hue equalizer +HISTORY_MSG_427;Retinex - Iterations +HISTORY_MSG_428;Retinex - T. Gradient HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOTS;Snapshots @@ -1654,6 +1656,10 @@ TP_RETINEX_HIGHLIG;Highlight TP_RETINEX_HIGH;High TP_RETINEX_HSLSPACE_LIN;HSL-Linear TP_RETINEX_HSLSPACE_LOG;HSL-Logarithmic +TP_RETINEX_ITER;Iterations (Tone-mapping) +TP_RETINEX_ITER_TOOLTIP;Simulate a tone-mapping operator\nHigh values increase the processing time +TP_RETINEX_GRAD;Transmission gradient +TP_RETINEX_GRAD_TOOLTIP;If slider at 0, all iterations are identical\nIf > 0 Variance and Threshold are reduce when iteration increases and conversely TP_RETINEX_LABEL;Retinex TP_RETINEX_LABSPACE;L*a*b* TP_RETINEX_LOW;Low @@ -1667,6 +1673,8 @@ TP_RETINEX_NEUTRAL;Reset TP_RETINEX_NEUTRAL_TIP;Reset all sliders and curves to their default values. TP_RETINEX_OFFSET;Offset TP_RETINEX_SETTINGS;Settings +TP_RETINEX_SCALES;Gaussian gradient +TP_RETINEX_SCALES_TOOLTIP;If slider at 0, all iterations are identical\nIf > 0 Scale and Neighboring pixels are reduce when iteration increases and conversely TP_RETINEX_SLOPE;Free gamma slope TP_RETINEX_STRENGTH;Strength TP_RETINEX_THRESHOLD;Threshold diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 54d5d3515..1f6602b62 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -217,10 +217,12 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e float gain2 = (float) deh.gain / 100.f; //def =1 not use gain2 = useHslLin ? gain2 * 0.5f : gain2; float offse = (float) deh.offs; //def = 0 not use - int scal = deh.scal; //def=3 - scal = 3;//disabled scal + int iter = deh.iter; + int gradient = deh.scal; + int scal = 3;//disabled scal int nei = (int) 2.8f * deh.neigh; //def = 220 float vart = (float)deh.vart / 100.f;//variance + float gradvart = (float)deh.grad; float strength = (float) deh.str / 100.f; // Blend with original L channel data float limD = (float) deh.limd; limD = pow(limD, 1.7f);//about 2500 enough @@ -271,283 +273,342 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e if (deh.retinexMethod == "highli" || deh.retinexMethod == "highliplus") { moderetinex = 3; } - - float aahi = 49.f / 99.f; ////reduce sensibility 50% - float bbhi = 1.f - aahi; - float high; - high = bbhi + aahi * (float) deh.highl; - retinex_scales( RetinexScales, scal, moderetinex, nei, high ); - - int H_L = height; - int W_L = width; - - float *src[H_L] ALIGNED16; - float *srcBuffer = new float[H_L * W_L]; - - for (int i = 0; i < H_L; i++) { - src[i] = &srcBuffer[i * W_L]; - } - -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int i = 0; i < H_L; i++) - for (int j = 0; j < W_L; j++) { - src[i][j] = luminance[i][j] + eps; - luminance[i][j] = 0.f; + for(int it=1; it= 0; scale-- ) { - if(scale == scal - 1) { - gaussianBlur (src, out, W_L, H_L, RetinexScales[scale], buffer); - } else { // reuse result of last iteration - gaussianBlur (out, out, W_L, H_L, sqrtf(SQR(RetinexScales[scale]) - SQR(RetinexScales[scale + 1])), buffer); + else if(gradient==1) { + grad=0.25f*it+0.75f; + sc=-0.5f*it+4.5f; + } + else if(gradient==2) { + grad=0.5f*it+0.5f; + sc=-it+6.f; + } + else if(gradient==3) { + grad=0.666f*it+0.333f; + sc=-it+6.f; + } + else if(gradient==4) { + grad=0.8f*it+0.2f; + sc=-it+6.f; + } + else if(gradient==5) { + grad=0.9f*it+0.1f; + sc=-it+6.f; + } + else if(gradient==-1) { + grad=-0.125f*it+1.125f; + sc=3.f; + } + float varx; + float limdx, ilimdx; + if(gradvart!=0) { + if(gradvart==1) { + varx=vart*(-0.125f*it+1.125f); + limdx=limD*(-0.125f*it+1.125f); + ilimdx=1.f/limdx; } - -#ifdef __SSE2__ - vfloat pondv = F2V(pond); - vfloat limMinv = F2V(ilimD); - vfloat limMaxv = F2V(limD); - -#endif -#ifdef _OPENMP - #pragma omp for -#endif - - for (int i = 0; i < H_L; i++) { - int j = 0; - -#ifdef __SSE2__ - - if(useHslLin) { - for (; j < W_L - 3; j += 4) { - _mm_storeu_ps(&luminance[i][j], LVFU(luminance[i][j]) + pondv * (LIMV(LVFU(src[i][j]) / LVFU(out[i][j]), limMinv, limMaxv) )); - } - } else { - for (; j < W_L - 3; j += 4) { - _mm_storeu_ps(&luminance[i][j], LVFU(luminance[i][j]) + pondv * xlogf(LIMV(LVFU(src[i][j]) / LVFU(out[i][j]), limMinv, limMaxv) )); - } - } - -#endif - - if(useHslLin) { - for (; j < W_L; j++) { - luminance[i][j] += pond * (LIM(src[i][j] / out[i][j], ilimD, limD)); - } - } else { - for (; j < W_L; j++) { - luminance[i][j] += pond * xlogf(LIM(src[i][j] / out[i][j], ilimD, limD)); // /logt ? - } - } + else if(gradvart==2) { + varx=vart*(-0.2f*it+1.2f); + limdx=limD*(-0.2f*it+1.2f); + ilimdx=1.f/limdx; + } + else if(gradvart==-1) { + varx=vart*(0.125f*it+0.875f); + limdx=limD*(0.125f*it+0.875f); + ilimdx=1.f/limdx; + } + else if(gradvart==-2) { + varx=vart*(0.4f*it+0.6f); + limdx=limD*(0.4f*it+0.6f); + ilimdx=1.f/limdx; } } - } - delete [] buffer; - delete [] outBuffer; - delete [] srcBuffer; + else { + varx=vart; + limdx=limD; + ilimdx=ilimD; + } + scal=round(sc); + float aahi = 49.f / 99.f; ////reduce sensibility 50% + float bbhi = 1.f - aahi; + float high; + high = bbhi + aahi * (float) deh.highl; + retinex_scales( RetinexScales, scal, moderetinex, nei/grad, high ); - mean = 0.f; - stddv = 0.f; - // I call mean_stddv2 instead of mean_stddv ==> logBetaGain + int H_L = height; + int W_L = width; - mean_stddv2( luminance, mean, stddv, W_L, H_L, maxtr, mintr); -// printf("mean=%f std=%f delta=%f maxtr=%f mintr=%f\n", mean, stddv, delta, maxtr, mintr); + float *src[H_L] ALIGNED16; + float *srcBuffer = new float[H_L * W_L]; - // mean_stddv( luminance, mean, stddv, W_L, H_L, logBetaGain, maxtr, mintr); - if (dehatransmissionCurve && mean != 0.f && stddv != 0.f) { //if curve - float asig = 0.166666f / stddv; - float bsig = 0.5f - asig * mean; - float amax = 0.333333f / (maxtr - mean - stddv); - float bmax = 1.f - amax * maxtr; - float amin = 0.333333f / (mean - stddv - mintr); - float bmin = -amin * mintr; + for (int i = 0; i < H_L; i++) { + src[i] = &srcBuffer[i * W_L]; + } - asig *= 500.f; - bsig *= 500.f; - amax *= 500.f; - bmax *= 500.f; - amin *= 500.f; - bmin *= 500.f; +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = 0; i < H_L; i++) + for (int j = 0; j < W_L; j++) { + src[i][j] = luminance[i][j] + eps; + luminance[i][j] = 0.f; + } + + float *out[H_L] ALIGNED16; + float *outBuffer = new float[H_L * W_L]; + + for (int i = 0; i < H_L; i++) { + out[i] = &outBuffer[i * W_L]; + } + + const float logBetaGain = xlogf(16384.f); + float pond = logBetaGain / (float) scal; + + if(!useHslLin) { + pond /= log(elogt); + } + + float *buffer = new float[W_L * H_L];; #ifdef _OPENMP #pragma omp parallel #endif { - float absciss; + for ( int scale = scal - 1; scale >= 0; scale-- ) { + if(scale == scal - 1) { + gaussianBlur (src, out, W_L, H_L, RetinexScales[scale], buffer); + } else { // reuse result of last iteration + gaussianBlur (out, out, W_L, H_L, sqrtf(SQR(RetinexScales[scale]) - SQR(RetinexScales[scale + 1])), buffer); + } + +#ifdef __SSE2__ + vfloat pondv = F2V(pond); + vfloat limMinv = F2V(ilimdx); + vfloat limMaxv = F2V(limdx); + +#endif #ifdef _OPENMP - #pragma omp for schedule(dynamic,16) + #pragma omp for #endif - for (int i = 0; i < H_L; i++ ) - for (int j = 0; j < W_L; j++) { //for mintr to maxtr evalate absciss in function of original transmission - if (LIKELY(fabsf(luminance[i][j] - mean) < stddv)) { - absciss = asig * luminance[i][j] + bsig; - } else if (luminance[i][j] >= mean) { - absciss = amax * luminance[i][j] + bmax; - } else { /*if(luminance[i][j] <= mean - stddv)*/ - absciss = amin * luminance[i][j] + bmin; + for (int i = 0; i < H_L; i++) { + int j = 0; + +#ifdef __SSE2__ + + if(useHslLin) { + for (; j < W_L - 3; j += 4) { + _mm_storeu_ps(&luminance[i][j], LVFU(luminance[i][j]) + pondv * (LIMV(LVFU(src[i][j]) / LVFU(out[i][j]), limMinv, limMaxv) )); + } + } else { + for (; j < W_L - 3; j += 4) { + _mm_storeu_ps(&luminance[i][j], LVFU(luminance[i][j]) + pondv * xlogf(LIMV(LVFU(src[i][j]) / LVFU(out[i][j]), limMinv, limMaxv) )); + } } - luminance[i][j] *= (-1.f + 4.f * dehatransmissionCurve[absciss]); //new transmission - } - } - - // median filter on transmission ==> reduce artifacts - if (deh.medianmap) { - int wid = W_L; - int hei = H_L; - float *tmL[hei] ALIGNED16; - float *tmLBuffer = new float[wid * hei]; - int borderL = 1; - - for (int i = 0; i < hei; i++) { - tmL[i] = &tmLBuffer[i * wid]; - } - -#ifdef _OPENMP - #pragma omp parallel for #endif - for (int i = borderL; i < hei - borderL; i++) { - float pp[9], temp; - - for (int j = borderL; j < wid - borderL; j++) { - med3(luminance[i][j], luminance[i - 1][j], luminance[i + 1][j], luminance[i][j + 1], luminance[i][j - 1], luminance[i - 1][j - 1], luminance[i - 1][j + 1], luminance[i + 1][j - 1], luminance[i + 1][j + 1], tmL[i][j]); //3x3 + if(useHslLin) { + for (; j < W_L; j++) { + luminance[i][j] += pond * (LIM(src[i][j] / out[i][j], ilimdx, limdx)); + } + } else { + for (; j < W_L; j++) { + luminance[i][j] += pond * xlogf(LIM(src[i][j] / out[i][j], ilimdx, limdx)); // /logt ? + } + } } } - -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int i = borderL; i < hei - borderL; i++ ) { - for (int j = borderL; j < wid - borderL; j++) { - luminance[i][j] = tmL[i][j]; - } - } - - delete [] tmLBuffer; - } + delete [] buffer; + delete [] outBuffer; + delete [] srcBuffer; + mean = 0.f; + stddv = 0.f; // I call mean_stddv2 instead of mean_stddv ==> logBetaGain - // mean_stddv( luminance, mean, stddv, W_L, H_L, 1.f, maxtr, mintr); + mean_stddv2( luminance, mean, stddv, W_L, H_L, maxtr, mintr); +// printf("mean=%f std=%f delta=%f maxtr=%f mintr=%f\n", mean, stddv, delta, maxtr, mintr); - } - - float epsil = 0.1f; - - mini = mean - vart * stddv; - - if (mini < mintr) { - mini = mintr + epsil; - } - - maxi = mean + vart * stddv; - - if (maxi > maxtr) { - maxi = maxtr - epsil; - } - - delta = maxi - mini; - // printf("maxi=%f mini=%f mean=%f std=%f delta=%f maxtr=%f mintr=%f\n", maxi, mini, mean, stddv, delta, maxtr, mintr); - - if ( !delta ) { - delta = 1.0f; - } - - float cdfactor = gain2 * 32768.f / delta; - maxCD = -9999999.f; - minCD = 9999999.f; - - - + // mean_stddv( luminance, mean, stddv, W_L, H_L, logBetaGain, maxtr, mintr); + if (dehatransmissionCurve && mean != 0.f && stddv != 0.f) { //if curve + float asig = 0.166666f / stddv; + float bsig = 0.5f - asig * mean; + float amax = 0.333333f / (maxtr - mean - stddv); + float bmax = 1.f - amax * maxtr; + float amin = 0.333333f / (mean - stddv - mintr); + float bmin = -amin * mintr; + asig *= 500.f; + bsig *= 500.f; + amax *= 500.f; + bmax *= 500.f; + amin *= 500.f; + bmin *= 500.f; #ifdef _OPENMP - #pragma omp parallel + #pragma omp parallel #endif - { - float cdmax = -999999.f, cdmin = 999999.f; - + { + float absciss; #ifdef _OPENMP - #pragma omp for + #pragma omp for schedule(dynamic,16) #endif - for ( int i = 0; i < H_L; i ++ ) - for (int j = 0; j < W_L; j++) { - // float cd = cdfactor * ( luminance[i][j] * logBetaGain - mini ) + offse; - float cd = cdfactor * ( luminance[i][j] - mini ) + offse; - - if(cd > cdmax) { - cdmax = cd; - } - - if(cd < cdmin) { - cdmin = cd; - } - - float str = strength; - - if(lhutili) { // S=f(H) - { - float HH = exLuminance[i][j]; - float valparam; - - if(useHsl || useHslLin) { - valparam = float((shcurve->getVal(HH) - 0.5f)); - } else { - valparam = float((shcurve->getVal(Color::huelab_to_huehsv2(HH)) - 0.5f)); + for (int i = 0; i < H_L; i++ ) + for (int j = 0; j < W_L; j++) { //for mintr to maxtr evalate absciss in function of original transmission + if (LIKELY(fabsf(luminance[i][j] - mean) < stddv)) { + absciss = asig * luminance[i][j] + bsig; + } else if (luminance[i][j] >= mean) { + absciss = amax * luminance[i][j] + bmax; + } else { /*if(luminance[i][j] <= mean - stddv)*/ + absciss = amin * luminance[i][j] + bmin; } - str *= (1.f + 2.f * valparam); + luminance[i][j] *= (-1.f + 4.f * dehatransmissionCurve[absciss]); //new transmission + } + } + + // median filter on transmission ==> reduce artifacts + if (deh.medianmap && it==1) {//only one time + int wid = W_L; + int hei = H_L; + float *tmL[hei] ALIGNED16; + float *tmLBuffer = new float[wid * hei]; + int borderL = 1; + + for (int i = 0; i < hei; i++) { + tmL[i] = &tmLBuffer[i * wid]; + } + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = borderL; i < hei - borderL; i++) { + float pp[9], temp; + + for (int j = borderL; j < wid - borderL; j++) { + med3(luminance[i][j], luminance[i - 1][j], luminance[i + 1][j], luminance[i][j + 1], luminance[i][j - 1], luminance[i - 1][j - 1], luminance[i - 1][j + 1], luminance[i + 1][j - 1], luminance[i + 1][j + 1], tmL[i][j]); //3x3 } } - // if(exLuminance[i][j] > 65535.f*hig && higplus) str *= hig; - luminance[i][j] = clipretinex( cd, 0.f, 32768.f ) * str + (1.f - str) * originalLuminance[i][j]; +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = borderL; i < hei - borderL; i++ ) { + for (int j = borderL; j < wid - borderL; j++) { + luminance[i][j] = tmL[i][j]; + } + } + + delete [] tmLBuffer; + } -#ifdef _OPENMP - #pragma omp critical -#endif - { - maxCD = maxCD > cdmax ? maxCD : cdmax; - minCD = minCD < cdmin ? minCD : cdmin; + // I call mean_stddv2 instead of mean_stddv ==> logBetaGain + // mean_stddv( luminance, mean, stddv, W_L, H_L, 1.f, maxtr, mintr); + mean_stddv2( luminance, mean, stddv, W_L, H_L, maxtr, mintr); + } - } - // printf("cdmin=%f cdmax=%f\n",minCD, maxCD); - Tmean = mean; - Tsigma = stddv; - Tmin = mintr; - Tmax = maxtr; + float epsil = 0.1f; - if (shcurve) { - delete shcurve; - } + mini = mean - varx * stddv; + if (mini < mintr) { + mini = mintr + epsil; + } + + maxi = mean + varx * stddv; + + if (maxi > maxtr) { + maxi = maxtr - epsil; + } + + delta = maxi - mini; + // printf("maxi=%f mini=%f mean=%f std=%f delta=%f maxtr=%f mintr=%f\n", maxi, mini, mean, stddv, delta, maxtr, mintr); + + if ( !delta ) { + delta = 1.0f; + } + + float cdfactor = gain2 * 32768.f / delta; + maxCD = -9999999.f; + minCD = 9999999.f; + + + + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + float cdmax = -999999.f, cdmin = 999999.f; + +#ifdef _OPENMP + #pragma omp for +#endif + + for ( int i = 0; i < H_L; i ++ ) + for (int j = 0; j < W_L; j++) { + // float cd = cdfactor * ( luminance[i][j] * logBetaGain - mini ) + offse; + float cd = cdfactor * ( luminance[i][j] - mini ) + offse; + + if(cd > cdmax) { + cdmax = cd; + } + + if(cd < cdmin) { + cdmin = cd; + } + + float str = strength; + + if(lhutili) { // S=f(H) + { + float HH = exLuminance[i][j]; + float valparam; + + if(useHsl || useHslLin) { + valparam = float((shcurve->getVal(HH) - 0.5f)); + } else { + valparam = float((shcurve->getVal(Color::huelab_to_huehsv2(HH)) - 0.5f)); + } + + str *= (1.f + 2.f * valparam); + } + } + + // if(exLuminance[i][j] > 65535.f*hig && higplus) str *= hig; + luminance[i][j] = clipretinex( cd, 0.f, 32768.f ) * str + (1.f - str) * originalLuminance[i][j]; + } + +#ifdef _OPENMP + #pragma omp critical +#endif + { + maxCD = maxCD > cdmax ? maxCD : cdmax; + minCD = minCD < cdmin ? minCD : cdmin; + } + + } + // printf("cdmin=%f cdmax=%f\n",minCD, maxCD); + Tmean = mean; + Tsigma = stddv; + Tmin = mintr; + Tmax = maxtr; + + if (shcurve) { + delete shcurve; + } + } } } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 4dbbad07c..ae348316f 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -454,6 +454,8 @@ enum ProcEvent { EvLbaselog = 424, // EvLgrbl = 425, EvRetinexlhcurve = 425, + EvLiter = 426, + EvLgrad = 427, NUMOFEVENTS }; } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index becd8932e..ed57f50d3 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -142,6 +142,8 @@ void RetinexParams::setDefaults() enabled = false; str = 20; scal = 3; + iter = 1; + grad = 1; gam = 1.30; slope = 3.; neigh = 80; @@ -1444,6 +1446,14 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_integer ("Retinex", "Scal", retinex.scal); } + if (!pedited || pedited->retinex.iter) { + keyFile.set_integer ("Retinex", "Iter", retinex.iter); + } + + if (!pedited || pedited->retinex.grad) { + keyFile.set_integer ("Retinex", "Grad", retinex.iter); + } + if (!pedited || pedited->retinex.gam) { keyFile.set_double ("Retinex", "Gam", retinex.gam); } @@ -3851,6 +3861,22 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Retinex", "Iter")) { + retinex.iter = keyFile.get_integer ("Retinex", "Iter"); + + if (pedited) { + pedited->retinex.iter = true; + } + } + + if (keyFile.has_key ("Retinex", "Grad")) { + retinex.grad = keyFile.get_integer ("Retinex", "Grad"); + + if (pedited) { + pedited->retinex.grad = true; + } + } + if (keyFile.has_key ("Retinex", "Gam")) { retinex.gam = keyFile.get_double ("Retinex", "Gam"); @@ -7322,6 +7348,8 @@ bool ProcParams::operator== (const ProcParams& other) && retinex.transmissionCurve == other.retinex.transmissionCurve && retinex.str == other.retinex.str && retinex.scal == other.retinex.scal + && retinex.iter == other.retinex.iter + && retinex.grad == other.retinex.grad && retinex.gam == other.retinex.gam && retinex.slope == other.retinex.slope && retinex.neigh == other.retinex.neigh diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d46fd4181..1226d1584 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -275,6 +275,8 @@ public: std::vector transmissionCurve; int str; int scal; + int iter; + int grad; double gam; double slope; int neigh; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 3505da24f..88338f06c 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -453,6 +453,9 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLhighl DEMOSAIC, // EvLbaselog // DEMOSAIC, // EvLgrbl - DEMOSAIC // EvRetinexlhcurve + DEMOSAIC, // EvRetinexlhcurve + RETINEX, // EvLiter + RETINEX // EvLgrad + }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index ac2fe6523..600a68af4 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -58,6 +58,8 @@ void ParamsEdited::set (bool v) retinex.enabled = v; retinex.str = v; retinex.scal = v; + retinex.iter = v; + retinex.grad = v; retinex.gam = v; retinex.slope = v; retinex.neigh = v; @@ -535,6 +537,8 @@ void ParamsEdited::initFrom (const std::vector retinex.gammaretinex = retinex.gammaretinex && p.retinex.gammaretinex == other.retinex.gammaretinex; retinex.str = retinex.str && p.retinex.str == other.retinex.str; retinex.scal = retinex.scal && p.retinex.scal == other.retinex.scal; + retinex.iter = retinex.iter && p.retinex.iter == other.retinex.iter; + retinex.grad = retinex.grad && p.retinex.grad == other.retinex.grad; retinex.gam = retinex.gam && p.retinex.gam == other.retinex.gam; retinex.slope = retinex.slope && p.retinex.slope == other.retinex.slope; retinex.neigh = retinex.neigh && p.retinex.neigh == other.retinex.neigh; @@ -1082,6 +1086,18 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.retinex.str = dontforceSet && options.baBehav[ADDSET_RETI_STR] ? toEdit.retinex.str + mods.retinex.str : mods.retinex.str; } + if (retinex.scal) { + toEdit.retinex.scal = mods.retinex.scal; + } + + if (retinex.iter) { + toEdit.retinex.iter = mods.retinex.iter; + } + + if (retinex.grad) { + toEdit.retinex.grad = mods.retinex.grad; + } + // if (retinex.scal) { // toEdit.retinex.scal = dontforceSet && options.baBehav[ADDSET_RETI_SCAL] ? toEdit.retinex.scal + mods.retinex.scal : mods.retinex.scal; // } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 3fa753013..ed1f07aec 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -61,6 +61,8 @@ public: bool enabled; bool str; bool scal; + bool iter; + bool grad; bool gam; bool slope; bool neigh; diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index b964ecbb5..0578c3e57 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -144,7 +144,9 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), transLabels->set_tooltip_markup (M("TP_RETINEX_TLABEL_TOOLTIP")); transLabels2 = Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER)); - scal = Gtk::manage (new Adjuster (M("TP_RETINEX_SCALES"), 1, 8., 1., 3.)); + scal = Gtk::manage (new Adjuster (M("TP_RETINEX_SCALES"), -1, 5., 1., 3.)); + iter = Gtk::manage (new Adjuster (M("TP_RETINEX_ITER"), 1, 5., 1., 1.)); + grad = Gtk::manage (new Adjuster (M("TP_RETINEX_GRAD"), -2., 2., 1., 1.)); gain = Gtk::manage (new Adjuster (M("TP_RETINEX_GAIN"), 20, 200, 1, 50)); offs = Gtk::manage (new Adjuster (M("TP_RETINEX_OFFSET"), -10000, 10000, 1, 0)); // vart = Gtk::manage (new Adjuster (M("TP_RETINEX_VARIANCE"), 50, 500, 1, 125)); @@ -153,6 +155,8 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), // grbl = Gtk::manage (new Adjuster (M("TP_RETINEX_HIGHLIGHT3"), 1, 100, 1, 50)); gain->set_tooltip_markup (M("TP_RETINEX_GAIN_TOOLTIP")); scal->set_tooltip_markup (M("TP_RETINEX_SCALES_TOOLTIP")); + iter->set_tooltip_markup (M("TP_RETINEX_ITER_TOOLTIP")); + grad->set_tooltip_markup (M("TP_RETINEX_GRAD_TOOLTIP")); // vart->set_tooltip_markup (M("TP_RETINEX_VARIANCE_TOOLTIP")); limd->set_tooltip_markup (M("TP_RETINEX_THRESHOLD_TOOLTIP")); baselog->set_tooltip_markup (M("TP_RETINEX_BASELOG_TOOLTIP")); @@ -211,8 +215,14 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), slope->show (); -// settingsVBox->pack_start (*scal); -// scal->show (); + settingsVBox->pack_start (*iter); + iter->show (); + + settingsVBox->pack_start (*scal); + scal->show (); + + settingsVBox->pack_start (*grad); + grad->show (); settingsVBox->pack_start (*gain); gain->show (); @@ -267,6 +277,18 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), scal->delay = 200; } + iter->setAdjusterListener (this); + + if (iter->delay < 200) { + iter->delay = 200; + } + + grad->setAdjusterListener (this); + + if (grad->delay < 200) { + grad->delay = 200; + } + gam->setAdjusterListener (this); if (gam->delay < 500) { @@ -354,6 +376,8 @@ void Retinex::neutral_pressed () offs->resetValue(false); str->resetValue(false); scal->resetValue(false); + iter->resetValue(false); + grad->resetValue(false); vart->resetValue(false); limd->resetValue(false); highl->resetValue(false); @@ -477,6 +501,8 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) if (pedited) { scal->setEditedState (pedited->retinex.scal ? Edited : UnEdited); + iter->setEditedState (pedited->retinex.iter ? Edited : UnEdited); + grad->setEditedState (pedited->retinex.grad ? Edited : UnEdited); neigh->setEditedState (pedited->retinex.neigh ? Edited : UnEdited); gam->setEditedState (pedited->retinex.gam ? Edited : UnEdited); slope->setEditedState (pedited->retinex.slope ? Edited : UnEdited); @@ -515,6 +541,8 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) offs->setValue (pp->retinex.offs); str->setValue (pp->retinex.str); scal->setValue (pp->retinex.scal); + iter->setValue (pp->retinex.iter); + grad->setValue (pp->retinex.grad); vart->setValue (pp->retinex.vart); limd->setValue (pp->retinex.limd); gam->setValue (pp->retinex.gam); @@ -522,10 +550,17 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) highl->setValue (pp->retinex.highl); baselog->setValue (pp->retinex.baselog); // grbl->setValue (pp->retinex.grbl); + if(pp->retinex.iter == 1) { + grad->set_sensitive(false); + scal->set_sensitive(false); + } + else { + grad->set_sensitive(true); + scal->set_sensitive(true); + } setEnabled (pp->retinex.enabled); - medianmapConn.block (true); medianmap->set_active (pp->retinex.medianmap); medianmapConn.block (false); lastmedianmap = pp->retinex.medianmap; @@ -590,6 +625,8 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pp->retinex.str = str->getValue (); pp->retinex.scal = (int)scal->getValue (); + pp->retinex.iter = (int) iter->getValue (); + pp->retinex.grad = (int) grad->getValue (); pp->retinex.gam = gam->getValue (); pp->retinex.slope = slope->getValue (); pp->retinex.neigh = neigh->getValue (); @@ -615,6 +652,8 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) //%%%%%%%%%%%%%%%%%%%%%% pedited->retinex.str = str->getEditedState (); pedited->retinex.scal = scal->getEditedState (); + pedited->retinex.iter = iter->getEditedState (); + pedited->retinex.grad = grad->getEditedState (); pedited->retinex.gam = gam->getEditedState (); pedited->retinex.slope = slope->getEditedState (); pedited->retinex.neigh = neigh->getEditedState (); @@ -770,6 +809,8 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi offs->setDefault (defParams->retinex.offs); str->setDefault (defParams->retinex.str); scal->setDefault (defParams->retinex.scal); + iter->setDefault (defParams->retinex.iter); + grad->setDefault (defParams->retinex.grad); vart->setDefault (defParams->retinex.vart); limd->setDefault (defParams->retinex.limd); highl->setDefault (defParams->retinex.highl); @@ -784,6 +825,8 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi offs->setDefaultEditedState (pedited->retinex.offs ? Edited : UnEdited); str->setDefaultEditedState (pedited->retinex.str ? Edited : UnEdited); scal->setDefaultEditedState (pedited->retinex.scal ? Edited : UnEdited); + iter->setDefaultEditedState (pedited->retinex.iter ? Edited : UnEdited); + grad->setDefaultEditedState (pedited->retinex.grad ? Edited : UnEdited); vart->setDefaultEditedState (pedited->retinex.vart ? Edited : UnEdited); limd->setDefaultEditedState (pedited->retinex.limd ? Edited : UnEdited); highl->setDefaultEditedState (pedited->retinex.highl ? Edited : UnEdited); @@ -803,6 +846,8 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi // grbl->setDefaultEditedState (Irrelevant); str->setDefaultEditedState (Irrelevant); scal->setDefaultEditedState (Irrelevant); + iter->setDefaultEditedState (Irrelevant); + grad->setDefaultEditedState (Irrelevant); gam->setDefaultEditedState (Irrelevant); slope->setDefaultEditedState (Irrelevant); } @@ -827,6 +872,15 @@ void Retinex::adjusterChanged (Adjuster* a, double newval) if (!listener || !getEnabled()) { return; } + if(iter->getTextValue() > "1") { + scal->set_sensitive(true); + grad->set_sensitive(true); + } + else { + scal->set_sensitive(false); + grad->set_sensitive(false); + } + if (a == neigh) { listener->panelChanged (EvLneigh, neigh->getTextValue()); @@ -834,6 +888,10 @@ void Retinex::adjusterChanged (Adjuster* a, double newval) listener->panelChanged (EvLstr, str->getTextValue()); } else if (a == scal) { listener->panelChanged (EvLscal, scal->getTextValue()); + } else if (a == iter) { + listener->panelChanged (EvLiter, iter->getTextValue()); + } else if (a == grad) { + listener->panelChanged (EvLgrad, grad->getTextValue()); } else if (a == gain) { listener->panelChanged (EvLgain, gain->getTextValue()); } else if (a == offs) { @@ -902,6 +960,8 @@ void Retinex::trimValues (rtengine::procparams::ProcParams* pp) { str->trimValue(pp->retinex.str); scal->trimValue(pp->retinex.scal); + iter->trimValue(pp->retinex.iter); + grad->trimValue(pp->retinex.grad); neigh->trimValue(pp->retinex.neigh); gain->trimValue(pp->retinex.gain); offs->trimValue(pp->retinex.offs); @@ -975,6 +1035,8 @@ void Retinex::setBatchMode (bool batchMode) offs->showEditedCB (); str->showEditedCB (); scal->showEditedCB (); + iter->showEditedCB (); + grad->showEditedCB (); gam->showEditedCB (); slope->showEditedCB (); vart->showEditedCB (); diff --git a/rtgui/retinex.h b/rtgui/retinex.h index 59001ce18..499b0ef0f 100644 --- a/rtgui/retinex.h +++ b/rtgui/retinex.h @@ -24,6 +24,8 @@ protected: CurveEditorGroup* curveEditorGH; Adjuster* str; Adjuster* scal; + Adjuster* grad; + Adjuster* iter; Adjuster* neigh; Adjuster* gain; Adjuster* offs; From 04478c3b946fc3e836d62330bda0d917084f440f Mon Sep 17 00:00:00 2001 From: Desmis Date: Mon, 9 Nov 2015 07:57:22 +0100 Subject: [PATCH 2/9] Fixed segfault bug and add strength gradient --- rtdata/languages/default | 3 +++ rtengine/ipretinex.cc | 31 ++++++++++++++++++++++++++++--- rtengine/procevents.h | 1 + rtengine/procparams.cc | 16 +++++++++++++++- rtengine/procparams.h | 1 + rtengine/refreshmap.cc | 3 ++- rtgui/paramsedited.cc | 6 ++++++ rtgui/paramsedited.h | 1 + rtgui/retinex.cc | 27 +++++++++++++++++++++++++++ rtgui/retinex.h | 1 + 10 files changed, 85 insertions(+), 5 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index aeb5664e8..ca1d0ac76 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -658,6 +658,7 @@ HISTORY_MSG_425;Retinex - Log base HISTORY_MSG_426;Retinex - Hue equalizer HISTORY_MSG_427;Retinex - Iterations HISTORY_MSG_428;Retinex - T. Gradient +HISTORY_MSG_429;Retinex - S. Gradient HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOTS;Snapshots @@ -1660,6 +1661,8 @@ TP_RETINEX_ITER;Iterations (Tone-mapping) TP_RETINEX_ITER_TOOLTIP;Simulate a tone-mapping operator\nHigh values increase the processing time TP_RETINEX_GRAD;Transmission gradient TP_RETINEX_GRAD_TOOLTIP;If slider at 0, all iterations are identical\nIf > 0 Variance and Threshold are reduce when iteration increases and conversely +TP_RETINEX_GRADS;Strength gradient +TP_RETINEX_GRAD_TOOLTIP;If slider at 0, all iterations are identical\nIf > 0 Strength is reduce when iteration increases and conversely TP_RETINEX_LABEL;Retinex TP_RETINEX_LABSPACE;L*a*b* TP_RETINEX_LOW;Low diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 1f6602b62..b07af2e14 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -223,6 +223,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e int nei = (int) 2.8f * deh.neigh; //def = 220 float vart = (float)deh.vart / 100.f;//variance float gradvart = (float)deh.grad; + float gradstr = (float)deh.grads; float strength = (float) deh.str / 100.f; // Blend with original L channel data float limD = (float) deh.limd; limD = pow(limD, 1.7f);//about 2500 enough @@ -274,6 +275,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e moderetinex = 3; } for(int it=1; itretinex.grad) { - keyFile.set_integer ("Retinex", "Grad", retinex.iter); + keyFile.set_integer ("Retinex", "Grad", retinex.grad); + } + + if (!pedited || pedited->retinex.grads) { + keyFile.set_integer ("Retinex", "Grads", retinex.grads); } if (!pedited || pedited->retinex.gam) { @@ -3877,6 +3882,14 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Retinex", "Grads")) { + retinex.grads = keyFile.get_integer ("Retinex", "Grads"); + + if (pedited) { + pedited->retinex.grads = true; + } + } + if (keyFile.has_key ("Retinex", "Gam")) { retinex.gam = keyFile.get_double ("Retinex", "Gam"); @@ -7350,6 +7363,7 @@ bool ProcParams::operator== (const ProcParams& other) && retinex.scal == other.retinex.scal && retinex.iter == other.retinex.iter && retinex.grad == other.retinex.grad + && retinex.grads == other.retinex.grads && retinex.gam == other.retinex.gam && retinex.slope == other.retinex.slope && retinex.neigh == other.retinex.neigh diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 1226d1584..2b8b7ada6 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -277,6 +277,7 @@ public: int scal; int iter; int grad; + int grads; double gam; double slope; int neigh; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 88338f06c..30373a35e 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -455,7 +455,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { // DEMOSAIC, // EvLgrbl DEMOSAIC, // EvRetinexlhcurve RETINEX, // EvLiter - RETINEX // EvLgrad + RETINEX, // EvLgrad + RETINEX // EvLgrads }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 600a68af4..2efed572e 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -60,6 +60,7 @@ void ParamsEdited::set (bool v) retinex.scal = v; retinex.iter = v; retinex.grad = v; + retinex.grads = v; retinex.gam = v; retinex.slope = v; retinex.neigh = v; @@ -539,6 +540,7 @@ void ParamsEdited::initFrom (const std::vector retinex.scal = retinex.scal && p.retinex.scal == other.retinex.scal; retinex.iter = retinex.iter && p.retinex.iter == other.retinex.iter; retinex.grad = retinex.grad && p.retinex.grad == other.retinex.grad; + retinex.grads = retinex.grads && p.retinex.grads == other.retinex.grads; retinex.gam = retinex.gam && p.retinex.gam == other.retinex.gam; retinex.slope = retinex.slope && p.retinex.slope == other.retinex.slope; retinex.neigh = retinex.neigh && p.retinex.neigh == other.retinex.neigh; @@ -1098,6 +1100,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.retinex.grad = mods.retinex.grad; } + if (retinex.grads) { + toEdit.retinex.grads = mods.retinex.grads; + } + // if (retinex.scal) { // toEdit.retinex.scal = dontforceSet && options.baBehav[ADDSET_RETI_SCAL] ? toEdit.retinex.scal + mods.retinex.scal : mods.retinex.scal; // } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index ed1f07aec..f174c8d52 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -63,6 +63,7 @@ public: bool scal; bool iter; bool grad; + bool grads; bool gam; bool slope; bool neigh; diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index 0578c3e57..0bd5c28ae 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -147,6 +147,7 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), scal = Gtk::manage (new Adjuster (M("TP_RETINEX_SCALES"), -1, 5., 1., 3.)); iter = Gtk::manage (new Adjuster (M("TP_RETINEX_ITER"), 1, 5., 1., 1.)); grad = Gtk::manage (new Adjuster (M("TP_RETINEX_GRAD"), -2., 2., 1., 1.)); + grads = Gtk::manage (new Adjuster (M("TP_RETINEX_GRADS"), -2., 2., 1., 1.)); gain = Gtk::manage (new Adjuster (M("TP_RETINEX_GAIN"), 20, 200, 1, 50)); offs = Gtk::manage (new Adjuster (M("TP_RETINEX_OFFSET"), -10000, 10000, 1, 0)); // vart = Gtk::manage (new Adjuster (M("TP_RETINEX_VARIANCE"), 50, 500, 1, 125)); @@ -157,6 +158,7 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), scal->set_tooltip_markup (M("TP_RETINEX_SCALES_TOOLTIP")); iter->set_tooltip_markup (M("TP_RETINEX_ITER_TOOLTIP")); grad->set_tooltip_markup (M("TP_RETINEX_GRAD_TOOLTIP")); + grads->set_tooltip_markup (M("TP_RETINEX_GRADS_TOOLTIP")); // vart->set_tooltip_markup (M("TP_RETINEX_VARIANCE_TOOLTIP")); limd->set_tooltip_markup (M("TP_RETINEX_THRESHOLD_TOOLTIP")); baselog->set_tooltip_markup (M("TP_RETINEX_BASELOG_TOOLTIP")); @@ -224,6 +226,9 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), settingsVBox->pack_start (*grad); grad->show (); + settingsVBox->pack_start (*grads); + grads->show (); + settingsVBox->pack_start (*gain); gain->show (); @@ -289,6 +294,12 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), grad->delay = 200; } + grads->setAdjusterListener (this); + + if (grads->delay < 200) { + grads->delay = 200; + } + gam->setAdjusterListener (this); if (gam->delay < 500) { @@ -378,6 +389,7 @@ void Retinex::neutral_pressed () scal->resetValue(false); iter->resetValue(false); grad->resetValue(false); + grads->resetValue(false); vart->resetValue(false); limd->resetValue(false); highl->resetValue(false); @@ -503,6 +515,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) scal->setEditedState (pedited->retinex.scal ? Edited : UnEdited); iter->setEditedState (pedited->retinex.iter ? Edited : UnEdited); grad->setEditedState (pedited->retinex.grad ? Edited : UnEdited); + grads->setEditedState (pedited->retinex.grads ? Edited : UnEdited); neigh->setEditedState (pedited->retinex.neigh ? Edited : UnEdited); gam->setEditedState (pedited->retinex.gam ? Edited : UnEdited); slope->setEditedState (pedited->retinex.slope ? Edited : UnEdited); @@ -543,6 +556,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) scal->setValue (pp->retinex.scal); iter->setValue (pp->retinex.iter); grad->setValue (pp->retinex.grad); + grads->setValue (pp->retinex.grads); vart->setValue (pp->retinex.vart); limd->setValue (pp->retinex.limd); gam->setValue (pp->retinex.gam); @@ -553,10 +567,12 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) if(pp->retinex.iter == 1) { grad->set_sensitive(false); scal->set_sensitive(false); + grads->set_sensitive(false); } else { grad->set_sensitive(true); scal->set_sensitive(true); + grads->set_sensitive(true); } setEnabled (pp->retinex.enabled); @@ -627,6 +643,7 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pp->retinex.scal = (int)scal->getValue (); pp->retinex.iter = (int) iter->getValue (); pp->retinex.grad = (int) grad->getValue (); + pp->retinex.grads = (int) grads->getValue (); pp->retinex.gam = gam->getValue (); pp->retinex.slope = slope->getValue (); pp->retinex.neigh = neigh->getValue (); @@ -654,6 +671,7 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pedited->retinex.scal = scal->getEditedState (); pedited->retinex.iter = iter->getEditedState (); pedited->retinex.grad = grad->getEditedState (); + pedited->retinex.grads = grads->getEditedState (); pedited->retinex.gam = gam->getEditedState (); pedited->retinex.slope = slope->getEditedState (); pedited->retinex.neigh = neigh->getEditedState (); @@ -811,6 +829,7 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi scal->setDefault (defParams->retinex.scal); iter->setDefault (defParams->retinex.iter); grad->setDefault (defParams->retinex.grad); + grads->setDefault (defParams->retinex.grads); vart->setDefault (defParams->retinex.vart); limd->setDefault (defParams->retinex.limd); highl->setDefault (defParams->retinex.highl); @@ -827,6 +846,7 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi scal->setDefaultEditedState (pedited->retinex.scal ? Edited : UnEdited); iter->setDefaultEditedState (pedited->retinex.iter ? Edited : UnEdited); grad->setDefaultEditedState (pedited->retinex.grad ? Edited : UnEdited); + grads->setDefaultEditedState (pedited->retinex.grads ? Edited : UnEdited); vart->setDefaultEditedState (pedited->retinex.vart ? Edited : UnEdited); limd->setDefaultEditedState (pedited->retinex.limd ? Edited : UnEdited); highl->setDefaultEditedState (pedited->retinex.highl ? Edited : UnEdited); @@ -848,6 +868,7 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi scal->setDefaultEditedState (Irrelevant); iter->setDefaultEditedState (Irrelevant); grad->setDefaultEditedState (Irrelevant); + grads->setDefaultEditedState (Irrelevant); gam->setDefaultEditedState (Irrelevant); slope->setDefaultEditedState (Irrelevant); } @@ -875,10 +896,12 @@ void Retinex::adjusterChanged (Adjuster* a, double newval) if(iter->getTextValue() > "1") { scal->set_sensitive(true); grad->set_sensitive(true); + grads->set_sensitive(true); } else { scal->set_sensitive(false); grad->set_sensitive(false); + grads->set_sensitive(false); } @@ -892,6 +915,8 @@ void Retinex::adjusterChanged (Adjuster* a, double newval) listener->panelChanged (EvLiter, iter->getTextValue()); } else if (a == grad) { listener->panelChanged (EvLgrad, grad->getTextValue()); + } else if (a == grads) { + listener->panelChanged (EvLgrads, grads->getTextValue()); } else if (a == gain) { listener->panelChanged (EvLgain, gain->getTextValue()); } else if (a == offs) { @@ -962,6 +987,7 @@ void Retinex::trimValues (rtengine::procparams::ProcParams* pp) scal->trimValue(pp->retinex.scal); iter->trimValue(pp->retinex.iter); grad->trimValue(pp->retinex.grad); + grads->trimValue(pp->retinex.grads); neigh->trimValue(pp->retinex.neigh); gain->trimValue(pp->retinex.gain); offs->trimValue(pp->retinex.offs); @@ -1037,6 +1063,7 @@ void Retinex::setBatchMode (bool batchMode) scal->showEditedCB (); iter->showEditedCB (); grad->showEditedCB (); + grads->showEditedCB (); gam->showEditedCB (); slope->showEditedCB (); vart->showEditedCB (); diff --git a/rtgui/retinex.h b/rtgui/retinex.h index 499b0ef0f..e014bed5d 100644 --- a/rtgui/retinex.h +++ b/rtgui/retinex.h @@ -25,6 +25,7 @@ protected: Adjuster* str; Adjuster* scal; Adjuster* grad; + Adjuster* grads; Adjuster* iter; Adjuster* neigh; Adjuster* gain; From 8cfab83f51dd5b35a60bd7039187b951bcc0a1a5 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 10 Nov 2015 08:05:44 +0100 Subject: [PATCH 3/9] Changes some labels - small change to gradient --- rtdata/languages/default | 12 ++++++------ rtengine/ipretinex.cc | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index ca1d0ac76..43eda0146 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -637,9 +637,9 @@ HISTORY_MSG_404;W - ES - Base amplification HISTORY_MSG_405;W - Denoise - Level 4 HISTORY_MSG_406;W - ES - Neighboring pixels HISTORY_MSG_407;Retinex - Method -HISTORY_MSG_408;Retinex - Neighboring -HISTORY_MSG_409;Retinex - Gain -HISTORY_MSG_410;Retinex - Offset +HISTORY_MSG_408;Retinex - Radius +HISTORY_MSG_409;Retinex - Contrast +HISTORY_MSG_410;Retinex - Brightness HISTORY_MSG_411;Retinex - Strength HISTORY_MSG_412;Retinex - G. Gradient HISTORY_MSG_413;Retinex - Variance @@ -1642,7 +1642,7 @@ TP_RETINEX_CURVEEDITOR_CD_TOOLTIP;Luminance according to luminance L=f(L)\nCorre TP_RETINEX_CURVEEDITOR_LH;Strength=f(H) TP_RETINEX_CURVEEDITOR_LH_TOOLTIP;Strength according to hue Strength=f(H)\nThis curve also acts on chroma when using the "Highlight" retinex method. TP_RETINEX_FREEGAMMA;Free gamma -TP_RETINEX_GAIN;Gain +TP_RETINEX_GAIN;Contrast TP_RETINEX_GAIN_TOOLTIP;Acts on the restored image.\n\nThis is very different from the others settings. Used for black or white pixels, and to help balance the histogram. TP_RETINEX_GAMMA;Gamma TP_RETINEX_GAMMA_FREE;Free @@ -1671,10 +1671,10 @@ TP_RETINEX_METHOD;Method TP_RETINEX_METHOD_TOOLTIP;Low = Reinforce low light,\nUniform = Equalize action,\nHigh = Reinforce high light,\nHighlights = Remove magenta in highlights. TP_RETINEX_MLABEL;Restored haze-free Min=%1 Max=%2 TP_RETINEX_MLABEL_TOOLTIP;Should be near min=0 max=32768\nRestored image with no mixture. -TP_RETINEX_NEIGHBOR;Neighboring pixels +TP_RETINEX_NEIGHBOR;Radius TP_RETINEX_NEUTRAL;Reset TP_RETINEX_NEUTRAL_TIP;Reset all sliders and curves to their default values. -TP_RETINEX_OFFSET;Offset +TP_RETINEX_OFFSET;Brightness TP_RETINEX_SETTINGS;Settings TP_RETINEX_SCALES;Gaussian gradient TP_RETINEX_SCALES_TOOLTIP;If slider at 0, all iterations are identical\nIf > 0 Scale and Neighboring pixels are reduce when iteration increases and conversely diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index b07af2e14..a93afbabc 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -288,19 +288,19 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } else if(gradient==2) { grad=0.5f*it+0.5f; - sc=-it+6.f; + sc=-0.75f*it+5.75f; } else if(gradient==3) { grad=0.666f*it+0.333f; - sc=-it+6.f; + sc=-0.75f*it+5.75f; } else if(gradient==4) { grad=0.8f*it+0.2f; - sc=-it+6.f; + sc=-0.75f*it+5.75f; } else if(gradient==5) { grad=0.9f*it+0.1f; - sc=-it+6.f; + sc=-0.75f*it+5.75f; } else if(gradient==-1) { grad=-0.125f*it+1.125f; From 4b6fa0c5f830e45a16467888091c3cb31e8fa397 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 10 Nov 2015 08:30:29 +0100 Subject: [PATCH 4/9] Forgot Tooltip label --- rtdata/languages/default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 43eda0146..e7836298a 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1662,7 +1662,7 @@ TP_RETINEX_ITER_TOOLTIP;Simulate a tone-mapping operator\nHigh values increase t TP_RETINEX_GRAD;Transmission gradient TP_RETINEX_GRAD_TOOLTIP;If slider at 0, all iterations are identical\nIf > 0 Variance and Threshold are reduce when iteration increases and conversely TP_RETINEX_GRADS;Strength gradient -TP_RETINEX_GRAD_TOOLTIP;If slider at 0, all iterations are identical\nIf > 0 Strength is reduce when iteration increases and conversely +TP_RETINEX_GRADS_TOOLTIP;If slider at 0, all iterations are identical\nIf > 0 Strength is reduce when iteration increases and conversely TP_RETINEX_LABEL;Retinex TP_RETINEX_LABSPACE;L*a*b* TP_RETINEX_LOW;Low From a1fd3d72b205e3fb362ab29afc1e8807567562c0 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 10 Nov 2015 11:34:17 +0100 Subject: [PATCH 5/9] Improvement to Gaussian gradient --- rtengine/ipretinex.cc | 33 ++++++++++++++++++++++++++++++--- rtgui/retinex.cc | 2 +- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index a93afbabc..0f67c1a84 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -275,6 +275,11 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e moderetinex = 3; } for(int it=1; it= 0; scale-- ) { if(scale == scal - 1) { gaussianBlur (src, out, W_L, H_L, RetinexScales[scale], buffer); - } else { // reuse result of last iteration + } else { + printf("reti=%f\n",RetinexScales[scale]);// reuse result of last iteration gaussianBlur (out, out, W_L, H_L, sqrtf(SQR(RetinexScales[scale]) - SQR(RetinexScales[scale + 1])), buffer); } diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index 0bd5c28ae..099ee7310 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -144,7 +144,7 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), transLabels->set_tooltip_markup (M("TP_RETINEX_TLABEL_TOOLTIP")); transLabels2 = Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER)); - scal = Gtk::manage (new Adjuster (M("TP_RETINEX_SCALES"), -1, 5., 1., 3.)); + scal = Gtk::manage (new Adjuster (M("TP_RETINEX_SCALES"), -1, 6., 1., 3.)); iter = Gtk::manage (new Adjuster (M("TP_RETINEX_ITER"), 1, 5., 1., 1.)); grad = Gtk::manage (new Adjuster (M("TP_RETINEX_GRAD"), -2., 2., 1., 1.)); grads = Gtk::manage (new Adjuster (M("TP_RETINEX_GRADS"), -2., 2., 1., 1.)); From 44490e81ae9bb9cde02cfcc9d61de2d4d9db39ed Mon Sep 17 00:00:00 2001 From: Desmis Date: Thu, 12 Nov 2015 08:58:07 +0100 Subject: [PATCH 6/9] Add mask method --- rtdata/languages/default | 17 +++ rtengine/curves.cc | 39 ++++++ rtengine/curves.h | 1 + rtengine/imagesource.h | 6 +- rtengine/improccoordinator.cc | 6 +- rtengine/ipretinex.cc | 95 ++++++++++++-- rtengine/procevents.h | 7 ++ rtengine/procparams.cc | 104 ++++++++++++++++ rtengine/procparams.h | 8 ++ rtengine/rawimagesource.cc | 7 +- rtengine/rawimagesource.h | 6 +- rtengine/refreshmap.cc | 15 ++- rtengine/shmap.cc | 162 ++++++++++++++++++++++++ rtengine/shmap.h | 2 + rtengine/simpleprocess.cc | 6 +- rtgui/paramsedited.cc | 46 +++++++ rtgui/paramsedited.h | 8 ++ rtgui/retinex.cc | 228 ++++++++++++++++++++++++++++++++++ rtgui/retinex.h | 15 ++- 19 files changed, 750 insertions(+), 28 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index e7836298a..97b327ef6 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -659,6 +659,13 @@ HISTORY_MSG_426;Retinex - Hue equalizer HISTORY_MSG_427;Retinex - Iterations HISTORY_MSG_428;Retinex - T. Gradient HISTORY_MSG_429;Retinex - S. Gradient +HISTORY_MSG_430;Retinex - Mask highlights +HISTORY_MSG_431;Retinex - Mask TW highlights +HISTORY_MSG_432;Retinex - Mask shadows +HISTORY_MSG_433;Retinex - Mask TW shadows +HISTORY_MSG_434;Retinex - Mask radius +HISTORY_MSG_435;Retinex - Mask method +HISTORY_MSG_436;Retinex - Mask curve HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOTS;Snapshots @@ -1637,6 +1644,9 @@ TP_RESIZE_W;Width: TP_RETINEX_CONTEDIT_HSL;Histogram equalizer HSL TP_RETINEX_CONTEDIT_LAB;Histogram equalizer L*a*b* TP_RETINEX_CONTEDIT_LH;Hue equalizer +TP_RETINEX_CONTEDIT_MAP;Mask equalizer +TP_RETINEX_CURVEEDITOR_MAP;L=f(L) +TP_RETINEX_CURVEEDITOR_MAP_TOOLTIP;This Curve can be applied alone or with gaussian mask or wavelet mask\nBe aware to artifacts TP_RETINEX_CURVEEDITOR_CD;L=f(L) TP_RETINEX_CURVEEDITOR_CD_TOOLTIP;Luminance according to luminance L=f(L)\nCorrect raw data to reduce halos and artifacts. TP_RETINEX_CURVEEDITOR_LH;Strength=f(H) @@ -1666,6 +1676,13 @@ TP_RETINEX_GRADS_TOOLTIP;If slider at 0, all iterations are identical\nIf > 0 St TP_RETINEX_LABEL;Retinex TP_RETINEX_LABSPACE;L*a*b* TP_RETINEX_LOW;Low +TP_RETINEX_MAP;Mask method +TP_RETINEX_MAP_METHOD_TOOLTIP;Use the mask generate by Gaussian function above to reduce halos and artifacts\nCurve only: apply a diagonal contrast curve on mask, be aware to artifacts\nGaussian mask : generate and use a gaussian blur of the original mask (quick)\nSharp mask : generate and use a wavelet on the original mask (slow or very very slow) +TP_RETINEX_MAP_NONE;none +TP_RETINEX_MAP_CURV;Curve only +TP_RETINEX_MAP_GAUS;Gaussian mask +TP_RETINEX_MAP_MAPP;Sharp mask (wavelet partial) +TP_RETINEX_MAP_MAPT;Sharp mask (wavelet total) TP_RETINEX_MEDIAN;Transmission median filter TP_RETINEX_METHOD;Method TP_RETINEX_METHOD_TOOLTIP;Low = Reinforce low light,\nUniform = Equalize action,\nHigh = Reinforce high light,\nHighlights = Remove magenta in highlights. diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 4ad1d06bd..d0b4c026f 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -504,6 +504,45 @@ void CurveFactory::curveCL ( bool & clcutili, const std::vector& clcurve } } +void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, LUTu & histogram, LUTu & outBeforeCurveHistogram) +{ + bool needed = false; + DiagonalCurve* dCurve = NULL; + outBeforeCurveHistogram.clear(); + bool histNeeded = false; + + if (!mapcurvePoints.empty() && mapcurvePoints[0] != 0) { + dCurve = new DiagonalCurve (mapcurvePoints, CURVES_MIN_POLY_POINTS / skip); + + if (outBeforeCurveHistogram) { + histNeeded = true; + } + + if (dCurve && !dCurve->isIdentity()) { + needed = true; + mapcontlutili = true; + } + } + + if (histNeeded) { + for (int i = 0; i < 32768; i++) { + double hval = CLIPD((double)i / 32767.0); + int hi = (int)(255.0 * hval); + outBeforeCurveHistogram[hi] += histogram[i] ; + } + } + + fillCurveArray(dCurve, mapcurve, skip, needed); + + if (dCurve) { + delete dCurve; + dCurve = NULL; + } +} + + + + void CurveFactory::curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, LUTu & histogram, LUTu & outBeforeCurveHistogram) { bool needed = false; diff --git a/rtengine/curves.h b/rtengine/curves.h index f0643c7a9..e55d7bc2a 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -283,6 +283,7 @@ public: static void curveWavContL ( bool & wavcontlutili, const std::vector& wavclcurvePoints, LUTf & wavclCurve,/* LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,*/int skip); static void curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, LUTu & histogram, LUTu & outBeforeCurveHistogram); + static void mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, LUTu & histogram, LUTu & outBeforeCurveHistogram); static void curveToningCL ( bool & clctoningutili, const std::vector& clcurvePoints, LUTf & clToningCurve, int skip); static void curveToningLL ( bool & llctoningutili, const std::vector& llcurvePoints, LUTf & llToningCurve, int skip); diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index d9f088813..eaf9997fa 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -69,14 +69,14 @@ public: virtual int load (Glib::ustring fname, bool batch = false) = 0; virtual void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse) {}; virtual void demosaic (const RAWParams &raw) {}; - virtual void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; - virtual void retinexPrepareCurves (RetinexParams retinexParams, LUTf &cdcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) {}; + virtual void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; + virtual void retinexPrepareCurves (RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) {}; virtual void retinexPrepareBuffers (ColorManagementParams cmp, RetinexParams retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI) {}; virtual void flushRawData () {}; virtual void flushRGB () {}; virtual void HLRecovery_Global (ToneCurveParams hrp) {}; virtual void HLRecovery_inpaint (float** red, float** green, float** blue) {}; - virtual void MSR(LabImage* lab, int width, int height, int skip, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) {}; + virtual void MSR(LabImage* lab, LUTf & mapcurve, bool &mapcontlutili, int width, int height, int skip, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) {}; virtual bool IsrgbSourceModified() = 0; // tracks whether cached rgb output of demosaic has been modified diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 8389ec34e..479ec1282 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -244,12 +244,14 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) if ((todo & (M_RETINEX|M_INIT)) && params.retinex.enabled) { bool dehacontlutili = false; + bool mapcontlutili = false; bool useHsl = false; LUTf cdcurve (65536, 0); + LUTf mapcurve (65536, 0); - imgsrc->retinexPrepareCurves(params.retinex, cdcurve, dehatransmissionCurve, dehacontlutili, useHsl, lhist16RETI, histLRETI); + imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehacontlutili, mapcontlutili, useHsl, lhist16RETI, histLRETI); float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; - imgsrc->retinex( params.icm, params.retinex, params.toneCurve, cdcurve, dehatransmissionCurve, conversionBuffer, dehacontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI);//enabled Retinex + imgsrc->retinex( params.icm, params.retinex, params.toneCurve, mapcurve, dehatransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI);//enabled Retinex if(dehaListener) { dehaListener->minmaxChanged(maxCD, minCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 0f67c1a84..d444380ce 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -32,6 +32,7 @@ * College of Physics and Information Engineering, Fuzhou University, Fuzhou, China * inspired from 2003 Fabien Pelisson + * some ideas taken (use of mask) Russell Cottrell - The Retinex .8bf Plugin */ @@ -205,7 +206,7 @@ void mean_stddv( float **dst, float &mean, float &stddv, int W_L, int H_L, const stddv = (float)sqrt(stddv); } -void RawImageSource::MSR(float** luminance, float** originalLuminance, float **exLuminance, int width, int height, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) +void RawImageSource::MSR(float** luminance, float** originalLuminance, float **exLuminance, LUTf & mapcurve, bool &mapcontlutili, int width, int height, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) { if (deh.enabled) {//enabled float mean, stddv, maxtr, mintr; @@ -234,7 +235,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e bool higplus = false ; float elogt; float hl = deh.baselog; - + SHMap* shmap; if(hl >= 2.71828f) { elogt = 2.71828f + SQR(SQR(hl - 2.71828f)); } else { @@ -382,13 +383,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } } strengthx=ks*strength; - /* - float aahi = 49.f / 99.f; ////reduce sensibility 50% - float bbhi = 1.f - aahi; - float high; - high = bbhi + aahi * (float) deh.highl; - */ - printf("high=%f moderetinex=%d\n",high,moderetinex); + retinex_scales( RetinexScales, scal, moderetinex, nei/grad, high ); int H_L = height; @@ -401,6 +396,17 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e src[i] = &srcBuffer[i * W_L]; } + int h_th, s_th; + + int shHighlights = deh.highlights; + int shShadows = deh.shadows; + int mapmet=0; + if(deh.mapMethod=="map") mapmet=2; + if(deh.mapMethod=="mapT") mapmet=3; + if(deh.mapMethod=="curv") mapmet=1; + if(deh.mapMethod=="gaus") mapmet=4; + + #ifdef _OPENMP #pragma omp parallel for #endif @@ -425,6 +431,10 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e pond /= log(elogt); } + if(mapmet > 1) shmap = new SHMap (W_L, H_L, true); + + + float *buffer = new float[W_L * H_L];; #ifdef _OPENMP #pragma omp parallel @@ -434,9 +444,26 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e if(scale == scal - 1) { gaussianBlur (src, out, W_L, H_L, RetinexScales[scale], buffer); } else { - printf("reti=%f\n",RetinexScales[scale]);// reuse result of last iteration + // reuse result of last iteration gaussianBlur (out, out, W_L, H_L, sqrtf(SQR(RetinexScales[scale]) - SQR(RetinexScales[scale + 1])), buffer); } + //printf("scal=%d RetinexScales=%f\n",scale, RetinexScales[scale]); + printf(".."); + + + double shradius = deh.radius; + if(mapmet==4) shradius /= 10.; + + // if(shHighlights > 0 || shShadows > 0) { + if(mapmet==3) if(it==1) shmap->updateL (out, shradius, true, 1);//wav Total + if(mapmet==2 && scale >2) if(it==1) shmap->updateL (out, shradius, true, 1);//wav partial + if(mapmet==4) if(it==1) shmap->updateL (out, shradius, false, 1);//gauss + // } + if (shmap) { + h_th = shmap->max_f - deh.htonalwidth * (shmap->max_f - shmap->avg) / 100; + s_th = deh.stonalwidth * (shmap->avg - shmap->min_f) / 100; + } + #ifdef __SSE2__ vfloat pondv = F2V(pond); @@ -444,6 +471,47 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e vfloat limMaxv = F2V(limdx); #endif + + if(mapmet > 0) { +#ifdef _OPENMP + #pragma omp for +#endif + for (int i = 0; i < H_L; i++) { + if(mapcontlutili) { + int j = 0; + for (; j < W_L; j++) { + if(it==1) out[i][j] = mapcurve[2.f * out[i][j]] / 2.f; + } + } + } + + } + + // if(shHighlights > 0 || shShadows > 0) { + if((mapmet == 2 && scale >2) || mapmet==3 || mapmet==4) { + + +#ifdef _OPENMP + #pragma omp for +#endif + for (int i = 0; i < H_L; i++) { + int j = 0; + for (; j < W_L; j++) { + double mapval = 1.0 + shmap->map[i][j]; + double factor = 1.0; + + if (mapval > h_th) { + factor = (h_th + (100.0 - shHighlights) * (mapval - h_th) / 100.0) / mapval; + } else if (mapval < s_th) { + factor = (s_th - (100.0 - shShadows) * (s_th - mapval) / 100.0) / mapval; + } + out[i][j] *= factor; + + } + } + } + // } + #ifdef _OPENMP #pragma omp for #endif @@ -477,6 +545,13 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } } } + if(mapmet > 1) { + if(shmap) { + delete shmap; + } + } + shmap = NULL; + delete [] buffer; delete [] outBuffer; delete [] srcBuffer; diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 6f1d7144a..f23d68f2e 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -457,6 +457,13 @@ enum ProcEvent { EvLiter = 426, EvLgrad = 427, EvLgrads = 428, + EvLhighlights = 429, + EvLh_tonalwidth = 430, + EvLshadows = 431, + EvLs_tonalwidth = 432, + EvLradius = 433, + EvmapMethod = 434, + EvRetinexmapcurve = 435, NUMOFEVENTS }; } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 6c737f8a2..075067585 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -153,9 +153,16 @@ void RetinexParams::setDefaults() vart = 200; limd = 8; highl = 4; + highlights = 0; + htonalwidth = 80; + shadows = 0; + stonalwidth = 80; + radius = 40; + baselog = 2.71828; // grbl = 50; retinexMethod = "high"; + mapMethod = "none"; retinexcolorspace = "Lab"; gammaretinex = "none"; medianmap = false; @@ -165,6 +172,8 @@ void RetinexParams::setDefaults() cdHcurve.push_back(DCT_Linear); lhcurve.clear(); lhcurve.push_back(DCT_Linear); + mapcurve.clear(); + mapcurve.push_back(DCT_Linear); getDefaulttransmissionCurve(transmissionCurve); } @@ -1513,6 +1522,10 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_string ("Retinex", "RetinexMethod", retinex.retinexMethod); } + if (!pedited || pedited->retinex.mapMethod) { + keyFile.set_string ("Retinex", "mapMethod", retinex.mapMethod); + } + if (!pedited || pedited->retinex.retinexcolorspace) { keyFile.set_string ("Retinex", "Retinexcolorspace", retinex.retinexcolorspace); } @@ -1526,6 +1539,11 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_double_list("Retinex", "CDCurve", cdcurve); } + if (!pedited || pedited->retinex.mapcurve) { + Glib::ArrayHandle mapcurve = retinex.mapcurve; + keyFile.set_double_list("Retinex", "MAPCurve", mapcurve); + } + if (!pedited || pedited->retinex.cdHcurve) { Glib::ArrayHandle cdHcurve = retinex.cdHcurve; keyFile.set_double_list("Retinex", "CDHCurve", cdHcurve); @@ -1536,6 +1554,26 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_double_list("Retinex", "LHCurve", lhcurve); } + if (!pedited || pedited->retinex.highlights) { + keyFile.set_integer ("Retinex", "Highlights", retinex.highlights); + } + + if (!pedited || pedited->retinex.htonalwidth) { + keyFile.set_integer ("Retinex", "HighlightTonalWidth", retinex.htonalwidth); + } + + if (!pedited || pedited->retinex.shadows) { + keyFile.set_integer ("Retinex", "Shadows", retinex.shadows); + } + + if (!pedited || pedited->retinex.stonalwidth) { + keyFile.set_integer ("Retinex", "ShadowTonalWidth", retinex.stonalwidth); + } + + if (!pedited || pedited->retinex.radius) { + keyFile.set_integer ("Retinex", "Radius", retinex.radius); + } + if (!pedited || pedited->retinex.transmissionCurve) { Glib::ArrayHandle transmissionCurve = retinex.transmissionCurve; keyFile.set_double_list("Retinex", "TransmissionCurve", transmissionCurve); @@ -3818,6 +3856,14 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Retinex", "mapMethod")) { + retinex.mapMethod = keyFile.get_string ("Retinex", "mapMethod"); + + if (pedited) { + pedited->retinex.mapMethod = true; + } + } + if (keyFile.has_key ("Retinex", "Retinexcolorspace")) { retinex.retinexcolorspace = keyFile.get_string ("Retinex", "Retinexcolorspace"); @@ -3970,6 +4016,14 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Retinex", "MAPCurve")) { + retinex.mapcurve = keyFile.get_double_list ("Retinex", "MAPCurve"); + + if (pedited) { + pedited->retinex.mapcurve = true; + } + } + if (keyFile.has_key ("Retinex", "CDHCurve")) { retinex.cdHcurve = keyFile.get_double_list ("Retinex", "CDHCurve"); @@ -3986,6 +4040,48 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Retinex", "Highlights")) { + retinex.highlights = keyFile.get_integer ("Retinex", "Highlights"); + + if (pedited) { + pedited->retinex.highlights = true; + } + } + + if (keyFile.has_key ("Retinex", "HighlightTonalWidth")) { + retinex.htonalwidth = keyFile.get_integer ("Retinex", "HighlightTonalWidth"); + + if (pedited) { + pedited->retinex.htonalwidth = true; + } + } + + if (keyFile.has_key ("Retinex", "Shadows")) { + retinex.shadows = keyFile.get_integer ("Retinex", "Shadows"); + + if (pedited) { + pedited->retinex.shadows = true; + } + } + + if (keyFile.has_key ("Retinex", "ShadowTonalWidth")) { + retinex.stonalwidth = keyFile.get_integer ("Retinex", "ShadowTonalWidth"); + + if (pedited) { + pedited->retinex.stonalwidth = true; + } + } + + + if (keyFile.has_key ("Retinex", "Radius")) { + sh.radius = keyFile.get_integer ("Retinex", "Radius"); + + if (pedited) { + pedited->retinex.radius = true; + } + } + + if (keyFile.has_key ("Retinex", "TransmissionCurve")) { retinex.transmissionCurve = keyFile.get_double_list ("Retinex", "TransmissionCurve"); @@ -7356,6 +7452,7 @@ bool ProcParams::operator== (const ProcParams& other) && toneCurve.hrenabled == other.toneCurve.hrenabled && toneCurve.method == other.toneCurve.method && retinex.cdcurve == other.retinex.cdcurve + && retinex.mapcurve == other.retinex.mapcurve && retinex.cdHcurve == other.retinex.cdHcurve && retinex.lhcurve == other.retinex.lhcurve && retinex.transmissionCurve == other.retinex.transmissionCurve @@ -7370,10 +7467,17 @@ bool ProcParams::operator== (const ProcParams& other) && retinex.gain == other.retinex.gain && retinex.limd == other.retinex.limd && retinex.highl == other.retinex.highl + && retinex.highlights == other.retinex.highlights + && retinex.htonalwidth == other.retinex.htonalwidth + && retinex.shadows == other.retinex.shadows + && retinex.stonalwidth == other.retinex.stonalwidth + && retinex.radius == other.retinex.radius + && retinex.baselog == other.retinex.baselog // && retinex.grbl == other.retinex.grbl && retinex.offs == other.retinex.offs && retinex.retinexMethod == other.retinex.retinexMethod + && retinex.mapMethod == other.retinex.mapMethod && retinex.retinexcolorspace == other.retinex.retinexcolorspace && retinex.gammaretinex == other.retinex.gammaretinex && retinex.vart == other.retinex.vart diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 2b8b7ada6..e2d2539ea 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -273,6 +273,7 @@ public: std::vector cdHcurve; std::vector lhcurve; std::vector transmissionCurve; + std::vector mapcurve; int str; int scal; int iter; @@ -283,9 +284,16 @@ public: int neigh; int gain; int offs; + int highlights; + int htonalwidth; + int shadows; + int stonalwidth; + int radius; + Glib::ustring retinexMethod; Glib::ustring retinexcolorspace; Glib::ustring gammaretinex; + Glib::ustring mapMethod; int vart; int limd; int highl; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 32d91be64..8a4fc3559 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2107,7 +2107,7 @@ void RawImageSource::retinexPrepareBuffers(ColorManagementParams cmp, RetinexPar } -void RawImageSource::retinexPrepareCurves(RetinexParams retinexParams, LUTf &cdcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) +void RawImageSource::retinexPrepareCurves(RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) { useHsl = (retinexParams.retinexcolorspace == "HSLLOG" || retinexParams.retinexcolorspace == "HSLLIN"); @@ -2116,12 +2116,13 @@ void RawImageSource::retinexPrepareCurves(RetinexParams retinexParams, LUTf &cdc } else { CurveFactory::curveDehaContL (retinexcontlutili, retinexParams.cdcurve, cdcurve, 1, lhist16RETI, histLRETI); } + CurveFactory::mapcurve (mapcontlutili, retinexParams.mapcurve, mapcurve, 1, lhist16RETI, histLRETI); retinexParams.getCurves(retinextransmissionCurve); } //void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) -void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) +void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) { MyTime t4, t5; @@ -2273,7 +2274,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC } } - MSR(LBuffer, conversionBuffer[2], conversionBuffer[3], WNew, HNew, deh, dehatransmissionCurve, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + MSR(LBuffer, conversionBuffer[2], conversionBuffer[3], cdcurve, mapcontlutili, WNew, HNew, deh, dehatransmissionCurve, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); if(useHsl) { if(chutili) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index ee89dd079..f9e7e6cf1 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -152,8 +152,8 @@ public: void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse); void demosaic (const RAWParams &raw); // void retinex (RAWParams raw, ColorManagementParams cmp, RetinexParams lcur, LUTf & cdcurve, bool dehacontlutili); - void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI); - void retinexPrepareCurves (RetinexParams retinexParams, LUTf &cdcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI); + void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI); + void retinexPrepareCurves (RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI); void retinexPrepareBuffers (ColorManagementParams cmp, RetinexParams retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI); void flushRawData (); void flushRGB (); @@ -230,7 +230,7 @@ public: void boxblur2(float** src, float** dst, float** temp, int H, int W, int box ); void boxblur_resamp(float **src, float **dst, float** temp, int H, int W, int box, int samp ); - void MSR(float** luminance, float **originalLuminance, float **exLuminance, int width, int height, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax); + void MSR(float** luminance, float **originalLuminance, float **exLuminance, LUTf & mapcurve, bool &mapcontlutili, int width, int height, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax); // void MSR(LabImage* lab, int width, int height, int skip, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve); //void boxblur_resamp(float **red, float **green, float **blue, int H, int W, float thresh[3], float max[3], diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 30373a35e..83cacfa1a 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -453,10 +453,17 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLhighl DEMOSAIC, // EvLbaselog // DEMOSAIC, // EvLgrbl - DEMOSAIC, // EvRetinexlhcurve - RETINEX, // EvLiter - RETINEX, // EvLgrad - RETINEX // EvLgrads + DEMOSAIC, // EvRetinexlhcurve + RETINEX, // EvLiter + RETINEX, // EvLgrad + RETINEX, // EvLgrads + RETINEX, //EvLhighlights + RETINEX, //EvLh_tonalwidth + RETINEX, //EvLshadows + RETINEX, //EvLs_tonalwidth + RETINEX, //EvLradius + RETINEX, //EvmapMethod + RETINEX //EvRetinexmapcurve }; diff --git a/rtengine/shmap.cc b/rtengine/shmap.cc index 34fadd5e7..f1539171d 100644 --- a/rtengine/shmap.cc +++ b/rtengine/shmap.cc @@ -64,6 +64,20 @@ void SHMap::fillLuminance( Imagefloat * img, float **luminance, double lumi[3] ) } +void SHMap::fillLuminanceL( float ** L, float **luminance) // fill with luminance +{ + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int i = 0; i < H; i++) + for (int j = 0; j < W; j++) { + luminance[i][j] = std::max(L[i][j], 0.f) ;//we can put here some enhancements Gamma, compression data,... + } + +} + void SHMap::update (Imagefloat* img, double radius, double lumi[3], bool hq, int skip) { @@ -210,6 +224,154 @@ void SHMap::update (Imagefloat* img, double radius, double lumi[3], bool hq, int } +void SHMap::updateL (float** L, double radius, bool hq, int skip) +{ + + if (!hq) { + fillLuminanceL( L, map); +#ifdef _OPENMP + #pragma omp parallel +#endif + { + gaussianBlur (map, map, W, H, radius); + } + } + + else + + { + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + //experimental dirpyr shmap + + float thresh = (100.f * radius); //1000; + + // set up range function + // calculate size of Lookup table. That's possible because from a value k for all i>=k rangefn[i] will be exp(-10) + // So we use this fact and the automatic clip of lut to reduce the size of lut and the number of calculations to fill the lut + // In past this lut had only integer precision with rangefn[i] = 0 for all i>=k + // We set the last element to a small epsilon 1e-15 instead of zero to avoid divisions by zero + const int lutSize = thresh * sqrtf(10.f) + 1; + thresh *= thresh; + LUTf rangefn(lutSize); + + for (int i = 0; i < lutSize - 1; i++) { + rangefn[i] = xexpf(-min(10.f, (static_cast(i) * i) / thresh )); //*intfactor; + } + + rangefn[lutSize - 1] = 1e-15f; + + // We need one temporary buffer + float ** buffer = allocArray (W, H); + + // the final result has to be in map + // for an even number of levels that means: map => buffer, buffer => map + // for an odd number of levels that means: buffer => map, map => buffer, buffer => map + // so let's calculate the number of levels first + // There are at least two levels + int numLevels = 2; + int scale = 2; + + while (skip * scale < 16) { + scale *= 2; + numLevels++; + } + //printf("numlev=%d\n",numLevels); + float ** dirpyrlo[2]; + + if(numLevels & 1) { // odd number of levels, start with buffer + dirpyrlo[0] = buffer; + dirpyrlo[1] = map; + } else { // even number of levels, start with map + dirpyrlo[0] = map; + dirpyrlo[1] = buffer; + } + + fillLuminanceL( L, dirpyrlo[0]); + + scale = 1; + int level = 0; + int indx = 0; + dirpyr_shmap(dirpyrlo[indx], dirpyrlo[1 - indx], W, H, rangefn, level, scale ); + scale *= 2; + level ++; + indx = 1 - indx; + + while (skip * scale < 16) { + dirpyr_shmap(dirpyrlo[indx], dirpyrlo[1 - indx], W, H, rangefn, level, scale ); + scale *= 2; + level ++; + indx = 1 - indx; + } + + dirpyr_shmap(dirpyrlo[indx], dirpyrlo[1 - indx], W, H, rangefn, level, scale ); + + freeArray(buffer, H); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + /* + // anti-alias filtering the result + #ifdef _OPENMP + #pragma omp for + #endif + for (int i=0; i0 && j>0 && i _max_f) { + _max_f = _val; + } + + _avg += _val; + } + +#ifdef _OPENMP + #pragma omp critical +#endif + { + if(_min_f < min_f ) { + min_f = _min_f; + } + + if(_max_f > max_f ) { + max_f = _max_f; + } + } + } + _avg /= ((H) * (W)); + avg = _avg; + +} + + void SHMap::forceStat (float max_, float min_, float avg_) { diff --git a/rtengine/shmap.h b/rtengine/shmap.h index 3d5609f48..97a394927 100644 --- a/rtengine/shmap.h +++ b/rtengine/shmap.h @@ -36,6 +36,7 @@ public: ~SHMap (); void update (Imagefloat* img, double radius, double lumi[3], bool hq, int skip); + void updateL (float** L, double radius, bool hq, int skip); void forceStat (float max_, float min_, float avg_); private: @@ -43,6 +44,7 @@ private: bool multiThread; void fillLuminance( Imagefloat * img, float **luminance, double lumi[3] ); + void fillLuminanceL( float ** L, float **luminance ); void dirpyr_shmap(float ** data_fine, float ** data_coarse, int width, int height, LUTf & rangefn, int level, int scale); }; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 91b7df178..1836c5446 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -118,16 +118,18 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p if(params.retinex.enabled) { //enabled Retinex LUTf cdcurve (65536, 0); + LUTf mapcurve (65536, 0); LUTu dummy; RetinextransmissionCurve dehatransmissionCurve; bool dehacontlutili = false; + bool mapcontlutili = false; bool useHsl = false; // multi_array2D conversionBuffer(1, 1); multi_array2D conversionBuffer(1, 1); imgsrc->retinexPrepareBuffers(params.icm, params.retinex, conversionBuffer, dummy); - imgsrc->retinexPrepareCurves(params.retinex, cdcurve, dehatransmissionCurve, dehacontlutili, useHsl, dummy, dummy ); + imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehacontlutili, mapcontlutili, useHsl, dummy, dummy ); float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; - imgsrc->retinex( params.icm, params.retinex, params.toneCurve, cdcurve, dehatransmissionCurve, conversionBuffer, dehacontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, dummy); + imgsrc->retinex( params.icm, params.retinex, params.toneCurve, mapcurve, dehatransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, dummy); } if (pl) { diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 2efed572e..5178f3b8a 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -50,9 +50,11 @@ void ParamsEdited::set (bool v) toneCurve.hrenabled = v; toneCurve.method = v; retinex.cdcurve = v; + retinex.mapcurve = v; retinex.cdHcurve = v; retinex.lhcurve = v; retinex.retinexMethod = v; + retinex.mapMethod = v; retinex.retinexcolorspace = v; retinex.gammaretinex = v; retinex.enabled = v; @@ -73,6 +75,12 @@ void ParamsEdited::set (bool v) // retinex.grbl = v; retinex.medianmap = v; retinex.transmissionCurve = v; + retinex.highlights = v; + retinex.htonalwidth = v; + retinex.shadows = v; + retinex.stonalwidth = v; + retinex.radius = v; + retinex.retinex = v; labCurve.lcurve = v; labCurve.acurve = v; @@ -530,10 +538,12 @@ void ParamsEdited::initFrom (const std::vector toneCurve.hrenabled = toneCurve.hrenabled && p.toneCurve.hrenabled == other.toneCurve.hrenabled; toneCurve.method = toneCurve.method && p.toneCurve.method == other.toneCurve.method; retinex.cdcurve = retinex.cdcurve && p.retinex.cdcurve == other.retinex.cdcurve; + retinex.mapcurve = retinex.mapcurve && p.retinex.mapcurve == other.retinex.mapcurve; retinex.cdHcurve = retinex.cdHcurve && p.retinex.cdHcurve == other.retinex.cdHcurve; retinex.lhcurve = retinex.lhcurve && p.retinex.lhcurve == other.retinex.lhcurve; retinex.transmissionCurve = retinex.transmissionCurve && p.retinex.transmissionCurve == other.retinex.transmissionCurve; retinex.retinexMethod = retinex.retinexMethod && p.retinex.retinexMethod == other.retinex.retinexMethod; + retinex.mapMethod = retinex.mapMethod && p.retinex.mapMethod == other.retinex.mapMethod; retinex.retinexcolorspace = retinex.retinexcolorspace && p.retinex.retinexcolorspace == other.retinex.retinexcolorspace; retinex.gammaretinex = retinex.gammaretinex && p.retinex.gammaretinex == other.retinex.gammaretinex; retinex.str = retinex.str && p.retinex.str == other.retinex.str; @@ -552,6 +562,12 @@ void ParamsEdited::initFrom (const std::vector retinex.baselog = retinex.baselog && p.retinex.baselog == other.retinex.baselog; // retinex.grbl = retinex.grbl && p.retinex.grbl == other.retinex.grbl; retinex.medianmap = retinex.medianmap && p.retinex.medianmap == other.retinex.medianmap; + retinex.highlights = retinex.highlights && p.retinex.highlights == other.retinex.highlights; + retinex.htonalwidth = retinex.htonalwidth && p.retinex.htonalwidth == other.retinex.htonalwidth; + retinex.shadows = retinex.shadows && p.retinex.shadows == other.retinex.shadows; + retinex.stonalwidth = retinex.stonalwidth && p.retinex.stonalwidth == other.retinex.stonalwidth; + retinex.radius = retinex.radius && p.retinex.radius == other.retinex.radius; + retinex.enabled = retinex.enabled && p.retinex.enabled == other.retinex.enabled; labCurve.lcurve = labCurve.lcurve && p.labCurve.lcurve == other.labCurve.lcurve; labCurve.acurve = labCurve.acurve && p.labCurve.acurve == other.labCurve.acurve; @@ -1052,6 +1068,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.retinex.cdcurve = mods.retinex.cdcurve; } + if (retinex.mapcurve) { + toEdit.retinex.mapcurve = mods.retinex.mapcurve; + } + if (retinex.cdHcurve) { toEdit.retinex.cdHcurve = mods.retinex.cdHcurve; } @@ -1068,6 +1088,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.retinex.retinexMethod = mods.retinex.retinexMethod; } + if (retinex.mapMethod) { + toEdit.retinex.mapMethod = mods.retinex.mapMethod; + } + if (retinex.retinexcolorspace) { toEdit.retinex.retinexcolorspace = mods.retinex.retinexcolorspace; } @@ -1144,6 +1168,28 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.retinex.vart = dontforceSet && options.baBehav[ADDSET_RETI_VART] ? toEdit.retinex.vart + mods.retinex.vart : mods.retinex.vart; } + if (retinex.highlights) { + toEdit.retinex.highlights = mods.retinex.highlights; + } + + if (retinex.htonalwidth) { + toEdit.retinex.htonalwidth = mods.retinex.htonalwidth; + } + + if (retinex.shadows) { + toEdit.retinex.shadows = mods.retinex.shadows; + + } + + if (retinex.stonalwidth) { + toEdit.retinex.stonalwidth = mods.retinex.stonalwidth; + } + + if (retinex.radius) { + toEdit.retinex.radius = mods.retinex.radius; + } + + if (labCurve.lcurve) { toEdit.labCurve.lcurve = mods.labCurve.lcurve; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index f174c8d52..ba53ee5ea 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -70,6 +70,7 @@ public: bool gain; bool offs; bool retinexMethod; + bool mapMethod; bool retinexcolorspace; bool gammaretinex; bool vart; @@ -80,11 +81,18 @@ public: bool method; bool transmissionCurve; bool cdcurve; + bool mapcurve; bool cdHcurve; bool lhcurve; bool retinex; bool medianmap; bool isUnchanged() const; + bool highlights; + bool htonalwidth; + bool shadows; + bool stonalwidth; + bool radius; + }; diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index 099ee7310..2ede52af6 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -83,6 +83,17 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), curveEditorGDH->curveListComplete(); + curveEditormap = new CurveEditorGroup (options.lastRetinexDir, M("TP_RETINEX_CONTEDIT_MAP")); + curveEditormap->setCurveListener (this); + mapshape = static_cast(curveEditormap->addCurve(CT_Diagonal, M("TP_RETINEX_CURVEEDITOR_MAP"))); + mapshape->setTooltip(M("TP_RETINEX_CURVEEDITOR_MAP_TOOLTIP")); + std::vector milestones222; + milestones222.push_back( GradientMilestone(0., 0., 0., 0.) ); + milestones222.push_back( GradientMilestone(1., 1., 1., 1.) ); + mapshape->setBottomBarBgGradient(milestones222); + mapshape->setLeftBarBgGradient(milestones222); + + curveEditormap->curveListComplete(); // Transmission map curve transmissionCurveEditorG = new CurveEditorGroup (options.lastRetinexDir, M("TP_RETINEX_TRANSMISSION")); @@ -163,6 +174,28 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), limd->set_tooltip_markup (M("TP_RETINEX_THRESHOLD_TOOLTIP")); baselog->set_tooltip_markup (M("TP_RETINEX_BASELOG_TOOLTIP")); + + mapbox = Gtk::manage (new Gtk::HBox ()); + labmap = Gtk::manage (new Gtk::Label (M("TP_RETINEX_MAP") + ":")); + mapbox->pack_start (*labmap, Gtk::PACK_SHRINK, 1); + + mapMethod = Gtk::manage (new MyComboBoxText ()); + mapMethod->append_text (M("TP_RETINEX_MAP_NONE")); + mapMethod->append_text (M("TP_RETINEX_MAP_CURV")); + mapMethod->append_text (M("TP_RETINEX_MAP_GAUS")); + mapMethod->append_text (M("TP_RETINEX_MAP_MAPP")); + mapMethod->append_text (M("TP_RETINEX_MAP_MAPT")); + mapMethod->set_active(0); + mapMethodConn = mapMethod->signal_changed().connect ( sigc::mem_fun(*this, &Retinex::mapMethodChanged) ); + mapMethod->set_tooltip_markup (M("TP_RETINEX_MAP_METHOD_TOOLTIP")); + + highlights = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), 0, 100, 1, 0)); + h_tonalwidth = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_HLTONALW"), 10, 100, 1, 80)); + shadows = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_SHADOWS"), 0, 100, 1, 0)); + s_tonalwidth = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_SHTONALW"), 10, 100, 1, 80)); + radius = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_RADIUS"), 5, 100, 1, 40)); + + curveEditorGH = new CurveEditorGroup (options.lastRetinexDir, M("TP_RETINEX_CONTEDIT_LH")); curveEditorGH->setCurveListener (this); @@ -241,6 +274,24 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), settingsVBox->pack_start (*limd); limd->show (); + settingsVBox->pack_start (*Gtk::manage (new Gtk::HSeparator())); + + mapbox->pack_start(*mapMethod); + settingsVBox->pack_start(*mapbox); + + settingsVBox->pack_start (*curveEditormap, Gtk::PACK_SHRINK, 4); + curveEditormap->show(); + + settingsVBox->pack_start (*highlights); + highlights->show(); + settingsVBox->pack_start (*h_tonalwidth); + h_tonalwidth->show(); + settingsVBox->pack_start (*shadows); + shadows->show(); + settingsVBox->pack_start (*s_tonalwidth); + s_tonalwidth->show(); + settingsVBox->pack_start (*radius); + radius->show(); // settingsVBox->pack_start (*highl); // highl->show (); @@ -249,6 +300,7 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), // settingsVBox->pack_start (*grbl); // grbl->show (); + settingsVBox->pack_start (*Gtk::manage (new Gtk::HSeparator())); settingsVBox->pack_start( *transmissionCurveEditorG, Gtk::PACK_SHRINK, 2); transmissionCurveEditorG->show(); @@ -354,6 +406,32 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), baselog->delay = 200; } + + radius->setAdjusterListener (this); + if (radius->delay < 200) { + radius->delay = 200; + } + + highlights->setAdjusterListener (this); + if (highlights->delay < 200) { + highlights->delay = 200; + } + + h_tonalwidth->setAdjusterListener (this); + if (h_tonalwidth->delay < 200) { + h_tonalwidth->delay = 200; + } + + shadows->setAdjusterListener (this); + if (shadows->delay < 200) { + shadows->delay = 200; + } + + s_tonalwidth->setAdjusterListener (this); + if (s_tonalwidth->delay < 200) { + s_tonalwidth->delay = 200; + } + /* grbl->setAdjusterListener (this); if (grbl->delay < 200) { @@ -378,6 +456,7 @@ Retinex::~Retinex() delete curveEditorGDH; delete transmissionCurveEditorG; delete curveEditorGH; + delete curveEditormap; } void Retinex::neutral_pressed () @@ -396,10 +475,20 @@ void Retinex::neutral_pressed () baselog->resetValue(false); gam->resetValue(false); slope->resetValue(false); + highlights->resetValue(false); + h_tonalwidth->resetValue(false); + shadows->resetValue(false); + s_tonalwidth->resetValue(false); + radius->resetValue(false); + mapMethod->set_active(0); + retinexMethod->set_active(2); + retinexcolorspace->set_active(0); + gammaretinex->set_active(0); transmissionShape->reset(); cdshape->reset(); cdshapeH->reset(); lhshape->reset(); + mapshape->reset(); } void Retinex::foldAllButMe (GdkEventButton* event, MyExpander *expander) @@ -509,6 +598,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) retinexMethodConn.block(true); retinexColorSpaceConn.block(true); gammaretinexConn.block(true); + mapMethodConn.block(true); if (pedited) { @@ -528,12 +618,21 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) // grbl->setEditedState (pedited->retinex.grbl ? Edited : UnEdited); set_inconsistent (multiImage && !pedited->retinex.enabled); medianmap->set_inconsistent (!pedited->retinex.medianmap); + radius->setEditedState (pedited->retinex.radius ? Edited : UnEdited); + highlights->setEditedState (pedited->retinex.highlights ? Edited : UnEdited); + h_tonalwidth->setEditedState (pedited->retinex.htonalwidth ? Edited : UnEdited); + shadows->setEditedState (pedited->retinex.shadows ? Edited : UnEdited); + s_tonalwidth->setEditedState (pedited->retinex.stonalwidth ? Edited : UnEdited); if (!pedited->retinex.retinexMethod) { retinexMethod->set_active_text(M("GENERAL_UNCHANGED")); } + if (!pedited->retinex.mapMethod) { + mapMethod->set_active_text(M("GENERAL_UNCHANGED")); + } + if (!pedited->retinex.retinexcolorspace) { retinexcolorspace->set_active_text(M("GENERAL_UNCHANGED")); } @@ -546,6 +645,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) cdshapeH->setUnChanged (!pedited->retinex.cdHcurve); transmissionShape->setUnChanged (!pedited->retinex.transmissionCurve); lhshape->setUnChanged (!pedited->retinex.lhcurve); + mapshape->setUnChanged (!pedited->retinex.mapcurve); } @@ -563,6 +663,13 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) slope->setValue (pp->retinex.slope); highl->setValue (pp->retinex.highl); baselog->setValue (pp->retinex.baselog); + + radius->setValue (pp->retinex.radius); + highlights->setValue (pp->retinex.highlights); + h_tonalwidth->setValue (pp->retinex.htonalwidth); + shadows->setValue (pp->retinex.shadows); + s_tonalwidth->setValue (pp->retinex.stonalwidth); + // grbl->setValue (pp->retinex.grbl); if(pp->retinex.iter == 1) { grad->set_sensitive(false); @@ -593,6 +700,19 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) // retinexMethod->set_active (4); } + if (pp->retinex.mapMethod == "none") { + mapMethod->set_active (0); + } else if (pp->retinex.mapMethod == "curv") { + mapMethod->set_active (1); + } else if (pp->retinex.mapMethod == "gaus") { + mapMethod->set_active (2); + } else if (pp->retinex.mapMethod == "map") { + mapMethod->set_active (3); + } else if (pp->retinex.mapMethod == "mapT") { + mapMethod->set_active (4); + } + + if (pp->retinex.retinexcolorspace == "Lab") { retinexcolorspace->set_active (0); } else if (pp->retinex.retinexcolorspace == "HSLLOG") { @@ -616,6 +736,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) retinexMethodChanged (); retinexColorSpaceChanged(); gammaretinexChanged(); + mapMethodChanged (); medianmapConn.block(true); medianmapChanged (); @@ -624,10 +745,12 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) cdshape->setCurve (pp->retinex.cdcurve); cdshapeH->setCurve (pp->retinex.cdHcurve); lhshape->setCurve (pp->retinex.lhcurve); + mapshape->setCurve (pp->retinex.mapcurve); retinexMethodConn.block(false); retinexColorSpaceConn.block(false); gammaretinexConn.block(false); + mapMethodConn.block(false); transmissionShape->setCurve (pp->retinex.transmissionCurve); @@ -657,14 +780,22 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pp->retinex.cdcurve = cdshape->getCurve (); pp->retinex.lhcurve = lhshape->getCurve (); pp->retinex.cdHcurve = cdshapeH->getCurve (); + pp->retinex.mapcurve = mapshape->getCurve (); pp->retinex.transmissionCurve = transmissionShape->getCurve (); pp->retinex.enabled = getEnabled(); pp->retinex.medianmap = medianmap->get_active(); + pp->retinex.radius = (int)radius->getValue (); + pp->retinex.highlights = (int)highlights->getValue (); + pp->retinex.htonalwidth = (int)h_tonalwidth->getValue (); + pp->retinex.shadows = (int)shadows->getValue (); + pp->retinex.stonalwidth = (int)s_tonalwidth->getValue (); + if (pedited) { pedited->retinex.retinexMethod = retinexMethod->get_active_text() != M("GENERAL_UNCHANGED"); pedited->retinex.retinexcolorspace = retinexcolorspace->get_active_text() != M("GENERAL_UNCHANGED"); pedited->retinex.gammaretinex = gammaretinex->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->retinex.mapMethod = mapMethod->get_active_text() != M("GENERAL_UNCHANGED"); //%%%%%%%%%%%%%%%%%%%%%% pedited->retinex.str = str->getEditedState (); @@ -685,10 +816,17 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pedited->retinex.cdcurve = !cdshape->isUnChanged (); pedited->retinex.cdHcurve = !cdshapeH->isUnChanged (); pedited->retinex.transmissionCurve = !transmissionShape->isUnChanged (); + pedited->retinex.mapcurve = !mapshape->isUnChanged (); pedited->retinex.enabled = !get_inconsistent(); pedited->retinex.medianmap = !medianmap->get_inconsistent(); pedited->retinex.lhcurve = !lhshape->isUnChanged (); + pedited->retinex.radius = radius->getEditedState (); + pedited->retinex.highlights = highlights->getEditedState (); + pedited->retinex.htonalwidth = h_tonalwidth->getEditedState (); + pedited->retinex.shadows = shadows->getEditedState (); + pedited->retinex.stonalwidth = s_tonalwidth->getEditedState (); + } if (retinexMethod->get_active_row_number() == 0) { @@ -703,6 +841,18 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) // pp->retinex.retinexMethod = "highliplus"; } + if (mapMethod->get_active_row_number() == 0) { + pp->retinex.mapMethod = "none"; + } else if (mapMethod->get_active_row_number() == 1) { + pp->retinex.mapMethod = "curv"; + } else if (mapMethod->get_active_row_number() == 2) { + pp->retinex.mapMethod = "gaus"; + } else if (mapMethod->get_active_row_number() == 3) { + pp->retinex.mapMethod = "map"; + } else if (mapMethod->get_active_row_number() == 4) { + pp->retinex.mapMethod = "mapT"; + } + if (retinexcolorspace->get_active_row_number() == 0) { pp->retinex.retinexcolorspace = "Lab"; } else if (retinexcolorspace->get_active_row_number() == 1) { @@ -739,6 +889,40 @@ void Retinex::retinexMethodChanged() } } + + +void Retinex::mapMethodChanged() +{ + + if(mapMethod->get_active_row_number() >= 1) { + curveEditormap->show(); + highlights->show(); + h_tonalwidth->show(); + shadows->show(); + s_tonalwidth->show(); + radius->show(); + /* } else if(mapMethod->get_active_row_number() == 1) { + curveEditormap->show(); + highlights->hide(); + h_tonalwidth->hide(); + shadows->hide(); + s_tonalwidth->hide(); + radius->hide();*/ + } else { + curveEditormap->hide(); + highlights->hide(); + h_tonalwidth->hide(); + shadows->hide(); + s_tonalwidth->hide(); + radius->hide(); + + } + + if (listener) { + listener->panelChanged (EvmapMethod, mapMethod->get_active_text ()); + } +} + void Retinex::ColorSpaceUpdateUI () { if (!batchMode) { @@ -838,6 +1022,12 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi gam->setDefault (defParams->retinex.gam); slope->setDefault (defParams->retinex.slope); + radius->setDefault (defParams->retinex.radius); + highlights->setDefault (defParams->retinex.highlights); + h_tonalwidth->setDefault (defParams->retinex.htonalwidth); + shadows->setDefault (defParams->retinex.shadows); + s_tonalwidth->setDefault (defParams->retinex.stonalwidth); + if (pedited) { neigh->setDefaultEditedState (pedited->retinex.neigh ? Edited : UnEdited); gain->setDefaultEditedState (pedited->retinex.gain ? Edited : UnEdited); @@ -855,6 +1045,12 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi gam->setDefaultEditedState (pedited->retinex.gam ? Edited : UnEdited); slope->setDefaultEditedState (pedited->retinex.slope ? Edited : UnEdited); + radius->setDefaultEditedState (pedited->retinex.radius ? Edited : UnEdited); + highlights->setDefaultEditedState (pedited->retinex.highlights ? Edited : UnEdited); + h_tonalwidth->setDefaultEditedState (pedited->retinex.htonalwidth ? Edited : UnEdited); + shadows->setDefaultEditedState (pedited->retinex.shadows ? Edited : UnEdited); + s_tonalwidth->setDefaultEditedState (pedited->retinex.stonalwidth ? Edited : UnEdited); + } else { neigh->setDefaultEditedState (Irrelevant); gain->setDefaultEditedState (Irrelevant); @@ -871,6 +1067,13 @@ void Retinex::setDefaults (const ProcParams* defParams, const ParamsEdited* pedi grads->setDefaultEditedState (Irrelevant); gam->setDefaultEditedState (Irrelevant); slope->setDefaultEditedState (Irrelevant); + + radius->setDefaultEditedState (Irrelevant); + highlights->setDefaultEditedState (Irrelevant); + h_tonalwidth->setDefaultEditedState (Irrelevant); + shadows->setDefaultEditedState (Irrelevant); + s_tonalwidth->setDefaultEditedState (Irrelevant); + } } @@ -935,8 +1138,20 @@ void Retinex::adjusterChanged (Adjuster* a, double newval) listener->panelChanged (EvLgam, gam->getTextValue()); } else if (a == slope) { listener->panelChanged (EvLslope, slope->getTextValue()); + } else if (a == highlights) { + listener->panelChanged (EvLhighlights, highlights->getTextValue()); + } else if (a == h_tonalwidth) { + listener->panelChanged (EvLh_tonalwidth, h_tonalwidth->getTextValue()); + } else if (a == shadows) { + listener->panelChanged (EvLshadows, shadows->getTextValue()); + } else if (a == s_tonalwidth) { + listener->panelChanged (EvLs_tonalwidth, s_tonalwidth->getTextValue()); + } else if (a == radius) { + listener->panelChanged (EvLradius, radius->getTextValue()); + } + } @@ -947,6 +1162,7 @@ void Retinex::autoOpenCurve () cdshapeH->openIfNonlinear(); transmissionShape->openIfNonlinear(); lhshape->openIfNonlinear(); + mapshape->openIfNonlinear(); } @@ -962,6 +1178,8 @@ void Retinex::curveChanged (CurveEditor* ce) listener->panelChanged (EvRetinextransmission, M("HISTORY_CUSTOMCURVE")); } else if (ce == lhshape) { listener->panelChanged (EvRetinexlhcurve, M("HISTORY_CUSTOMCURVE")); + } else if (ce == mapshape) { + listener->panelChanged (EvRetinexmapcurve, M("HISTORY_CUSTOMCURVE")); } } } @@ -998,6 +1216,8 @@ void Retinex::trimValues (rtengine::procparams::ProcParams* pp) // grbl->trimValue(pp->retinex.grbl); gam->trimValue(pp->retinex.gam); slope->trimValue(pp->retinex.slope); + highlights->trimValue(pp->retinex.highlights); + shadows->trimValue(pp->retinex.shadows); } void Retinex::updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve,/* LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histLRETI) @@ -1070,11 +1290,19 @@ void Retinex::setBatchMode (bool batchMode) limd->showEditedCB (); highl->showEditedCB (); baselog->showEditedCB (); + + radius->showEditedCB (); + highlights->showEditedCB (); + h_tonalwidth->showEditedCB (); + shadows->showEditedCB (); + s_tonalwidth->showEditedCB (); + // grbl->showEditedCB (); curveEditorGD->setBatchMode (batchMode); curveEditorGDH->setBatchMode (batchMode); transmissionCurveEditorG->setBatchMode (batchMode); curveEditorGH->setBatchMode (batchMode); + curveEditormap->setBatchMode (batchMode); } diff --git a/rtgui/retinex.h b/rtgui/retinex.h index e014bed5d..ac55fea99 100644 --- a/rtgui/retinex.h +++ b/rtgui/retinex.h @@ -22,6 +22,7 @@ protected: CurveEditorGroup* curveEditorGD; CurveEditorGroup* curveEditorGDH; CurveEditorGroup* curveEditorGH; + CurveEditorGroup* curveEditormap; Adjuster* str; Adjuster* scal; Adjuster* grad; @@ -37,10 +38,19 @@ protected: Adjuster* grbl; Adjuster* gam; Adjuster* slope; + Adjuster* highlights; + Adjuster* h_tonalwidth; + Adjuster* shadows; + Adjuster* s_tonalwidth; + Adjuster* radius; + MyExpander* expsettings; Gtk::Label* labmdh; Gtk::HBox* dhbox; + Gtk::HBox* mapbox; + Gtk::Label* labmap; + Gtk::Label* labgam; Gtk::HBox* gambox; Gtk::Button* neutral; @@ -49,6 +59,7 @@ protected: MyComboBoxText* retinexMethod; MyComboBoxText* retinexcolorspace; MyComboBoxText* gammaretinex; + MyComboBoxText* mapMethod; Gtk::CheckButton* medianmap; double nextmin; double nextmax; @@ -65,8 +76,9 @@ protected: DiagonalCurveEditor* cdshape; DiagonalCurveEditor* cdshapeH; + DiagonalCurveEditor* mapshape; CurveEditorGroup* transmissionCurveEditorG; - sigc::connection retinexMethodConn, neutralconn; + sigc::connection retinexMethodConn, neutralconn, mapMethodConn; sigc::connection retinexColorSpaceConn; sigc::connection gammaretinexConn; FlatCurveEditor* transmissionShape; @@ -95,6 +107,7 @@ public: void enabledChanged (); void curveChanged (CurveEditor* ce); void retinexMethodChanged(); + void mapMethodChanged(); void retinexColorSpaceChanged(); void gammaretinexChanged(); void ColorSpaceUpdateUI(); From f74e4b0dd20aafce52a208434570bece705687c1 Mon Sep 17 00:00:00 2001 From: Desmis Date: Fri, 13 Nov 2015 08:45:24 +0100 Subject: [PATCH 7/9] Fixed numerous bug and add Preview for mask and transmission --- rtdata/languages/default | 6 +++ rtengine/imagesource.h | 2 +- rtengine/improccoordinator.cc | 2 +- rtengine/ipretinex.cc | 33 ++++++++++--- rtengine/procevents.h | 2 + rtengine/procparams.cc | 15 ++++++ rtengine/procparams.h | 1 + rtengine/rawimagesource.cc | 4 +- rtengine/rawimagesource.h | 2 +- rtengine/refreshmap.cc | 7 +-- rtengine/shmap.cc | 17 ++++--- rtengine/simpleprocess.cc | 2 +- rtgui/paramsedited.cc | 6 +++ rtgui/paramsedited.h | 1 + rtgui/retinex.cc | 91 ++++++++++++++++++++++++++++++++--- rtgui/retinex.h | 6 ++- 16 files changed, 165 insertions(+), 32 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 97b327ef6..4ec24b42c 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -666,6 +666,7 @@ HISTORY_MSG_433;Retinex - Mask TW shadows HISTORY_MSG_434;Retinex - Mask radius HISTORY_MSG_435;Retinex - Mask method HISTORY_MSG_436;Retinex - Mask curve +HISTORY_MSG_437;Retinex - Preview HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOTS;Snapshots @@ -1707,6 +1708,11 @@ TP_RETINEX_TRANSMISSION_TOOLTIP;Transmission according to transmission.\nAbsciss TP_RETINEX_UNIFORM;Uniform TP_RETINEX_VARIANCE;Variance TP_RETINEX_VARIANCE_TOOLTIP;Low variance increase local contrast and saturation, but can lead to artifacts. +TP_RETINEX_VIEW;Preview +TP_RETINEX_VIEW_NONE;Standard +TP_RETINEX_VIEW_MASK;Mask +TP_RETINEX_VIEW_TRAN;Transmission +TP_RETINEX_VIEW_METHOD_TOOLTIP;Standard - normal display\nMask - display mask\nTransmission - displays the file transmission-map , before any action on contrast and brightness\nAttention, this does not correspond to reality, but a shift to make it visible TP_RGBCURVES_BLUE;B TP_RGBCURVES_CHANNEL;Channel TP_RGBCURVES_GREEN;G diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index eaf9997fa..80fc53f23 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -69,7 +69,7 @@ public: virtual int load (Glib::ustring fname, bool batch = false) = 0; virtual void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse) {}; virtual void demosaic (const RAWParams &raw) {}; - virtual void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; + virtual void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; virtual void retinexPrepareCurves (RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) {}; virtual void retinexPrepareBuffers (ColorManagementParams cmp, RetinexParams retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI) {}; virtual void flushRawData () {}; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 479ec1282..dc135c4d5 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -251,7 +251,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehacontlutili, mapcontlutili, useHsl, lhist16RETI, histLRETI); float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; - imgsrc->retinex( params.icm, params.retinex, params.toneCurve, mapcurve, dehatransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI);//enabled Retinex + imgsrc->retinex( params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI);//enabled Retinex if(dehaListener) { dehaListener->minmaxChanged(maxCD, minCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index d444380ce..839d8646e 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -405,7 +405,12 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e if(deh.mapMethod=="mapT") mapmet=3; if(deh.mapMethod=="curv") mapmet=1; if(deh.mapMethod=="gaus") mapmet=4; + double shradius = (double) deh.radius; + // printf("shrad=%f\n",shradius); + int viewmet=0; + if(deh.viewMethod=="mask") viewmet=1; + if(deh.viewMethod=="tran") viewmet=2; #ifdef _OPENMP #pragma omp parallel for @@ -424,6 +429,13 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e out[i] = &outBuffer[i * W_L]; } + float *tran[H_L] ALIGNED16; + float *tranBuffer = new float[H_L * W_L]; + + for (int i = 0; i < H_L; i++) { + tran[i] = &tranBuffer[i * W_L]; + } + const float logBetaGain = xlogf(16384.f); float pond = logBetaGain / (float) scal; @@ -451,8 +463,8 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e printf(".."); - double shradius = deh.radius; - if(mapmet==4) shradius /= 10.; + if(mapmet==4) shradius /= 1.; + else shradius = 40.; // if(shHighlights > 0 || shShadows > 0) { if(mapmet==3) if(it==1) shmap->updateL (out, shradius, true, 1);//wav Total @@ -488,7 +500,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } // if(shHighlights > 0 || shShadows > 0) { - if((mapmet == 2 && scale >2) || mapmet==3 || mapmet==4) { + if(((mapmet == 2 && scale >2) || mapmet==3 || mapmet==4) && it==1) { #ifdef _OPENMP @@ -545,6 +557,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } } } + printf(".\n"); if(mapmet > 1) { if(shmap) { delete shmap; @@ -553,7 +566,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e shmap = NULL; delete [] buffer; - delete [] outBuffer; +// delete [] outBuffer; delete [] srcBuffer; mean = 0.f; @@ -598,6 +611,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } luminance[i][j] *= (-1.f + 4.f * dehatransmissionCurve[absciss]); //new transmission + tran[i][j]=luminance[i][j]; } } @@ -713,8 +727,10 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } } - // if(exLuminance[i][j] > 65535.f*hig && higplus) str *= hig; - luminance[i][j] = clipretinex( cd, 0.f, 32768.f ) * str + (1.f - str) * originalLuminance[i][j]; + if(exLuminance[i][j] > 65535.f*hig && higplus) str *= hig; + if(viewmet==0) luminance[i][j]=clipretinex( cd, 0.f, 32768.f ) * str + (1.f - str) * originalLuminance[i][j]; + if(viewmet==1) luminance[i][j] = out[i][j]; + if(viewmet==2) luminance[i][j] = 1000.f+ tran[i][j]*700.f;//arbitrary values to help display log values which are between -20 to + 30 - usage values -4 + 5 } #ifdef _OPENMP @@ -726,6 +742,11 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } } + delete [] outBuffer; + outBuffer = NULL; + delete [] tranBuffer; + tranBuffer = NULL; + // printf("cdmin=%f cdmax=%f\n",minCD, maxCD); Tmean = mean; Tsigma = stddv; diff --git a/rtengine/procevents.h b/rtengine/procevents.h index f23d68f2e..d02018d78 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -464,6 +464,8 @@ enum ProcEvent { EvLradius = 433, EvmapMethod = 434, EvRetinexmapcurve = 435, + EvviewMethod = 436, + NUMOFEVENTS }; } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 075067585..7a674e8c3 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -163,6 +163,7 @@ void RetinexParams::setDefaults() // grbl = 50; retinexMethod = "high"; mapMethod = "none"; + viewMethod = "none"; retinexcolorspace = "Lab"; gammaretinex = "none"; medianmap = false; @@ -1526,6 +1527,10 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_string ("Retinex", "mapMethod", retinex.mapMethod); } + if (!pedited || pedited->retinex.viewMethod) { + keyFile.set_string ("Retinex", "viewMethod", retinex.viewMethod); + } + if (!pedited || pedited->retinex.retinexcolorspace) { keyFile.set_string ("Retinex", "Retinexcolorspace", retinex.retinexcolorspace); } @@ -3864,6 +3869,15 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Retinex", "viewMethod")) { + retinex.viewMethod = keyFile.get_string ("Retinex", "viewMethod"); + + if (pedited) { + pedited->retinex.viewMethod = true; + } + } + + if (keyFile.has_key ("Retinex", "Retinexcolorspace")) { retinex.retinexcolorspace = keyFile.get_string ("Retinex", "Retinexcolorspace"); @@ -7478,6 +7492,7 @@ bool ProcParams::operator== (const ProcParams& other) && retinex.offs == other.retinex.offs && retinex.retinexMethod == other.retinex.retinexMethod && retinex.mapMethod == other.retinex.mapMethod + && retinex.viewMethod == other.retinex.viewMethod && retinex.retinexcolorspace == other.retinex.retinexcolorspace && retinex.gammaretinex == other.retinex.gammaretinex && retinex.vart == other.retinex.vart diff --git a/rtengine/procparams.h b/rtengine/procparams.h index e2d2539ea..0aa31a9bd 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -294,6 +294,7 @@ public: Glib::ustring retinexcolorspace; Glib::ustring gammaretinex; Glib::ustring mapMethod; + Glib::ustring viewMethod; int vart; int limd; int highl; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 8a4fc3559..c552c64ac 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2122,7 +2122,7 @@ void RawImageSource::retinexPrepareCurves(RetinexParams retinexParams, LUTf &cdc } //void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) -void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) +void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) { MyTime t4, t5; @@ -2274,7 +2274,7 @@ void RawImageSource::retinex(ColorManagementParams cmp, RetinexParams deh, ToneC } } - MSR(LBuffer, conversionBuffer[2], conversionBuffer[3], cdcurve, mapcontlutili, WNew, HNew, deh, dehatransmissionCurve, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); + MSR(LBuffer, conversionBuffer[2], conversionBuffer[3], mapcurve, mapcontlutili, WNew, HNew, deh, dehatransmissionCurve, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); if(useHsl) { if(chutili) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index f9e7e6cf1..10057d58a 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -152,7 +152,7 @@ public: void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse); void demosaic (const RAWParams &raw); // void retinex (RAWParams raw, ColorManagementParams cmp, RetinexParams lcur, LUTf & cdcurve, bool dehacontlutili); - void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI); + void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI); void retinexPrepareCurves (RetinexParams retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI); void retinexPrepareBuffers (ColorManagementParams cmp, RetinexParams retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI); void flushRawData (); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 83cacfa1a..915ed615d 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -440,13 +440,13 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLstr RETINEX, // EvLscal RETINEX, // EvLvart - RETINEX, // EvLCDCurve + DEMOSAIC, // EvLCDCurve RETINEX, // EvRetinextransmission DEMOSAIC, // EvRetinexEnabled RETINEX, // EvRetinexmedianmap RETINEX, // EvLlimd DEMOSAIC, // Evretinexcolorspace - RETINEX, // EvLCDHCurve + DEMOSAIC, // EvLCDHCurve DEMOSAIC, // Evretinexgamma DEMOSAIC, // EvLgam DEMOSAIC, // EvLslope @@ -463,7 +463,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, //EvLs_tonalwidth RETINEX, //EvLradius RETINEX, //EvmapMethod - RETINEX //EvRetinexmapcurve + DEMOSAIC, //EvRetinexmapcurve + DEMOSAIC //EvviewMethod }; diff --git a/rtengine/shmap.cc b/rtengine/shmap.cc index f1539171d..2471b17a4 100644 --- a/rtengine/shmap.cc +++ b/rtengine/shmap.cc @@ -242,23 +242,23 @@ void SHMap::updateL (float** L, double radius, bool hq, int skip) { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //experimental dirpyr shmap - float thresh = (100.f * radius); //1000; - + int levrad = 16; + levrad=2;//for retinex - otherwise levrad = 16 // set up range function // calculate size of Lookup table. That's possible because from a value k for all i>=k rangefn[i] will be exp(-10) // So we use this fact and the automatic clip of lut to reduce the size of lut and the number of calculations to fill the lut // In past this lut had only integer precision with rangefn[i] = 0 for all i>=k // We set the last element to a small epsilon 1e-15 instead of zero to avoid divisions by zero - const int lutSize = thresh * sqrtf(10.f) + 1; + const int lutSize = (int) thresh * sqrtf(10.f) + 1; thresh *= thresh; LUTf rangefn(lutSize); - for (int i = 0; i < lutSize - 1; i++) { rangefn[i] = xexpf(-min(10.f, (static_cast(i) * i) / thresh )); //*intfactor; } rangefn[lutSize - 1] = 1e-15f; + //printf("lut=%d rf5=%f rfm=%f\n thre=%f",lutSize, rangefn[5],rangefn[lutSize-10],thresh ); // We need one temporary buffer float ** buffer = allocArray (W, H); @@ -271,7 +271,7 @@ void SHMap::updateL (float** L, double radius, bool hq, int skip) int numLevels = 2; int scale = 2; - while (skip * scale < 16) { + while (skip * scale < levrad) { scale *= 2; numLevels++; } @@ -296,7 +296,7 @@ void SHMap::updateL (float** L, double radius, bool hq, int skip) level ++; indx = 1 - indx; - while (skip * scale < 16) { + while (skip * scale < levrad) { dirpyr_shmap(dirpyrlo[indx], dirpyrlo[1 - indx], W, H, rangefn, level, scale ); scale *= 2; level ++; @@ -398,7 +398,7 @@ SSEFUNCTION void SHMap::dirpyr_shmap(float ** data_fine, float ** data_coarse, i #endif { #if defined( __SSE2__ ) && defined( __x86_64__ ) - __m128 dirwtv, valv, normv, dftemp1v, dftemp2v; + __m128 dirwtv, valv, normv, dftemp1v, dftemp2v, fg; #endif // __SSE2__ int j; #ifdef _OPENMP @@ -414,6 +414,7 @@ SSEFUNCTION void SHMap::dirpyr_shmap(float ** data_fine, float ** data_coarse, i for(int inbr = max(i - scalewin, i % scale); inbr <= min(i + scalewin, height - 1); inbr += scale) { for (int jnbr = j % scale; jnbr <= j + scalewin; jnbr += scale) { + //printf("dat=%f ",abs(data_fine[inbr][jnbr] - data_fine[i][j])); dirwt = ( rangefn[abs(data_fine[inbr][jnbr] - data_fine[i][j])] ); val += dirwt * data_fine[inbr][jnbr]; norm += dirwt; @@ -504,7 +505,7 @@ SSEFUNCTION void SHMap::dirpyr_shmap(float ** data_fine, float ** data_coarse, i #endif { #if defined( __SSE2__ ) && defined( __x86_64__ ) - __m128 dirwtv, valv, normv, dftemp1v, dftemp2v; + __m128 dirwtv, valv, normv, dftemp1v, dftemp2v, fgg; float domkerv[5][5][4] __attribute__ ((aligned (16))) = {{{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}, {{1, 1, 1, 1}, {2, 2, 2, 2}, {2, 2, 2, 2}, {2, 2, 2, 2}, {1, 1, 1, 1}}, {{1, 1, 1, 1}, {2, 2, 2, 2}, {2, 2, 2, 2}, {2, 2, 2, 2}, {1, 1, 1, 1}}, {{1, 1, 1, 1}, {2, 2, 2, 2}, {2, 2, 2, 2}, {2, 2, 2, 2}, {1, 1, 1, 1}}, {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}}}; #endif // __SSE2__ diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 1836c5446..3e667c129 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -129,7 +129,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p imgsrc->retinexPrepareBuffers(params.icm, params.retinex, conversionBuffer, dummy); imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehacontlutili, mapcontlutili, useHsl, dummy, dummy ); float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; - imgsrc->retinex( params.icm, params.retinex, params.toneCurve, mapcurve, dehatransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, dummy); + imgsrc->retinex( params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, dummy); } if (pl) { diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 5178f3b8a..35f26c58c 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -55,6 +55,7 @@ void ParamsEdited::set (bool v) retinex.lhcurve = v; retinex.retinexMethod = v; retinex.mapMethod = v; + retinex.viewMethod = v; retinex.retinexcolorspace = v; retinex.gammaretinex = v; retinex.enabled = v; @@ -544,6 +545,7 @@ void ParamsEdited::initFrom (const std::vector retinex.transmissionCurve = retinex.transmissionCurve && p.retinex.transmissionCurve == other.retinex.transmissionCurve; retinex.retinexMethod = retinex.retinexMethod && p.retinex.retinexMethod == other.retinex.retinexMethod; retinex.mapMethod = retinex.mapMethod && p.retinex.mapMethod == other.retinex.mapMethod; + retinex.viewMethod = retinex.viewMethod && p.retinex.viewMethod == other.retinex.viewMethod; retinex.retinexcolorspace = retinex.retinexcolorspace && p.retinex.retinexcolorspace == other.retinex.retinexcolorspace; retinex.gammaretinex = retinex.gammaretinex && p.retinex.gammaretinex == other.retinex.gammaretinex; retinex.str = retinex.str && p.retinex.str == other.retinex.str; @@ -1092,6 +1094,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.retinex.mapMethod = mods.retinex.mapMethod; } + if (retinex.viewMethod) { + toEdit.retinex.viewMethod = mods.retinex.viewMethod; + } + if (retinex.retinexcolorspace) { toEdit.retinex.retinexcolorspace = mods.retinex.retinexcolorspace; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index ba53ee5ea..60fbbdb81 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -71,6 +71,7 @@ public: bool offs; bool retinexMethod; bool mapMethod; + bool viewMethod; bool retinexcolorspace; bool gammaretinex; bool vart; diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index 2ede52af6..5e4a9f636 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -195,6 +195,17 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), s_tonalwidth = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_SHTONALW"), 10, 100, 1, 80)); radius = Gtk::manage (new Adjuster (M("TP_SHADOWSHLIGHTS_RADIUS"), 5, 100, 1, 40)); + viewbox = Gtk::manage (new Gtk::HBox ()); + labview = Gtk::manage (new Gtk::Label (M("TP_RETINEX_VIEW") + ":")); + viewbox->pack_start (*labview, Gtk::PACK_SHRINK, 1); + + viewMethod = Gtk::manage (new MyComboBoxText ()); + viewMethod->append_text (M("TP_RETINEX_VIEW_NONE")); + viewMethod->append_text (M("TP_RETINEX_VIEW_MASK")); + viewMethod->append_text (M("TP_RETINEX_VIEW_TRAN")); + viewMethod->set_active(0); + viewMethodConn = viewMethod->signal_changed().connect ( sigc::mem_fun(*this, &Retinex::viewMethodChanged) ); + viewMethod->set_tooltip_markup (M("TP_RETINEX_VIEW_METHOD_TOOLTIP")); curveEditorGH = new CurveEditorGroup (options.lastRetinexDir, M("TP_RETINEX_CONTEDIT_LH")); curveEditorGH->setCurveListener (this); @@ -292,6 +303,12 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), s_tonalwidth->show(); settingsVBox->pack_start (*radius); radius->show(); + + viewbox->pack_start(*viewMethod); + settingsVBox->pack_start(*viewbox); + + //settingsVBox->pack_start (*viewMethod); + // settingsVBox->pack_start (*highl); // highl->show (); @@ -481,6 +498,7 @@ void Retinex::neutral_pressed () s_tonalwidth->resetValue(false); radius->resetValue(false); mapMethod->set_active(0); + viewMethod->set_active(0); retinexMethod->set_active(2); retinexcolorspace->set_active(0); gammaretinex->set_active(0); @@ -599,6 +617,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) retinexColorSpaceConn.block(true); gammaretinexConn.block(true); mapMethodConn.block(true); + viewMethodConn.block(true); if (pedited) { @@ -633,6 +652,10 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) mapMethod->set_active_text(M("GENERAL_UNCHANGED")); } + if (!pedited->retinex.viewMethod) { + viewMethod->set_active_text(M("GENERAL_UNCHANGED")); + } + if (!pedited->retinex.retinexcolorspace) { retinexcolorspace->set_active_text(M("GENERAL_UNCHANGED")); } @@ -712,6 +735,13 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) mapMethod->set_active (4); } + if (pp->retinex.viewMethod == "none") { + viewMethod->set_active (0); + } else if (pp->retinex.viewMethod == "mask") { + viewMethod->set_active (1); + } else if (pp->retinex.viewMethod == "tran") { + viewMethod->set_active (2); + } if (pp->retinex.retinexcolorspace == "Lab") { retinexcolorspace->set_active (0); @@ -737,6 +767,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) retinexColorSpaceChanged(); gammaretinexChanged(); mapMethodChanged (); + viewMethodChanged (); medianmapConn.block(true); medianmapChanged (); @@ -751,6 +782,7 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) retinexColorSpaceConn.block(false); gammaretinexConn.block(false); mapMethodConn.block(false); + viewMethodConn.block(false); transmissionShape->setCurve (pp->retinex.transmissionCurve); @@ -796,6 +828,7 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pedited->retinex.retinexcolorspace = retinexcolorspace->get_active_text() != M("GENERAL_UNCHANGED"); pedited->retinex.gammaretinex = gammaretinex->get_active_text() != M("GENERAL_UNCHANGED"); pedited->retinex.mapMethod = mapMethod->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->retinex.viewMethod = viewMethod->get_active_text() != M("GENERAL_UNCHANGED"); //%%%%%%%%%%%%%%%%%%%%%% pedited->retinex.str = str->getEditedState (); @@ -853,6 +886,14 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) pp->retinex.mapMethod = "mapT"; } + if (viewMethod->get_active_row_number() == 0) { + pp->retinex.viewMethod = "none"; + } else if (viewMethod->get_active_row_number() == 1) { + pp->retinex.viewMethod = "mask"; + } else if (viewMethod->get_active_row_number() == 2) { + pp->retinex.viewMethod = "tran"; + } + if (retinexcolorspace->get_active_row_number() == 0) { pp->retinex.retinexcolorspace = "Lab"; } else if (retinexcolorspace->get_active_row_number() == 1) { @@ -894,20 +935,20 @@ void Retinex::retinexMethodChanged() void Retinex::mapMethodChanged() { - if(mapMethod->get_active_row_number() >= 1) { + if(mapMethod->get_active_row_number() == 1 || mapMethod->get_active_row_number() == 2) { curveEditormap->show(); highlights->show(); h_tonalwidth->show(); shadows->show(); s_tonalwidth->show(); radius->show(); - /* } else if(mapMethod->get_active_row_number() == 1) { - curveEditormap->show(); - highlights->hide(); - h_tonalwidth->hide(); - shadows->hide(); - s_tonalwidth->hide(); - radius->hide();*/ + } else if(mapMethod->get_active_row_number() == 3 || mapMethod->get_active_row_number() == 4) { + curveEditormap->show(); + highlights->show(); + h_tonalwidth->show(); + shadows->show(); + s_tonalwidth->show(); + radius->hide(); } else { curveEditormap->hide(); highlights->hide(); @@ -923,6 +964,40 @@ void Retinex::mapMethodChanged() } } +void Retinex::viewMethodChanged() +{ + /* + if(mapMethod->get_active_row_number() == 1 || mapMethod->get_active_row_number() == 2) { + curveEditormap->show(); + highlights->show(); + h_tonalwidth->show(); + shadows->show(); + s_tonalwidth->show(); + radius->show(); + } else if(mapMethod->get_active_row_number() == 3 || mapMethod->get_active_row_number() == 4) { + curveEditormap->show(); + highlights->show(); + h_tonalwidth->show(); + shadows->show(); + s_tonalwidth->show(); + radius->hide(); + } else { + curveEditormap->hide(); + highlights->hide(); + h_tonalwidth->hide(); + shadows->hide(); + s_tonalwidth->hide(); + radius->hide(); + + } + */ + if (listener) { + listener->panelChanged (EvviewMethod, viewMethod->get_active_text ()); + } +} + + + void Retinex::ColorSpaceUpdateUI () { if (!batchMode) { diff --git a/rtgui/retinex.h b/rtgui/retinex.h index ac55fea99..d24254757 100644 --- a/rtgui/retinex.h +++ b/rtgui/retinex.h @@ -50,6 +50,8 @@ protected: Gtk::HBox* dhbox; Gtk::HBox* mapbox; Gtk::Label* labmap; + Gtk::HBox* viewbox; + Gtk::Label* labview; Gtk::Label* labgam; Gtk::HBox* gambox; @@ -60,6 +62,7 @@ protected: MyComboBoxText* retinexcolorspace; MyComboBoxText* gammaretinex; MyComboBoxText* mapMethod; + MyComboBoxText* viewMethod; Gtk::CheckButton* medianmap; double nextmin; double nextmax; @@ -78,7 +81,7 @@ protected: DiagonalCurveEditor* cdshapeH; DiagonalCurveEditor* mapshape; CurveEditorGroup* transmissionCurveEditorG; - sigc::connection retinexMethodConn, neutralconn, mapMethodConn; + sigc::connection retinexMethodConn, neutralconn, mapMethodConn, viewMethodConn; sigc::connection retinexColorSpaceConn; sigc::connection gammaretinexConn; FlatCurveEditor* transmissionShape; @@ -108,6 +111,7 @@ public: void curveChanged (CurveEditor* ce); void retinexMethodChanged(); void mapMethodChanged(); + void viewMethodChanged(); void retinexColorSpaceChanged(); void gammaretinexChanged(); void ColorSpaceUpdateUI(); From 38f9c05c3c2ec2a75981daaa5a85f187a1dbe4d1 Mon Sep 17 00:00:00 2001 From: Desmis Date: Sun, 15 Nov 2015 16:57:02 +0100 Subject: [PATCH 8/9] Enhancement to 'Process Transmission' and High radius unsharp mask --- rtdata/languages/default | 12 ++++--- rtengine/ipretinex.cc | 49 ++++++++++++++++++++-------- rtgui/retinex.cc | 69 +++++++++++++++++++++++++--------------- 3 files changed, 86 insertions(+), 44 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 4ec24b42c..2cb777a8c 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1653,7 +1653,7 @@ TP_RETINEX_CURVEEDITOR_CD_TOOLTIP;Luminance according to luminance L=f(L)\nCorre TP_RETINEX_CURVEEDITOR_LH;Strength=f(H) TP_RETINEX_CURVEEDITOR_LH_TOOLTIP;Strength according to hue Strength=f(H)\nThis curve also acts on chroma when using the "Highlight" retinex method. TP_RETINEX_FREEGAMMA;Free gamma -TP_RETINEX_GAIN;Contrast +TP_RETINEX_GAIN;Gain TP_RETINEX_GAIN_TOOLTIP;Acts on the restored image.\n\nThis is very different from the others settings. Used for black or white pixels, and to help balance the histogram. TP_RETINEX_GAMMA;Gamma TP_RETINEX_GAMMA_FREE;Free @@ -1706,13 +1706,15 @@ TP_RETINEX_TLABEL_TOOLTIP;Transmission map result.\nMin and Max are used by Vari TP_RETINEX_TRANSMISSION;Transmission map TP_RETINEX_TRANSMISSION_TOOLTIP;Transmission according to transmission.\nAbscissa: transmission from negative values (min), mean, and positives values (max).\nOrdinate: amplification or reduction. TP_RETINEX_UNIFORM;Uniform -TP_RETINEX_VARIANCE;Variance +TP_RETINEX_VARIANCE;Contrast TP_RETINEX_VARIANCE_TOOLTIP;Low variance increase local contrast and saturation, but can lead to artifacts. -TP_RETINEX_VIEW;Preview +TP_RETINEX_VIEW;Process (Preview) TP_RETINEX_VIEW_NONE;Standard TP_RETINEX_VIEW_MASK;Mask -TP_RETINEX_VIEW_TRAN;Transmission -TP_RETINEX_VIEW_METHOD_TOOLTIP;Standard - normal display\nMask - display mask\nTransmission - displays the file transmission-map , before any action on contrast and brightness\nAttention, this does not correspond to reality, but a shift to make it visible +TP_RETINEX_VIEW_UNSHARP;Unsharp mask +TP_RETINEX_VIEW_TRAN;Transmission (auto) +TP_RETINEX_VIEW_TRAN2;Transmission (fixed) +TP_RETINEX_VIEW_METHOD_TOOLTIP;Standard - normal display\nMask - display mask\nUnsharp mask - display image with high radius unsharp mask\nTransmission (auto - fixed) - displays the file transmission-map , before any action on contrast and brightness\nAttention, this does not correspond to reality, but a shift (or auto) to make it visible TP_RGBCURVES_BLUE;B TP_RGBCURVES_CHANNEL;Channel TP_RGBCURVES_GREEN;G diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 839d8646e..b24cc9bb3 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -241,6 +241,12 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } else { elogt = hl; } + int H_L = height; + int W_L = width; + + float *tran[H_L] ALIGNED16; + float *tranBuffer; + int viewmet=0; elogt = 2.71828f;//disabled baselog FlatCurve* shcurve = NULL;//curve L=f(H) @@ -386,8 +392,8 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e retinex_scales( RetinexScales, scal, moderetinex, nei/grad, high ); - int H_L = height; - int W_L = width; + // int H_L = height; + // int W_L = width; float *src[H_L] ALIGNED16; float *srcBuffer = new float[H_L * W_L]; @@ -408,9 +414,11 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e double shradius = (double) deh.radius; // printf("shrad=%f\n",shradius); - int viewmet=0; + // int viewmet=0; if(deh.viewMethod=="mask") viewmet=1; if(deh.viewMethod=="tran") viewmet=2; + if(deh.viewMethod=="tran2") viewmet=3; + if(deh.viewMethod=="unsharp") viewmet=4; #ifdef _OPENMP #pragma omp parallel for @@ -429,13 +437,13 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e out[i] = &outBuffer[i * W_L]; } - float *tran[H_L] ALIGNED16; - float *tranBuffer = new float[H_L * W_L]; + if(viewmet==3 || viewmet==2) { + tranBuffer = new float[H_L * W_L]; - for (int i = 0; i < H_L; i++) { - tran[i] = &tranBuffer[i * W_L]; + for (int i = 0; i < H_L; i++) { + tran[i] = &tranBuffer[i * W_L]; + } } - const float logBetaGain = xlogf(16384.f); float pond = logBetaGain / (float) scal; @@ -611,7 +619,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } luminance[i][j] *= (-1.f + 4.f * dehatransmissionCurve[absciss]); //new transmission - tran[i][j]=luminance[i][j]; + if(viewmet==3 || viewmet==2) tran[i][j]=luminance[i][j]; } } @@ -683,7 +691,11 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e float cdfactor = gain2 * 32768.f / delta; maxCD = -9999999.f; minCD = 9999999.f; - + // coeff for auto "transmission" with 2 sigma #95% datas + float aza=16300.f/(2.f*stddv); + float azb=-aza*(mean-2.f*stddv); + float bza=16300.f/(2.f*stddv); + float bzb=16300.f-bza*(mean); @@ -730,7 +742,13 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e if(exLuminance[i][j] > 65535.f*hig && higplus) str *= hig; if(viewmet==0) luminance[i][j]=clipretinex( cd, 0.f, 32768.f ) * str + (1.f - str) * originalLuminance[i][j]; if(viewmet==1) luminance[i][j] = out[i][j]; - if(viewmet==2) luminance[i][j] = 1000.f+ tran[i][j]*700.f;//arbitrary values to help display log values which are between -20 to + 30 - usage values -4 + 5 + if(viewmet==4) luminance[i][j] = (1.f + str) * originalLuminance[i][j] - str* out[i][j];//unsharp + if(viewmet==2) { + if(tran[i][j]<= mean) luminance[i][j] = azb + aza*tran[i][j];//auto values + else luminance[i][j] = bzb + bza*tran[i][j]; + } + if(viewmet==3) luminance[i][j] = 1000.f + tran[i][j]*700.f;//arbitrary values to help display log values which are between -20 to + 30 - usage values -4 + 5 + } #ifdef _OPENMP @@ -744,19 +762,22 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } delete [] outBuffer; outBuffer = NULL; - delete [] tranBuffer; - tranBuffer = NULL; - // printf("cdmin=%f cdmax=%f\n",minCD, maxCD); Tmean = mean; Tsigma = stddv; Tmin = mintr; Tmax = maxtr; + if (shcurve && it==1) { delete shcurve; } } + if(viewmet==3 || viewmet==2) { + delete [] tranBuffer; + tranBuffer = NULL; + } + } } diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index 5e4a9f636..eca9f7a91 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -202,7 +202,9 @@ Retinex::Retinex () : FoldableToolPanel(this, "retinex", M("TP_RETINEX_LABEL"), viewMethod = Gtk::manage (new MyComboBoxText ()); viewMethod->append_text (M("TP_RETINEX_VIEW_NONE")); viewMethod->append_text (M("TP_RETINEX_VIEW_MASK")); + viewMethod->append_text (M("TP_RETINEX_VIEW_UNSHARP")); viewMethod->append_text (M("TP_RETINEX_VIEW_TRAN")); + viewMethod->append_text (M("TP_RETINEX_VIEW_TRAN2")); viewMethod->set_active(0); viewMethodConn = viewMethod->signal_changed().connect ( sigc::mem_fun(*this, &Retinex::viewMethodChanged) ); viewMethod->set_tooltip_markup (M("TP_RETINEX_VIEW_METHOD_TOOLTIP")); @@ -739,8 +741,12 @@ void Retinex::read (const ProcParams* pp, const ParamsEdited* pedited) viewMethod->set_active (0); } else if (pp->retinex.viewMethod == "mask") { viewMethod->set_active (1); - } else if (pp->retinex.viewMethod == "tran") { + } else if (pp->retinex.viewMethod == "unsharp") { viewMethod->set_active (2); + } else if (pp->retinex.viewMethod == "tran") { + viewMethod->set_active (3); + } else if (pp->retinex.viewMethod == "tran2") { + viewMethod->set_active (4); } if (pp->retinex.retinexcolorspace == "Lab") { @@ -891,7 +897,11 @@ void Retinex::write (ProcParams* pp, ParamsEdited* pedited) } else if (viewMethod->get_active_row_number() == 1) { pp->retinex.viewMethod = "mask"; } else if (viewMethod->get_active_row_number() == 2) { + pp->retinex.viewMethod = "unsharp"; + } else if (viewMethod->get_active_row_number() == 3) { pp->retinex.viewMethod = "tran"; + } else if (viewMethod->get_active_row_number() == 4) { + pp->retinex.viewMethod = "tran2"; } if (retinexcolorspace->get_active_row_number() == 0) { @@ -966,31 +976,40 @@ void Retinex::mapMethodChanged() void Retinex::viewMethodChanged() { - /* - if(mapMethod->get_active_row_number() == 1 || mapMethod->get_active_row_number() == 2) { - curveEditormap->show(); - highlights->show(); - h_tonalwidth->show(); - shadows->show(); - s_tonalwidth->show(); - radius->show(); - } else if(mapMethod->get_active_row_number() == 3 || mapMethod->get_active_row_number() == 4) { - curveEditormap->show(); - highlights->show(); - h_tonalwidth->show(); - shadows->show(); - s_tonalwidth->show(); - radius->hide(); - } else { - curveEditormap->hide(); - highlights->hide(); - h_tonalwidth->hide(); - shadows->hide(); - s_tonalwidth->hide(); - radius->hide(); + if(viewMethod->get_active_row_number() == 1 || viewMethod->get_active_row_number() == 2) { + vart->hide(); + gain->hide(); + offs->hide(); + limd->hide(); + transmissionCurveEditorG->hide(); + medianmap->hide(); + iter->hide(); + scal->hide(); + grad->hide(); + grads->hide(); + curveEditorGH->hide(); + } + else if(viewMethod->get_active_row_number() == 3 || viewMethod->get_active_row_number() == 4) { + gain->hide(); + offs->hide(); + vart->hide(); + curveEditorGH->hide(); + } + else { + vart->show(); + neigh->show(); + gain->show(); + offs->show(); + limd->show(); + transmissionCurveEditorG->show(); + medianmap->show(); + iter->show(); + scal->show(); + grad->show(); + grads->show(); + curveEditorGH->show(); + } - } - */ if (listener) { listener->panelChanged (EvviewMethod, viewMethod->get_active_text ()); } From 4e229fe9284b62346b8cf096cd7037d03260b73d Mon Sep 17 00:00:00 2001 From: Desmis Date: Sun, 3 Jan 2016 15:48:22 +0100 Subject: [PATCH 9/9] update retinexadd with master 4d6833c --- .../images/Dark/actions/intent-perceptual.png | Bin 0 -> 898 bytes .../images/Dark/actions/intent-relative.png | Bin 0 -> 1140 bytes .../images/Dark/actions/intent-saturation.png | Bin 0 -> 1012 bytes rtdata/images/Dark/actions/softProof.png | Bin 0 -> 842 bytes .../images/Light/actions/intent-absolute.png | Bin 0 -> 700 bytes .../Light/actions/intent-perceptual.png | Bin 0 -> 847 bytes .../images/Light/actions/intent-relative.png | Bin 0 -> 1101 bytes .../Light/actions/intent-saturation.png | Bin 0 -> 1007 bytes rtdata/images/Light/actions/softProof.png | Bin 0 -> 915 bytes rtengine/dcrop.cc | 38 +- rtengine/iccstore.cc | 387 ++--- rtengine/iccstore.h | 143 +- rtengine/improccoordinator.cc | 26 +- rtengine/improccoordinator.h | 7 + rtengine/improcfun.cc | 84 +- rtengine/improcfun.h | 7 +- rtengine/iplab2rgb.cc | 12 +- rtengine/procevents.h | 3 +- rtengine/procparams.cc | 39 + rtengine/procparams.h | 10 + rtengine/refreshmap.cc | 21 +- rtengine/refreshmap.h | 56 +- rtengine/rtengine.h | 7 +- rtengine/settings.h | 4 +- rtengine/simpleprocess.cc | 8 +- rtgui/colortoning.cc | 1 + rtgui/diagonalcurveeditorsubgroup.cc | 1 + rtgui/editorpanel.cc | 185 +++ rtgui/editorpanel.h | 3 + rtgui/filecatalog.cc | 1 + rtgui/flatcurveeditorsubgroup.cc | 1 + rtgui/guiutils.h | 23 + rtgui/history.cc | 5 +- rtgui/icmpanel.cc | 55 +- rtgui/icmpanel.h | 2 + rtgui/options.cc | 10 +- rtgui/options.h | 1 + rtgui/paramsedited.cc | 6 + rtgui/paramsedited.h | 1 + rtgui/popupbutton.cc | 34 +- rtgui/popupbutton.h | 12 +- rtgui/popupcommon.cc | 127 +- rtgui/popupcommon.h | 48 +- rtgui/popuptogglebutton.h | 2 +- rtgui/preferences.cc | 109 +- rtgui/preferences.h | 7 +- rtgui/retinex.cc | 1 + rtgui/wavelet.cc | 1 + .../scalable/intent-absolute.file | 1 + .../source_icons/scalable/intent-absolute.svg | 1376 ++++++++++++++++ .../scalable/intent-perceptual.file | 1 + .../scalable/intent-perceptual.svg | 1362 ++++++++++++++++ .../scalable/intent-relative.file | 1 + .../source_icons/scalable/intent-relative.svg | 1361 ++++++++++++++++ .../scalable/intent-saturation.file | 1 + .../scalable/intent-saturation.svg | 1362 ++++++++++++++++ tools/source_icons/scalable/softProof.file | 1 + tools/source_icons/scalable/softProof.svg | 1389 +++++++++++++++++ 58 files changed, 7810 insertions(+), 533 deletions(-) create mode 100644 rtdata/images/Dark/actions/intent-perceptual.png create mode 100644 rtdata/images/Dark/actions/intent-relative.png create mode 100644 rtdata/images/Dark/actions/intent-saturation.png create mode 100644 rtdata/images/Dark/actions/softProof.png create mode 100644 rtdata/images/Light/actions/intent-absolute.png create mode 100644 rtdata/images/Light/actions/intent-perceptual.png create mode 100644 rtdata/images/Light/actions/intent-relative.png create mode 100644 rtdata/images/Light/actions/intent-saturation.png create mode 100644 rtdata/images/Light/actions/softProof.png create mode 100644 tools/source_icons/scalable/intent-absolute.file create mode 100644 tools/source_icons/scalable/intent-absolute.svg create mode 100644 tools/source_icons/scalable/intent-perceptual.file create mode 100644 tools/source_icons/scalable/intent-perceptual.svg create mode 100644 tools/source_icons/scalable/intent-relative.file create mode 100644 tools/source_icons/scalable/intent-relative.svg create mode 100644 tools/source_icons/scalable/intent-saturation.file create mode 100644 tools/source_icons/scalable/intent-saturation.svg create mode 100644 tools/source_icons/scalable/softProof.file create mode 100644 tools/source_icons/scalable/softProof.svg diff --git a/rtdata/images/Dark/actions/intent-perceptual.png b/rtdata/images/Dark/actions/intent-perceptual.png new file mode 100644 index 0000000000000000000000000000000000000000..821a714aef1582240a179b26dce741f5500e2c14 GIT binary patch literal 898 zcmV-|1AY97P)P000&U1^@s6HNQ8u00004b3#c}2nYxW zdpNm?f9idCTX==Z#d^RfzMR+H4z!8YTJ8%KMcczQmHifSCJ{k|7ncrEiEm@Yin!0 z)0?W*s##xO|0qe4+s2q%Kp-Njs$CKJYqU;PAC=4HuLA&U?H8Of-g{3R$21xZr>f6X z^|6R_j4_X`wH@GKYisMr-QC@#AP8=zY5Fd3*%*_Xs1X4K0M5B@CQo9m&3o@(QPsSN zEE{940`IA6QB_IP6u|B6?L8Bbr_Q;qwf4D)9I9$Eagu0!UFT(ge?K3`@rtTm6Ok1W zx$3>YVvNbFYG%ro!*aQNXD*Rh?Ck9178Vwkz4znm%49PA&CShU1Au0;`K9;%or@4N z#*Cj;^(Wx&$df@31Q!w^lcZ@nfH^&x#jwkklO)NG-o0>L=VfHPwf35GZUwjwyanWe zz|0OuTl1CD`5KqMkP=UmTPJ8t1L zP5+sb)5GY!9~&qlDexQcP((VwlO#zxi;Ig-OQlj;tJN+Q3WX27_p88lRULPii2MTl zFm)J5v2t>9(wi25)oRrgi^Y$d&E{=Y{R9Y%F=t}M7}J9}jjz}1Zw5i|DZ_wN)qyeQ zd*Hsc_TkKcoW;@6QFwfOd?xBeWH*<~eOoLR`~OvA>Q75mbHPx# literal 0 HcmV?d00001 diff --git a/rtdata/images/Dark/actions/intent-relative.png b/rtdata/images/Dark/actions/intent-relative.png new file mode 100644 index 0000000000000000000000000000000000000000..d586b47b20aac6c2d20688c32399828f2dd32663 GIT binary patch literal 1140 zcmV-)1dIELP)P000&U1^@s6HNQ8u00004b3#c}2nYxW zdsKd}23iNAw=f3Z8;T9;Bx`GHOBXL*T*vS& z%g;teMpiQbu(Go9MMpU1zjH2iafR6NikbGulk0jkUv)FrI2XKGWxFm6ObhLwH!8x}tgwPA1&&&=;qNLc& zrU2ZKbgN#k&yI|YtZo(8rvQ$U%!Ls0BzFMFwDctaegkj=z+_KP&-C%*$K&bg>0Gs1 zJxua|_rBZA3IN^&kOz<<`CwpR;HxH)2k;m`!#TGeLRbMX@4a6zv$@^7ci%gE_H3h4 zsbu0f?yJ>mA4gGix>~Is0+5jeGXsDn08atbCB-3xr<=yrL=;6kz4r$J95JGT1 z)AD@)Q<7#R-ED7gubn%0ZtZ1peM0g;Iu%(-J0%rJ=32hf6Oz|SPCDnV6^q3`0iaT; z?DF342ha_m0AQD-teLfW@2f*YL*F&0>m5n^Nd`$PBp*wO*`jq7mLLw zt@TVwGz_3Sgs>xBq7E}Fgb)gnwxvWt(t?>OUDkwT1;F zX;iZ$A4sZ&5RQ;6rGh^-8jWw8OS%yhk!e@;ZQT1_lOZ zUWNPxk#f2Gu5)frdQWtQ5Dt+%oSrn1G?B?0oN$S6lZp2^rh8lp2JN&@_0000P000&U1^@s6HNQ8u00004b3#c}2nYxW zd|a!fwv=vavFO4O#o)}F z8OLtiq|lu|TcIurb|DVB>`HLy%7rHWfI=4Y@?H#56QS6JS`v+z*qSjU(oX(UC-2?s zBJ+l+G;P$rP!<{QSCDpDHI+)u_V@QM3=a>dUDrM4y6#Z`PmydFkq(mgwK$mq@S_6&#+diF zwzh5x-WanHMbWiVsq|O!RxX!KZ*T9@VHm!aN~KN!*drn!xga9fN&ZH%-tyVsn@+OX zZ1r||_`aVp#uNa&2w*?SbyfYwT00TP@lWmT?YgqEasa>q0QV<-aU5T79oH>UsZ_eH zwI@~81CS;;17NVbyZh^Ewb~O!Q6I@yR##UaY8h{{-&%Vaz(ofDMn*=SQ`LP9izK<% z7;{8Kj*wK6-vRg{m&^SShT-w~`T4g=9w(_H@(X|=0Q0K4psF_#5!ZD$n@&g;Nj8HA z5Q)ei06wkP>tB^hrMWN+9}I%vO;zn{jBChooJwbB=W?x9dtO!hj4=mEx(SJhOas{7 z_)I4A&fMIbO^TC~lN;r7SsL~k1VI77%K%cU`lX0`oX_Vs#>U28SXx>-1)z)MGJsi< zYYC64R)ITgyzl$_jWMqSctTZYj4|)!a=DpGrP5`LIYaV zQ8N=`40Ib80et9r-cS>yjv&~7Iz~6?BWUsLC_&0Zx~~q6p>2+&KC-W_1y~GR%BvgBE7b@b`ro# zB-5(;k>`1z?G)}EMSS0X)fn?=%X>;y4>ivC6v+>Ax!m->B~OqX$S#rxTi!PST!`a% itXM35|6j@PDgFjNYM$N22^3-g0000?>2K~y-6t&}@x6j2n0|NENjxJ|NY1o2UcT8NF1B9cIoogkzM zGANcl5CRqv?1b3btJv5HAx)4JdE9k}6rzR*0R<5Zh$6vamppf}cX#fwa8{Bvo6UkB z3|tQ9|L!?cTp(p;X6E$5!omssCuIGgl)7!LbpRd$fHCHz5TcuiKJ@qZue2-XsicpH z&H^|WMNtm`5Ye?HN&2005Ayl^=+x9yM>}E`MUhOBlx^qS ziy#O-9cp50t#-~mA)-8hc_Mncxw+ZZAO(O7=X}%{(|0Iw5Cq$~TyB{$w(6W)&E;~- zQcBmXAHa2E%t%Y|e#L6F+Du$0$mjD{iHNl&&StY4ttKL(L1WB~X7YW-v$L~X02}}a zA%s#&Dy1Z2Y)?O9?6NWD=H%q0IFxvNeB1%p0>HG^p58@z!EX7bY&Ls$X=zEd6sP9d*noPVQp>gUKB+~T8bHC-vB^LDYVwwOHoQGDW%6b-?KguovBu< zV{>zJnO5TO^|MmS^E^)rA(Rk8N-0I7IL(|ALX1sMPakb6&SWxQIp;~OR!gLmDwT2} z1Ovc0|0kLNSOV~JczC!h|1qX?cXw|XW4`R{>|9Ke#4*N*h{!od0LVG#(kWvAZ)>%h z85$ZY)$>ioY3O~WQaN8Pm$y96Q`TA=$MJR?#}y*_$vH0+i^X?g7~00{f#OoBwAk6% zd1ZZlT?iqhwYK7%`^*@7JuoovkugTivImO8FiZ-C!i2T<4(EIkKz?v=@KW$#bWVQW6<|~8OL$0*#KQ#U5}h|$BAf}h@J;Qu)SM6!We7$ zYV8LRW$vr- UDcf2aR{#J207*qoM6N<$g6`yc_W%F@ literal 0 HcmV?d00001 diff --git a/rtdata/images/Light/actions/intent-absolute.png b/rtdata/images/Light/actions/intent-absolute.png new file mode 100644 index 0000000000000000000000000000000000000000..fb59191816dd7244af926633e6883b7dbe8a6f56 GIT binary patch literal 700 zcmV;t0z>_YP)P000&U1^@s6HNQ8u00004b3#c}2nYxW zd1 zozDQ0BpETYVwPpU%H{I++1c3+J(T5;`;sQ|HA(vBocm~IAHp!4UszaJIx-}VTs|4c@m6=6rl+TaTCFy^wY7E4%x(ZB zV9|U3xY=yJ%;5)z>}pqAQp?PiffY$#opYZhm4TbUprpE_N6lulc3?=QQkjx;#(N(D z&ddgYq5LX!#ji>lFtZ?ko_EeYt=H?X_o~eH%VKnN^mL(681vpIz*R{}7X$!FOTZiN z{d?zJJx$ZqZm0o_jg8%vlpLsZvk2(lD@Ibs%v!*FqtSQ}=8J1)cBE~(E0G=8TCY6! zhXTZLd)@ayaA8vr3d6h+l2iUz&+k#jBt`Xvps-NF&zM4nko z(wwBXz+9T9iwCJF%P000&U1^@s6HNQ8u00004b3#c}2nYxW zdMKS^)NiPAMUNk2gySuwTjTIhe6(EUnxtx-GM)HZfADGz_ zGdoyZT->SEYJZeUrOWwzzDjb#%&th9%k=0>o1_S!0H7!-HnVGzmXTQwNh!%^0NTR| zUIFNa5C&P2Mx*f{0)SSl)tn&1Ybck?MR#A0qUaMz%OtN!Dw8Y%_y7Rh{o;F)j{!WG zN%(14T3VVb6bf;YBp25eLg+UdjXxs*SX*2BLDJg05~XPh^1uIE>^n0jKXhhY+M}- z247_Z62R{y@1LHYKAIYk(=aLO&Ft5sqod#2?RNi7J;pv-xm<28Ns+f06r2mqoe`YtQ{xpUq9Imvrwwq38+9|G`+o!&$;DtrjxRgxr~32({F Z_!oStca#5KBYpq?002ovPDHLkV1im@c^Loz literal 0 HcmV?d00001 diff --git a/rtdata/images/Light/actions/intent-relative.png b/rtdata/images/Light/actions/intent-relative.png new file mode 100644 index 0000000000000000000000000000000000000000..f952f4ab7ec55317c9d8073f91eca01ad4fd409f GIT binary patch literal 1101 zcmV-T1hV^yP)P000&U1^@s6HNQ8u00004b3#c}2nYxW zd&OxS35 znz(Xh;@{xbg@1uNH~t0clC37jjT;kJ4YhP^`#P;7tpl`%0;Of%d-J~If|;f?X+iL8 z@44Uk^1JtbmjDn&(Yt0=2!f!KWm(tVcbd&+g8xbEg?uGx>d@K_fGv{uNUpm3N|t3y ztyZh^S|PPs?M4s;l|0Xj0E#3}0XPTXJb+;UrvN}w*UXjy%t`uvdU`s(b?a9CN+H9; z!zYp?363%i4GmSzY>ebpcfZyT1&{z(CE0ZM`)2ka2!ic2O*;bv1KIZW_LFwIy>}e0 zHx|i-IF7#z0l?jV0xse2Hbs+WY{-J>H_$ab zTeGvX+04vLxW2wVo+QbqwOZ|Zk|dW&hVJ`kz60PffDVAv-5(!^3;i<)!*GP;Sf1zO zB(L_m1j)PZzF=lC$+g|x-TNCG8_$l!Rj=1SBY8?284cOR5wB+r^z1wbW9k`q0zOWGnS0F=}v`3uP(R#sNl zj%&1!>jOzsBw=Px-F*+hrn|2KSno~PF*Ey663pyZGyAUpNMEM?QGfI1&Gg{kP^;BS zW;QNq2EhAx{?E*t*|$qeOYy4|e<37_qW2`7Cwa=<-vV$Mz$nSEhvhd(KQ^1q#(yc^ zSN~Oi0${2)gSuw+x4Zu==?{0GTU%Ru{5r*72qF1Rp-^xDX`|8D2B0@7dRYGg*Dn1M TGhyDO00000NkvXXu0mjf9P000&U1^@s6HNQ8u00004b3#c}2nYxW zdJR{A{B*V7siIkyf>LxHI~WH!XwU1XL9fT zTx8xbN}9&Me!F+hJ>Pe}bKZRqxC;;fC=?2>kUajMlZ#ZtFudUPAGS!2{SP8rK;Ox~ zK_-()rqk(Euh&cdHK(=i1VOOr9h5Aa%}y$%aw0M-A~Pgs089fIF~&eCwO83y0Izv{ zf`mk*feMdjOEn=byyxlA*O0YwZyL1!GJB z07-tYwf?MHt**?@&Xz^w4U*-4E(EZol)7%MZ2-6xi)gJo11CzUXX3^8J26VB->kLE zBJyReR{OPBEZ*z;{;MSC0klXiDWxu^QmLrbYCUC)nO903BbkUrNCp6QZ+yGmezV){ z>NweKHroJV-%>0V7o2l1IOh&2r9O|M=%YrX(e{1+*(i!mi%42TA^;m&>)&G@=iDZ6 zhZ|ommydQjotFVT44^I|?*>6oFO^E^Uaxl!z)1jg=iJiz`ucYOxEGHAK&ezp0~m>e zJ3Bjv0X$A}0f1IYEtbpWPnVaMt?&C;lCP7zM?^jj!*FrP^_~y_@O}TC;ma706u@O` z?FaRG{pbF1So$YXc_;GDY%;L1?EnMfppN~Ll=ZYH14pCNgg!1SricC*Wk0q1IQ_i{PNsei)Kde@( zpWrsjy`xAzpMOzA9vq4v0+7Y-%TUo;zrVJ&7W`fE81bJmP4d`4S)@(!l2YocAP9c= dr{s4Pe*h?1j$Np+MCSki002ovPDHLkV1oH}#n%7; literal 0 HcmV?d00001 diff --git a/rtdata/images/Light/actions/softProof.png b/rtdata/images/Light/actions/softProof.png new file mode 100644 index 0000000000000000000000000000000000000000..3e5eb2f182e5f0b9768fb82948230d0d03ec04f0 GIT binary patch literal 915 zcmV;E18n?>P)K~y-6t(4DeV^tK#zvupXuMM@5yigj^mU`0^?G!^95XGSz z5p*F8b~Y|mbmd|ef(sXJ{SREY7m5qlI)l3L2Z$}wPOYyn44q=r_O;FLT>S)eD1mDa4*o&!otGr;^N}dcuZ2=g>&w`IF22FPXJ(UZtfYa^@~Z8{2GSg z?xTVw09b2R0K7p&!Q|xR{>jP7gCGdrXXa%hdN~M!nTd&sKTl6jnhAd zCYf0g(X-iX_B&?21%NufDIvs5Q&Uq9kB*K?BY_)@#+dK>y8xVXE)+t1)o!IF|4MMJR*R!3`YW5w&M>(;l@Q`Tej<9s zTKmrG>Z%;IVh5l~L^L)wW>Tq?mrA9)@$qp_Ypr^XM09;)W8;J6nmCA>+v$Osv;QIiewU(aedA{!(t+g@6Xk&~KLdZVUcK|#n_hJA+5IoP!97WMqH@3C4#p!gq4r&+Rd_I2@z|CQ;86;*-5s_kMCxqC|<#Hbl{GA>}`F#E}W_}XD_r+rI p%eA$&ipf.lab2monitorRgb (labnCrop, cropImg); - //parent->ipf.lab2monitorRgb (laboCrop, cropImg); - - //cropImg = baseCrop->to8(); - /* - // int xref,yref; - xref=000;yref=000; - if (colortest && cropw>115 && croph>115) - for(int j=1;j<5;j++){ - xref+=j*30;yref+=j*30; - int rlin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))]/255.0) * 255.0); - int glin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+1]/255.0) * 255.0); - int blin = (CurveFactory::igamma2((float)cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+2]/255.0) * 255.0); - - printf("after lab2rgb RGB lab2 Xr%i Yr%i Skip=%d R=%d G=%d B=%d \n",xref,yref,skip, - rlin,glin,blin); - //cropImg->data[3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))], - //cropImg->data[(3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+1)], - //cropImg->data[(3*((int)(xref/skip)*cropImg->width+(int)(yref/skip))+2)]); - //printf("after lab2rgb Lab lab2 Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip, labnCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327,labnCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327,labnCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327); - printf("after lab2rgb Lab Xr%i Yr%i Skip=%d l=%f a=%f b=%f \n",xref,yref,skip, - labnCrop->L[(int)(xref/skip)][(int)(yref/skip)]/327, - labnCrop->a[(int)(xref/skip)][(int)(yref/skip)]/327, - labnCrop->b[(int)(xref/skip)][(int)(yref/skip)]/327)q; - } - */ - /* - if (colortest && cropImg->height>115 && cropImg->width>115) {//for testing - xref=000;yref=000; - printf("dcrop final R= %d G= %d B= %d \n", - cropImg->data[3*xref/(skip)*(cropImg->width+1)], - cropImg->data[3*xref/(skip)*(cropImg->width+1)+1], - cropImg->data[3*xref/(skip)*(cropImg->width+1)+2]); - } - */ if (cropImageListener) { // this in output space held in parallel to allow analysis like shadow/highlight Glib::ustring outProfile = params.icm.output; @@ -1030,13 +996,13 @@ void Crop::update (int todo) Image8 *cropImgtrue; if(settings->HistogramWorking) { - cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, workProfile, false); + cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, workProfile, RI_RELATIVE, false); // HOMBRE: was RELATIVE by default in lab2rgb, is it safe to assume we have to use it again ? } else { if (params.icm.output == "" || params.icm.output == ColorManagementParams::NoICMString) { outProfile = "sRGB"; } - cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, outProfile, false); + cropImgtrue = parent->ipf.lab2rgb (labnCrop, 0, 0, cropw, croph, outProfile, params.icm.outputIntent, false); } int finalW = rqcropw; diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index bad4e8dfa..b77da03dd 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -29,9 +29,90 @@ #include -namespace rtengine +namespace { +void loadProfiles (const Glib::ustring& dirName, + std::map* profiles, + std::map* profileContents, + std::map* profileNames, + bool nameUpper, bool onlyRgb) +{ + if (dirName.empty ()) + return; + + try { + + Glib::Dir dir (dirName); + + for (Glib::DirIterator entry = dir.begin (); entry != dir.end (); ++entry) { + + const Glib::ustring fileName = *entry; + + if (fileName.size () < 4) + continue; + + const Glib::ustring extension = fileName.substr (fileName.size () - 4).casefold (); + + if (extension.compare(".icc") == 0 && extension.compare(".icm") == 0) + continue; + + const Glib::ustring filePath = Glib::build_filename (dirName, fileName); + + if (!safe_file_test (filePath, Glib::FILE_TEST_IS_REGULAR)) + continue; + + Glib::ustring name = fileName.substr (0, fileName.size() - 4); + + if (nameUpper) + name = name.uppercase (); + + if (profiles) { + const rtengine::ProfileContent content (filePath); + const cmsHPROFILE profile = content.toProfile (); + + if (profile && (!onlyRgb || cmsGetColorSpace (profile) == cmsSigRgbData)) { + profiles->insert (std::make_pair (name, profile)); + + if (profileContents) + profileContents->insert (std::make_pair (name, content)); + } + } + + if (profileNames) + profileNames->insert (std::make_pair (name, filePath)); + } + } + catch (Glib::Exception&) {} +} + +inline void getSupportedIntent (cmsHPROFILE profile, cmsUInt32Number intent, cmsUInt32Number direction, std::uint8_t& result) +{ + if (cmsIsIntentSupported (profile, intent, direction)) + result |= 1 << intent; +} + +inline std::uint8_t getSupportedIntents (cmsHPROFILE profile, cmsUInt32Number direction) +{ + if (!profile) + return 0; + + std::uint8_t result = 0; + + getSupportedIntent (profile, INTENT_PERCEPTUAL, direction, result); + getSupportedIntent (profile, INTENT_RELATIVE_COLORIMETRIC, direction, result); + getSupportedIntent (profile, INTENT_SATURATION, direction, result); + getSupportedIntent (profile, INTENT_ABSOLUTE_COLORIMETRIC, direction, result); + + return result; +} + +inline cmsHPROFILE createXYZProfile () +{ + double mat[3][3] = { {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0} }; + return rtengine::ICCStore::createFromMatrix (mat, false, "XYZ"); +} + const double (*wprofiles[])[3] = {xyz_sRGB, xyz_adobe, xyz_prophoto, xyz_widegamut, xyz_bruce, xyz_beta, xyz_best}; const double (*iwprofiles[])[3] = {sRGB_xyz, adobe_xyz, prophoto_xyz, widegamut_xyz, bruce_xyz, beta_xyz, best_xyz}; const char* wpnames[] = {"sRGB", "Adobe RGB", "ProPhoto", "WideGamut", "BruceRGB", "Beta RGB", "BestRGB"}; @@ -43,8 +124,12 @@ const char* wpgamma[] = {"default", "BT709_g2.2_s4.5", "sRGB_g2.4_s12.92", "line // high g=1.3 s=3.35 for high dynamic images //low g=2.6 s=6.9 for low contrast images +} -std::vector getGamma () //return gamma +namespace rtengine +{ + +std::vector getGamma () { std::vector res; @@ -56,7 +141,6 @@ std::vector getGamma () //return gamma return res; } - std::vector getWorkingProfiles () { @@ -69,32 +153,38 @@ std::vector getWorkingProfiles () return res; } -std::vector ICCStore::getOutputProfiles () +std::vector ICCStore::getProfiles () const { MyMutex::MyLock lock(mutex_); std::vector res; - for (std::map::iterator i = fileProfiles.begin(); i != fileProfiles.end(); i++) { - Glib::ustring name(i->first); - std::string::size_type i2 = name.find_last_of('/'); - - if( i2 == std::string::npos ) { - i2 = name.find_last_of('\\'); - } - - if( i2 == std::string::npos ) { - res.push_back ( name ); // list only profiles inside selected profiles directory - } - } + for (ProfileMap::const_iterator profile = fileProfiles.begin (); profile != fileProfiles.end (); ++profile) + res.push_back (profile->first); return res; } +std::vector ICCStore::getProfilesFromDir (const Glib::ustring& dirName) const +{ -cmsHPROFILE -ICCStore::makeStdGammaProfile(cmsHPROFILE iprof) + MyMutex::MyLock lock(mutex_); + + std::vector res; + + ProfileMap profiles; + + loadProfiles (profilesDir, &profiles, NULL, NULL, false, true); + loadProfiles (dirName, &profiles, NULL, NULL, false, true); + + for (ProfileMap::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) + res.push_back (profile->first); + + return res; +} + +cmsHPROFILE ICCStore::makeStdGammaProfile (cmsHPROFILE iprof) { // forgive me for the messy code, quick hack to change gamma of an ICC profile to the RT standard gamma if (!iprof) { @@ -189,14 +279,15 @@ ICCStore::makeStdGammaProfile(cmsHPROFILE iprof) return oprof; } -ICCStore* -ICCStore::getInstance(void) +ICCStore* ICCStore::getInstance () { static ICCStore instance_; return &instance_; } -ICCStore::ICCStore () +ICCStore::ICCStore () : + xyz (createXYZProfile ()), + srgb (cmsCreate_sRGBProfile ()) { //cmsErrorAction (LCMS_ERROR_SHOW); @@ -208,234 +299,172 @@ ICCStore::ICCStore () wMatrices[wpnames[i]] = wprofiles[i]; iwMatrices[wpnames[i]] = iwprofiles[i]; } - - double mat[3][3] = { {1.0, 0, 0}, {0, 1.0, 0}, {0, 0, 1.0}}; - xyz = createFromMatrix (mat, false, "XYZ"); - srgb = cmsCreate_sRGBProfile (); } -int ICCStore::numOfWProfiles () +TMatrix ICCStore::workingSpaceMatrix (const Glib::ustring& name) const { - return sizeof(wpnames) / sizeof(wpnames[0]); -} - -TMatrix ICCStore::workingSpaceMatrix (Glib::ustring name) -{ - - std::map::iterator r = wMatrices.find (name); + const MatrixMap::const_iterator r = wMatrices.find (name); if (r != wMatrices.end()) { return r->second; } else { - return wMatrices["sRGB"]; + return wMatrices.find ("sRGB")->second; } } -TMatrix ICCStore::workingSpaceInverseMatrix (Glib::ustring name) +TMatrix ICCStore::workingSpaceInverseMatrix (const Glib::ustring& name) const { - std::map::iterator r = iwMatrices.find (name); + const MatrixMap::const_iterator r = iwMatrices.find (name); if (r != iwMatrices.end()) { return r->second; } else { - return iwMatrices["sRGB"]; + return iwMatrices.find ("sRGB")->second; } } -cmsHPROFILE ICCStore::workingSpace (Glib::ustring name) +cmsHPROFILE ICCStore::workingSpace (const Glib::ustring& name) const { - std::map::iterator r = wProfiles.find (name); + const ProfileMap::const_iterator r = wProfiles.find (name); if (r != wProfiles.end()) { return r->second; } else { - return wProfiles["sRGB"]; + return wProfiles.find ("sRGB")->second; } } -cmsHPROFILE ICCStore::workingSpaceGamma (Glib::ustring name) +cmsHPROFILE ICCStore::workingSpaceGamma (const Glib::ustring& name) const { - std::map::iterator r = wProfilesGamma.find (name); + const ProfileMap::const_iterator r = wProfilesGamma.find (name); if (r != wProfilesGamma.end()) { return r->second; } else { - return wProfilesGamma["sRGB"]; + return wProfilesGamma.find ("sRGB")->second; } } -cmsHPROFILE ICCStore::getProfile (Glib::ustring name) +cmsHPROFILE ICCStore::getProfile (const Glib::ustring& name) const { MyMutex::MyLock lock(mutex_); - std::map::iterator r = fileProfiles.find (name); + const ProfileMap::const_iterator r = fileProfiles.find (name); - if (r != fileProfiles.end()) { + if (r != fileProfiles.end ()) return r->second; - } else { - if (!name.compare (0, 5, "file:") && safe_file_test (name.substr(5), Glib::FILE_TEST_EXISTS) && !safe_file_test (name.substr(5), Glib::FILE_TEST_IS_DIR)) { - ProfileContent pc (name.substr(5)); - if (pc.data) { - cmsHPROFILE profile = pc.toProfile (); + if (name.compare (0, 5, "file:") == 0) { + const ProfileContent content (name.substr (5)); + const cmsHPROFILE profile = content.toProfile (); - if (profile) { - fileProfiles[name] = profile; - fileProfileContents[name] = pc; - return profile; - } - } + if (profile) { + const_cast(fileProfiles).insert(std::make_pair(name, profile)); + const_cast(fileProfileContents).insert(std::make_pair(name, content)); + + return profile; } } return NULL; } -cmsHPROFILE ICCStore::getStdProfile (Glib::ustring name) +cmsHPROFILE ICCStore::getStdProfile (const Glib::ustring& name) const { + const Glib::ustring nameUpper = name.uppercase (); + MyMutex::MyLock lock(mutex_); - std::map::iterator r = fileStdProfiles.find (name.uppercase()); + const ProfileMap::const_iterator r = fileStdProfiles.find (nameUpper); - if (r == fileStdProfiles.end()) { - // profile is not yet in store - std::map::iterator f = fileStdProfilesFileNames.find (name.uppercase()); - - if(f != fileStdProfilesFileNames.end()) { - // but there exists one => load it - ProfileContent pc (f->second); - - if (pc.data) { - cmsHPROFILE profile = pc.toProfile (); - - if (profile) { - fileStdProfiles[name.uppercase()] = profile; - } - - // profile is not valid or it is now stored => remove entry from fileStdProfilesFileNames - fileStdProfilesFileNames.erase(f); - return profile; - } else { - // profile not valid => remove entry from fileStdProfilesFileNames - fileStdProfilesFileNames.erase(f); - return NULL; - } - } else { - // profile does not exist - return NULL; - } - } else { - // return profile from store + // return profile from store + if (r != fileStdProfiles.end ()) return r->second; - } + + // profile is not yet in store + const NameMap::const_iterator f = fileStdProfilesFileNames.find (nameUpper); + + // profile does not exist + if (f == fileStdProfilesFileNames.end ()) + return NULL; + + // but there exists one => load it + const ProfileContent content (f->second); + const cmsHPROFILE profile = content.toProfile (); + + if (profile) + const_cast(fileStdProfiles).insert (std::make_pair (f->first, profile)); + + // profile is not valid or it is now stored => remove entry from fileStdProfilesFileNames + const_cast(fileStdProfilesFileNames).erase (f); + return profile; } -ProfileContent ICCStore::getContent (Glib::ustring name) +ProfileContent ICCStore::getContent (const Glib::ustring& name) const { MyMutex::MyLock lock(mutex_); - return fileProfileContents[name]; + const ContentMap::const_iterator r = fileProfileContents.find (name); + + return r != fileProfileContents.end () ? r->second : ProfileContent(); +} + +std::uint8_t ICCStore::getInputIntents (cmsHPROFILE profile) const +{ + + MyMutex::MyLock lock (mutex_); + + return getSupportedIntents (profile, LCMS_USED_AS_INPUT); +} + +std::uint8_t ICCStore::getOutputIntents (cmsHPROFILE profile) const +{ + + MyMutex::MyLock lock (mutex_); + + return getSupportedIntents (profile, LCMS_USED_AS_OUTPUT); +} + +std::uint8_t ICCStore::getProofIntents (cmsHPROFILE profile) const +{ + + MyMutex::MyLock lock (mutex_); + + return getSupportedIntents (profile, LCMS_USED_AS_PROOF); } // Reads all profiles from the given profiles dir -void ICCStore::init (Glib::ustring usrICCDir, Glib::ustring rtICCDir) +void ICCStore::init (const Glib::ustring& usrICCDir, const Glib::ustring& rtICCDir) { MyMutex::MyLock lock(mutex_); - // + // RawTherapee's profiles take precedence if a user's profile of the same name exists + profilesDir = Glib::build_filename (rtICCDir, "output"); fileProfiles.clear(); fileProfileContents.clear(); - // RawTherapee's profiles take precedence if a user's profile of the same name exists - loadICCs(Glib::build_filename(rtICCDir, "output"), false, fileProfiles, &fileProfileContents, true, true); - loadICCs(usrICCDir, false, fileProfiles, &fileProfileContents, true, true); + loadProfiles (profilesDir, &fileProfiles, &fileProfileContents, NULL, false, true); + loadProfiles (usrICCDir, &fileProfiles, &fileProfileContents, NULL, false, true); // Input profiles // Load these to different areas, since the short name (e.g. "NIKON D700" may overlap between system/user and RT dir) + stdProfilesDir = Glib::build_filename (rtICCDir, "input"); fileStdProfiles.clear(); fileStdProfilesFileNames.clear(); - loadICCs(Glib::build_filename(rtICCDir, "input"), true, fileStdProfiles, NULL); -} - -void ICCStore::loadICCs(Glib::ustring rootDirName, bool nameUpper, std::map& resultProfiles, std::map *resultProfileContents, bool prefetch, bool onlyRgb) -{ - if (rootDirName != "") { - std::deque qDirs; - - qDirs.push_front(rootDirName); - - while (!qDirs.empty()) { - // process directory - Glib::ustring dirname = qDirs.back(); - qDirs.pop_back(); - - Glib::Dir* dir = NULL; - - try { - if (!safe_file_test (dirname, Glib::FILE_TEST_IS_DIR)) { - return; - } - - dir = new Glib::Dir (dirname); - } catch (Glib::Exception& fe) { - return; - } - - dirname = dirname + "/"; - - for (Glib::DirIterator i = dir->begin(); i != dir->end(); ++i) { - Glib::ustring fname = dirname + *i; - Glib::ustring sname = *i; - - // ignore directories - if (!safe_file_test (fname, Glib::FILE_TEST_IS_DIR)) { - size_t lastdot = sname.find_last_of ('.'); - - if (lastdot != Glib::ustring::npos && lastdot <= sname.size() - 4 && (!sname.casefold().compare (lastdot, 4, ".icm") || !sname.casefold().compare (lastdot, 4, ".icc"))) { - Glib::ustring name = nameUpper ? sname.substr(0, lastdot).uppercase() : sname.substr(0, lastdot); - - if(!prefetch) { - fileStdProfilesFileNames[name] = fname; - } else { - ProfileContent pc (fname); - - if (pc.data) { - cmsHPROFILE profile = pc.toProfile (); - - if (profile && (!onlyRgb || cmsGetColorSpace(profile) == cmsSigRgbData)) { - resultProfiles[name] = profile; - - if(resultProfileContents) { - (*resultProfileContents)[name] = pc; - } - } - } - } - } - } - - // Removed recursive scanning, see issue #1730. - // To revert to the recursive method, just uncomment the next line. - - //else qDirs.push_front(fname); // for later scanning - } - - delete dir; - } - } + loadProfiles (stdProfilesDir, NULL, NULL, &fileStdProfilesFileNames, true, false); } // Determine the first monitor default profile of operating system, if selected -void ICCStore::findDefaultMonitorProfile() +void ICCStore::findDefaultMonitorProfile () { - defaultMonitorProfile = ""; + defaultMonitorProfile.clear (); #ifdef WIN32 // Get current main monitor. Could be fine tuned to get the current windows monitor (multi monitor setup), @@ -449,6 +478,11 @@ void ICCStore::findDefaultMonitorProfile() if (GetICMProfileA(hDC, &profileLength, profileName)) { defaultMonitorProfile = Glib::ustring(profileName); + defaultMonitorProfile = Glib::path_get_basename(defaultMonitorProfile); + size_t pos = defaultMonitorProfile.rfind("."); + if (pos != Glib::ustring::npos) { + defaultMonitorProfile = defaultMonitorProfile.substr(0, pos); + } } // might fail if e.g. the monitor has no profile @@ -466,7 +500,7 @@ void ICCStore::findDefaultMonitorProfile() } } -ProfileContent::ProfileContent (Glib::ustring fileName) : data(NULL), length(0) +ProfileContent::ProfileContent (const Glib::ustring& fileName) : data(NULL), length(0) { FILE* f = safe_g_fopen (fileName, "rb"); @@ -518,9 +552,7 @@ ProfileContent& ProfileContent::operator= (const ProfileContent& other) length = other.length; - if (data) { - delete [] data; - } + delete [] data; if (other.data) { data = new char[length + 1]; @@ -532,15 +564,7 @@ ProfileContent& ProfileContent::operator= (const ProfileContent& other) return *this; } -ProfileContent::~ProfileContent () -{ - - if (data) { - delete [] data; - } -} - -cmsHPROFILE ProfileContent::toProfile () +cmsHPROFILE ProfileContent::toProfile () const { if (data) { @@ -550,7 +574,7 @@ cmsHPROFILE ProfileContent::toProfile () } } -cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, Glib::ustring name) +cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, const Glib::ustring& name) { static const unsigned phead[] = { @@ -644,4 +668,5 @@ cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, G delete [] oprof; return p; } + } diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h index acb31e4cf..8b6e6465c 100644 --- a/rtengine/iccstore.h +++ b/rtengine/iccstore.h @@ -37,74 +37,135 @@ public: char* data; int length; - ProfileContent (): data(NULL), length(0) {} - ProfileContent (Glib::ustring fileName); - ProfileContent (const ProfileContent& other); - ProfileContent (cmsHPROFILE hProfile); + ProfileContent (); ~ProfileContent (); + + ProfileContent (const ProfileContent& other); ProfileContent& operator= (const rtengine::ProfileContent& other); - cmsHPROFILE toProfile (); + + ProfileContent (const Glib::ustring& fileName); + ProfileContent (cmsHPROFILE hProfile); + cmsHPROFILE toProfile () const; }; class ICCStore { + typedef std::map ProfileMap; + typedef std::map MatrixMap; + typedef std::map ContentMap; + typedef std::map NameMap; - std::map wProfiles; - std::map wProfilesGamma; - std::map wMatrices; - std::map iwMatrices; + ProfileMap wProfiles; + ProfileMap wProfilesGamma; + MatrixMap wMatrices; + MatrixMap iwMatrices; // these contain profiles from user/system directory (supplied on init) - std::map fileProfiles; - std::map fileProfileContents; + Glib::ustring profilesDir; + ProfileMap fileProfiles; + ContentMap fileProfileContents; // these contain standard profiles from RT. keys are all in uppercase - std::map fileStdProfilesFileNames; - std::map fileStdProfiles; + Glib::ustring stdProfilesDir; + NameMap fileStdProfilesFileNames; + ProfileMap fileStdProfiles; - cmsHPROFILE xyz; - cmsHPROFILE srgb; + Glib::ustring defaultMonitorProfile; - MyMutex mutex_; + const cmsHPROFILE xyz; + const cmsHPROFILE srgb; + + mutable MyMutex mutex_; ICCStore (); - void loadICCs(Glib::ustring rootDirName, bool nameUpper, std::map& resultProfiles, std::map *resultProfileContents, bool prefetch = false, bool onlyRgb = false); public: - static ICCStore* getInstance(void); - static cmsHPROFILE makeStdGammaProfile(cmsHPROFILE iprof); + static ICCStore* getInstance (); - Glib::ustring defaultMonitorProfile; // Main monitors standard profile name, from OS - void findDefaultMonitorProfile(); + void init (const Glib::ustring& usrICCDir, const Glib::ustring& stdICCDir); - int numOfWProfiles (); - cmsHPROFILE createFromMatrix (const double matrix[3][3], bool gamma = false, Glib::ustring name = ""); - cmsHPROFILE workingSpace (Glib::ustring name); - cmsHPROFILE workingSpaceGamma (Glib::ustring name); - TMatrix workingSpaceMatrix (Glib::ustring name); - TMatrix workingSpaceInverseMatrix (Glib::ustring name); + static cmsHPROFILE makeStdGammaProfile (cmsHPROFILE iprof); + static cmsHPROFILE createFromMatrix (const double matrix[3][3], bool gamma = false, const Glib::ustring& name = Glib::ustring()); - cmsHPROFILE getProfile (Glib::ustring name); - cmsHPROFILE getStdProfile(Glib::ustring name); + // Main monitors standard profile name, from OS + void findDefaultMonitorProfile (); + cmsHPROFILE getDefaultMonitorProfile () const; + Glib::ustring getDefaultMonitorProfileName () const; - void init (Glib::ustring usrICCDir, Glib::ustring stdICCDir); - ProfileContent getContent (Glib::ustring name); + cmsHPROFILE workingSpace (const Glib::ustring& name) const; + cmsHPROFILE workingSpaceGamma (const Glib::ustring& name) const; + TMatrix workingSpaceMatrix (const Glib::ustring& name) const; + TMatrix workingSpaceInverseMatrix (const Glib::ustring& name) const; - cmsHPROFILE getXYZProfile () - { - return xyz; - } - cmsHPROFILE getsRGBProfile () - { - return srgb; - } - std::vector getOutputProfiles (); + cmsHPROFILE getProfile (const Glib::ustring& name) const; + cmsHPROFILE getStdProfile (const Glib::ustring& name) const; + ProfileContent getContent (const Glib::ustring& name) const; + + cmsHPROFILE getXYZProfile () const; + cmsHPROFILE getsRGBProfile () const; + + std::vector getProfiles () const; + std::vector getProfilesFromDir (const Glib::ustring& dirName) const; + + std::uint8_t getInputIntents (cmsHPROFILE profile) const; + std::uint8_t getOutputIntents (cmsHPROFILE profile) const; + std::uint8_t getProofIntents (cmsHPROFILE profile) const; + + std::uint8_t getInputIntents (const Glib::ustring& name) const; + std::uint8_t getOutputIntents (const Glib::ustring& name) const; + std::uint8_t getProofIntents (const Glib::ustring& name) const; }; #define iccStore ICCStore::getInstance() -//extern const char* wpnames[]; +inline ProfileContent::ProfileContent () : + data(NULL), + length(0) +{ } + +inline ProfileContent::~ProfileContent () +{ + delete [] data; +} + +inline cmsHPROFILE ICCStore::getDefaultMonitorProfile () const +{ + return getProfile (defaultMonitorProfile); +} + +inline Glib::ustring ICCStore::getDefaultMonitorProfileName () const +{ + return defaultMonitorProfile; +} + +inline std::uint8_t ICCStore::getInputIntents (const Glib::ustring &name) const +{ + return getInputIntents (getProfile (name)); +} + +inline std::uint8_t ICCStore::getOutputIntents (const Glib::ustring &name) const +{ + return getOutputIntents (getProfile (name)); +} + +inline std::uint8_t ICCStore::getProofIntents (const Glib::ustring &name) const +{ + return getProofIntents (getProfile (name)); +} + +inline cmsHPROFILE ICCStore::getXYZProfile () const +{ + return xyz; +} + +inline cmsHPROFILE ICCStore::getsRGBProfile () const +{ + return srgb; +} + +} + #endif diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index dc135c4d5..1745d8210 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -31,7 +31,7 @@ extern const Settings* settings; ImProcCoordinator::ImProcCoordinator () : orig_prev(NULL), oprevi(NULL), oprevl(NULL), nprevl(NULL), previmg(NULL), workimg(NULL), - ncie(NULL), imgsrc(NULL), shmap(NULL), lastAwbEqual(0.), ipf(¶ms, true), scale(10), + ncie(NULL), imgsrc(NULL), shmap(NULL), lastAwbEqual(0.), ipf(¶ms, true), monitorIntent(RI_RELATIVE), scale(10), highDetailPreprocessComputed(false), highDetailRawComputed(false), allocated(false), bwAutoR(-9000.f), bwAutoG(-9000.f), bwAutoB(-9000.f), CAMMean(0.), @@ -782,6 +782,10 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } } } + // Update the monitor color transform if necessary + if (todo & M_MONITOR) { + ipf.updateColorProfiles(params.icm, monitorProfile, monitorIntent); + } // process crop, if needed for (size_t i = 0; i < crops.size(); i++) @@ -796,7 +800,8 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) progress ("Conversion to RGB...", 100 * readyphase / numofphases); - if (todo != CROP && todo != MINUPDATE) { +// if (todo != CROP && todo != MINUPDATE) { + if ((todo != CROP && todo != MINUPDATE) || (todo & M_MONITOR)) { MyMutex::MyLock prevImgLock(previmg->getMutex()); try { @@ -806,13 +811,13 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) if(settings->HistogramWorking) { Glib::ustring workProfile = params.icm.working; - workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, workProfile, true); + workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, workProfile, RI_RELATIVE, true); // HOMBRE: was RELATIVE by default in lab2rgb, is it safe to assume we have to use it again ? } else { - if (params.icm.output == "" || params.icm.output == ColorManagementParams::NoICMString) { + if (params.icm.output.empty() || params.icm.output == ColorManagementParams::NoICMString) { outProfile = "sRGB"; } - workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, outProfile, false); + workimg = ipf.lab2rgb (nprevl, 0, 0, pW, pH, outProfile, params.icm.outputIntent, false); } } catch(char * str) { progress ("Error converting file...", 0); @@ -1128,6 +1133,17 @@ void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int & y = (fullh - h) / 2; } +void ImProcCoordinator::setMonitorProfile (const Glib::ustring& profile, RenderingIntent intent) +{ + monitorProfile = profile; + monitorIntent = intent; +} + +void ImProcCoordinator::getMonitorProfile (Glib::ustring& profile, RenderingIntent& intent) const +{ + profile = monitorProfile; + intent = monitorIntent; +} void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname, bool apply_wb) { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index ef981fe6a..4d442482e 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -72,6 +72,10 @@ protected: ImProcFunctions ipf; + Glib::ustring monitorProfile; + + RenderingIntent monitorIntent; + int scale; bool highDetailPreprocessComputed; bool highDetailRawComputed; @@ -249,6 +253,9 @@ public: void getSpotWB (int x, int y, int rectSize, double& temp, double& green); void getAutoCrop (double ratio, int &x, int &y, int &w, int &h); + void setMonitorProfile (const Glib::ustring& profile, RenderingIntent intent); + void getMonitorProfile (Glib::ustring& profile, RenderingIntent& intent) const; + bool updateTryLock () { return updaterThreadStart.trylock(); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index f21748a3b..c3c5af03f 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -140,57 +140,10 @@ void ImProcFunctions::firstAnalysisThread (Imagefloat* original, Glib::ustring w } } } -/* -void ImProcFunctions::CAT02 (Imagefloat* baseImg, const ProcParams* params) + +void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent) { - const double toxyz[3][3] = {{0.7976749, 0.1351917, 0.0313534}, - {0.2880402, 0.7118741, 0.0000857}, - {0.0000000, 0.0000000, 0.8252100}}; - - const double xyzto[3][3] = {{1.3459433, -0.2556075, -0.0511118}, - {-0.5445989, 1.5081673, 0.0205351}, - {0.0000000, 0.0000000, 1.2118128}}; - int fw = baseImg->width; - int fh = baseImg->height; - - double CAM02BB00,CAM02BB01,CAM02BB02,CAM02BB10,CAM02BB11,CAM02BB12,CAM02BB20,CAM02BB21,CAM02BB22; - double Xxx,Yyy,Zzz; - // Xxx=1.09844; - // Yyy=1.0; - // Zzz=0.355961; - //params.wb.temperature, params.wb.green, params.wb.method - double Xxyz, Zxyz; -// ColorTemp::temp2mulxyz (params->wb.temperature, params->wb.green, params->wb.method, Xxyz, Zxyz); - ColorTemp::temp2mulxyz (5000.0, 1.0, "Camera", Xxyz, Zxyz); - - ColorTemp::cieCAT02(Xxx, Yyy, Zzz, CAM02BB00,CAM02BB01,CAM02BB02,CAM02BB10,CAM02BB11,CAM02BB12,CAM02BB20,CAM02BB21,CAM02BB22); - printf("00=%f 01=%f 11=%f 20=%f 22=%f\n", CAM02BB00,CAM02BB01,CAM02BB11,CAM02BB20,CAM02BB22); - - - for (int i=0; ir(i,j); - float g = baseImg->g(i,j); - float b = baseImg->b(i,j); - - float x = toxyz[0][0] * r + toxyz[0][1] * g + toxyz[0][2] * b; - float y = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; - float z = toxyz[2][0] * r + toxyz[2][1] * g + toxyz[2][2] * b; - float Xcam=CAM02BB00* x +CAM02BB01* y + CAM02BB02* z ; - float Ycam=CAM02BB10* x +CAM02BB11* y + CAM02BB12* z ; - float Zcam=CAM02BB20* x +CAM02BB21* y + CAM02BB22* z ; - baseImg->r(i,j) = xyzto[0][0] * Xcam + xyzto[0][1] * Ycam + xyzto[0][2] * Zcam; - baseImg->g(i,j) = xyzto[1][0] * Xcam + xyzto[1][1] * Ycam + xyzto[1][2] * Zcam; - baseImg->b(i,j) = xyzto[2][0] * Xcam + xyzto[2][1] * Ycam + xyzto[2][2] * Zcam; - } - } -} -*/ -void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* params, LUTu & histogram) -{ - // set up monitor transform - Glib::ustring wprofile = params->icm.working; if (monitorTransform != NULL) { cmsDeleteTransform (monitorTransform); @@ -209,43 +162,38 @@ void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* par lab2outputTransform = NULL; #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB - Glib::ustring monitorProfile = settings->monitorProfile; -#if defined(WIN32) - if (settings->autoMonitorProfile) { - monitorProfile = iccStore->defaultMonitorProfile; - } - -#endif - - cmsHPROFILE monitor = iccStore->getProfile ("file:" + monitorProfile); + cmsHPROFILE monitor = iccStore->getProfile (monitorProfile); if (monitor) { - lcmsMutex->lock (); + MyMutex::MyLock lcmsLock (*lcmsMutex); cmsHPROFILE iprof = cmsCreateLab4Profile(NULL); - monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, + monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, monitorIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is for thread safety, NOOPTIMIZE for precision Glib::ustring outputProfile; - if (params->icm.output != "" && params->icm.output != ColorManagementParams::NoICMString) { - outputProfile = params->icm.output; + if (!icm.output.empty() && icm.output != ColorManagementParams::NoICMString) { + outputProfile = icm.output; cmsHPROFILE jprof = iccStore->getProfile(outputProfile); if (jprof) { - lab2outputTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, jprof, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); - - if (monitor) { - output2monitorTransform = cmsCreateTransform (jprof, TYPE_RGB_FLT, monitor, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); - } + lab2outputTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, jprof, TYPE_RGB_FLT, icm.outputIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); + output2monitorTransform = cmsCreateTransform (jprof, TYPE_RGB_FLT, monitor, TYPE_RGB_8, monitorIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); } } cmsCloseProfile(iprof); - lcmsMutex->unlock (); } #endif +} + +void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* params, LUTu & histogram) +{ + + Glib::ustring wprofile = params->icm.working; + // calculate histogram of the y channel needed for contrast curve calculation in exposure adjustments int T = 1; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index cfabbba64..ec81f26eb 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -233,6 +233,7 @@ public: bool needsPCVignetting (); void firstAnalysis (Imagefloat* working, const ProcParams* params, LUTu & vhist16); + void updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent); void rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *editBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf); @@ -379,9 +380,9 @@ public: void Badpixelscam(CieImage * src, CieImage * dst, double radius, int thresh, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom, int hotbad); void BadpixelsLab(LabImage * src, LabImage * dst, double radius, int thresh, int mode, float b_l, float t_l, float t_r, float b_r, float skinprot, float chrom); - Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, bool standard_gamma); - Image16* lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6, bool bw);// for gamma output - Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, bool bw);//without gamma ==>default + Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool standard_gamma); + Image16* lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6, bool bw);// for gamma output + Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool bw);//without gamma ==>default // CieImage *ciec; bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LCPMapper *pLCPMap = NULL); diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index cc01b783f..c36e185d0 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -134,7 +134,7 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) } } -Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, bool standard_gamma) +Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool standard_gamma) { //gamutmap(lab); @@ -167,7 +167,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, lcmsMutex->lock (); cmsHPROFILE hLab = cmsCreateLab4Profile(NULL); - cmsHTRANSFORM hTransform = cmsCreateTransform (hLab, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, + cmsHTRANSFORM hTransform = cmsCreateTransform (hLab, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, intent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is important for thread safety cmsCloseProfile(hLab); lcmsMutex->unlock (); @@ -259,7 +259,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, return image; } // for default (not gamma) -Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, bool bw) +Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, bool bw) { //gamutmap(lab); @@ -322,7 +322,7 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int cmsHPROFILE iprof = iccStore->getXYZProfile (); lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_16, intent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); lcmsMutex->unlock (); image->ExecCMSTransform(hTransform); @@ -363,7 +363,7 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int // for gamma options (BT709...sRGB linear...) -Image16* ImProcFunctions::lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6, bool bw) +Image16* ImProcFunctions::lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile, RenderingIntent intent, Glib::ustring profi, Glib::ustring gam, bool freegamma, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6, bool bw) { //gamutmap(lab); @@ -593,7 +593,7 @@ Image16* ImProcFunctions::lab2rgb16b (LabImage* lab, int cx, int cy, int cw, int cmsHPROFILE iprof = iccStore->getXYZProfile (); lcmsMutex->lock (); - cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprofdef, TYPE_RGB_16, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); + cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprofdef, TYPE_RGB_16, intent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE); lcmsMutex->unlock (); image->ExecCMSTransform(hTransform); diff --git a/rtengine/procevents.h b/rtengine/procevents.h index d02018d78..3c7e1ceb5 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -465,7 +465,8 @@ enum ProcEvent { EvmapMethod = 434, EvRetinexmapcurve = 435, EvviewMethod = 436, - + EvOIntent = 437, + EvMonitorTransform = 438, NUMOFEVENTS }; } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 7a674e8c3..90eafe375 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -907,6 +907,7 @@ void ColorManagementParams::setDefaults() dcpIlluminant = 0; working = "ProPhoto"; output = "RT_sRGB"; + outputIntent = RI_RELATIVE; gamma = "default"; gampos = 2.22; slpos = 4.5; @@ -2606,6 +2607,27 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_string ("Color Management", "OutputProfile", icm.output); } + if (!pedited || pedited->icm.outputIntent) { + Glib::ustring intent; + switch (icm.outputIntent) { + default: + case RI_PERCEPTUAL: + intent = "Perceptual"; + break; + case RI_RELATIVE: + intent = "Relative"; + break; + case RI_SATURATION: + intent = "Saturation"; + break; + case RI_ABSOLUTE: + intent = "Absolute"; + break; + } + + keyFile.set_string ("Color Management", "OutputProfileIntent", intent); + } + if (!pedited || pedited->icm.gamma) { keyFile.set_string ("Color Management", "Gammafree", icm.gamma); } @@ -5821,6 +5843,23 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } + if (keyFile.has_key ("Color Management", "OutputProfileIntent")) { + Glib::ustring intent = keyFile.get_string ("Color Management", "OutputProfileIntent"); + if (intent == "Perceptual") { + icm.outputIntent = RI_PERCEPTUAL; + } else if (intent == "Relative") { + icm.outputIntent = RI_RELATIVE; + } else if (intent == "Saturation") { + icm.outputIntent = RI_SATURATION; + } else if (intent == "Absolute") { + icm.outputIntent = RI_ABSOLUTE; + } + + if (pedited) { + pedited->icm.outputIntent = true; + } + } + if (keyFile.has_key ("Color Management", "Gammafree")) { icm.gamma = keyFile.get_string ("Color Management", "Gammafree"); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 0aa31a9bd..47b8f1cf1 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "LUT.h" #include "coord.h" @@ -41,6 +42,14 @@ class WavOpacityCurveW; class WavOpacityCurveWL; class RetinextransmissionCurve; +enum RenderingIntent { + RI_PERCEPTUAL = INTENT_PERCEPTUAL, + RI_RELATIVE = INTENT_RELATIVE_COLORIMETRIC, + RI_SATURATION = INTENT_SATURATION, + RI_ABSOLUTE = INTENT_ABSOLUTE_COLORIMETRIC, + RI__COUNT +}; + namespace procparams { @@ -953,6 +962,7 @@ public: int dcpIlluminant; Glib::ustring working; Glib::ustring output; + RenderingIntent outputIntent; static const Glib::ustring NoICMString; Glib::ustring gamma; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 915ed615d..291dc0550 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -64,9 +64,9 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DARKFRAME, // EvLCPUseVign, TRANSFORM, // EvLCPUseCA, M_VOID, // EvFixedExp - WHITEBALANCE, // EvWBMethod, - WHITEBALANCE, // EvWBTemp, - WHITEBALANCE, // EvWBGreen, + ALLNORAW, // EvWBMethod, + ALLNORAW, // EvWBTemp, + ALLNORAW, // EvWBGreen, RGBCURVE, // EvToneCurveMode1, RGBCURVE, // EvToneCurve2, RGBCURVE, // EvToneCurveMode2, @@ -75,7 +75,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { 0, // EvCDNEnabled:obsolete, ALL, // EvBlendCMSMatrix, RGBCURVE, // EvDCPToneCurve, - INPUTPROFILE, // EvDCPIlluminant, + ALLNORAW, // EvDCPIlluminant, RETINEX, // EvSHEnabled, RGBCURVE, // EvSHHighlights, RGBCURVE, // EvSHShadows, @@ -97,7 +97,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { ALLNORAW, // EvHRMethod, ALLNORAW, // EvWProfile, OUTPUTPROFILE, // EvOProfile, - INPUTPROFILE, // EvIProfile, + ALLNORAW, // EvIProfile, TRANSFORM, // EvVignettingAmount, RGBCURVE, // EvChMixer, RESIZE, // EvResizeScale, @@ -234,8 +234,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { LUMINANCECURVE, // EvCATbadpix LUMINANCECURVE, // EvCATAutoadap DEFRINGE, // EvPFCurve - WHITEBALANCE, // EvWBequal - WHITEBALANCE, // EvWBequalbo + ALLNORAW, // EvWBequal + ALLNORAW, // EvWBequalbo TRANSFORM, // EvGradientDegree TRANSFORM, // EvGradientEnabled TRANSFORM, // EvPCVignetteStrength @@ -421,7 +421,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DIRPYREQUALIZER, // EvWavNeutral RGBCURVE, // EvDCPApplyLookTable, RGBCURVE, // EvDCPApplyBaselineExposureOffset, - INPUTPROFILE, // EvDCPApplyHueSatMap + ALLNORAW, // EvDCPApplyHueSatMap DIRPYREQUALIZER, // EvWavenacont DIRPYREQUALIZER, // EvWavenachrom DIRPYREQUALIZER, // EvWavenaedge @@ -464,7 +464,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, //EvLradius RETINEX, //EvmapMethod DEMOSAIC, //EvRetinexmapcurve - DEMOSAIC //EvviewMethod - + DEMOSAIC, //EvviewMethod + ALLNORAW, // EvOIntent + MONITORTRANSFORM // EvMonitorTransform }; diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index e24d0c422..23e179f9f 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -20,15 +20,16 @@ #define __REFRESHMAP__ // Use M_VOID if you wish to update the proc params without updating the preview at all ! -#define M_VOID (1<<15) +#define M_VOID (1<<16) // Use M_MINUPDATE if you wish to update the preview without modifying the image (think about it like a "refreshPreview") // Must NOT be used with other event (i.e. will be used for MINUPDATE only) -#define M_MINUPDATE (1<<14) +#define M_MINUPDATE (1<<15) // Force high quality -#define M_HIGHQUAL (1<<13) +#define M_HIGHQUAL (1<<14) // Elementary functions that can be done to // the preview image when an event occurs +#define M_MONITOR (1<<13) #define M_RETINEX (1<<12) #define M_CROP (1<<11) #define M_PREPROC (1<<10) @@ -45,31 +46,30 @@ // Bitfield of functions to do to the preview image when an event occurs // Use those or create new ones for your new events -#define FIRST (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL -#define ALL (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL -#define TRANSFORM (M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define AUTOEXP (M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define RGBCURVE (M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define LUMINANCECURVE (M_LUMACURVE|M_LUMINANCE) -#define SHARPENING M_LUMINANCE -#define IMPULSEDENOISE M_LUMINANCE -#define DEFRINGE M_LUMINANCE -#define WHITEBALANCE (M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define DEMOSAIC (M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define DARKFRAME (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define FLATFIELD (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define DIRPYRDENOISE (M_COLOR|M_LUMINANCE) -#define CROP M_CROP -#define RESIZE M_VOID -#define EXIF M_VOID -#define IPTC M_VOID -#define DIRPYREQUALIZER (M_COLOR|M_LUMINANCE) -#define OUTPUTPROFILE (M_INIT|M_COLOR|M_LUMINANCE) -#define INPUTPROFILE WHITEBALANCE -#define GAMMA (M_COLOR|M_LUMINANCE) -#define MINUPDATE M_MINUPDATE -#define ALLNORAW (M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define RETINEX (M_RETINEX|ALLNORAW) +#define FIRST (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL +#define ALL (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL +#define DARKFRAME (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define FLATFIELD (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define DEMOSAIC (M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define ALLNORAW (M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define TRANSFORM (M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define AUTOEXP (M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define RGBCURVE (M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define LUMINANCECURVE (M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define SHARPENING (M_LUMINANCE|M_COLOR) +#define IMPULSEDENOISE (M_LUMINANCE|M_COLOR) +#define DEFRINGE (M_LUMINANCE|M_COLOR) +#define DIRPYRDENOISE (M_LUMINANCE|M_COLOR) +#define DIRPYREQUALIZER (M_LUMINANCE|M_COLOR) +#define GAMMA (M_LUMINANCE|M_COLOR) +#define CROP M_CROP +#define RESIZE M_VOID +#define EXIF M_VOID +#define IPTC M_VOID +#define MINUPDATE M_MINUPDATE +#define RETINEX (M_RETINEX|ALLNORAW) +#define MONITORTRANSFORM M_MONITOR +#define OUTPUTPROFILE (ALLNORAW|MONITORTRANSFORM) extern int refreshmap[]; #endif diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 195911a3a..42e06406e 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -35,7 +35,7 @@ #include "LUT.h" /** * @file - * This file contains the main functionality of the raw therapee engine. + * This file contains the main functionality of the RawTherapee engine. * */ @@ -413,9 +413,12 @@ public: virtual void setAutoBWListener (AutoBWListener* l) = 0; virtual void setAutoColorTonListener (AutoColorTonListener* l) = 0; virtual void setAutoChromaListener (AutoChromaListener* l) = 0; - virtual void setRetinexListener (RetinexListener* l) = 0; + virtual void setRetinexListener (RetinexListener* l) = 0; virtual void setWaveletListener (WaveletListener* l) = 0; + virtual void setMonitorProfile (const Glib::ustring& monitorProfile, RenderingIntent intent) = 0; + virtual void getMonitorProfile (Glib::ustring& monitorProfile, RenderingIntent& intent) const = 0; + virtual ~StagedImageProcessor () {} /** Returns a staged, cached image processing manager supporting partial updates diff --git a/rtengine/settings.h b/rtengine/settings.h index 373103d07..e3e220af9 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -19,6 +19,8 @@ #ifndef _RTSETTINGS_ #define _RTSETTINGS_ +#include "procparams.h" + namespace rtengine { @@ -27,7 +29,6 @@ class Settings { public: Glib::ustring iccDirectory; ///< The directory containing the possible output icc profiles - int colorimetricIntent; ///< Colorimetric intent used at color space conversions int viewingdevice; // white of output device (D50...D65..) int viewingdevicegrey; // level of grey output device int viewinggreySc; // level of grey Scene @@ -38,6 +39,7 @@ public: int leveldnautsimpl; // STD or EXPERT Glib::ustring monitorProfile; ///< ICC profile of the monitor (full path recommended) + RenderingIntent monitorIntent; ///< Colorimetric intent used with the above profile bool autoMonitorProfile; ///< Try to auto-determine the correct monitor color profile bool autocielab; bool rgbcurveslumamode_gamut;// controls gamut enforcement for RGB curves in lumamode diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 8bb0e839c..14d827bab 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -1157,7 +1157,8 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p cmsFloat64Number Parameters[7]; double ga0, ga1, ga2, ga3, ga4, ga5, ga6; // if(params.blackwhite.enabled) params.toneCurve.hrenabled=false; - readyImg = ipf.lab2rgb16b (labView, cx, cy, cw, ch, params.icm.output, params.icm.working, params.icm.gamma, params.icm.freegamma, params.icm.gampos, params.icm.slpos, ga0, ga1, ga2, ga3, ga4, ga5, ga6, params.blackwhite.enabled ); + readyImg = ipf.lab2rgb16b (labView, cx, cy, cw, ch, params.icm.output, params.icm.outputIntent, params.icm.working, params.icm.gamma, params.icm.freegamma, params.icm.gampos, params.icm.slpos, ga0, ga1, ga2, ga3, ga4, ga5, ga6, params.blackwhite.enabled ); + customGamma = true; customGamma = true; //or selected Free gamma @@ -1165,8 +1166,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p bool pro = false; Glib::ustring chpro, outProfile; bool present_space[9] = {false, false, false, false, false, false, false, false, false}; - std::vector opnames = iccStore->getOutputProfiles (); - + std::vector opnames = iccStore->getProfiles (); //test if files are in system for (int j = 0; j < 9; j++) { // one can modify "option" [Color Management] to adapt the profile's name if they are different for windows, MacOS, Linux ?? @@ -1349,7 +1349,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p bwonly = false; } - readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output, bwonly); + readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm.output, params.icm.outputIntent, bwonly); if (settings->verbose) { printf("Output profile_: \"%s\"\n", params.icm.output.c_str()); diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc index 38cf88230..99ad03e9f 100644 --- a/rtgui/colortoning.cc +++ b/rtgui/colortoning.cc @@ -3,6 +3,7 @@ */ #include "colortoning.h" #include "mycurve.h" +#include "rtimage.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/diagonalcurveeditorsubgroup.cc b/rtgui/diagonalcurveeditorsubgroup.cc index ad896789f..4ca2bb159 100644 --- a/rtgui/diagonalcurveeditorsubgroup.cc +++ b/rtgui/diagonalcurveeditorsubgroup.cc @@ -30,6 +30,7 @@ #include "mydiagonalcurve.h" #include "curveeditor.h" #include "diagonalcurveeditorsubgroup.h" +#include "rtimage.h" DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt, Glib::ustring& curveDir) : CurveEditorSubGroup(curveDir) { diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 82e8d9fcf..b9f123ac5 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -25,12 +25,188 @@ #include "procparamchangers.h" #include "../rtengine/safegtk.h" #include "../rtengine/imagesource.h" +#include "../rtengine/iccstore.h" #include "soundman.h" #include "rtimage.h" #include +#include "popupbutton.h" using namespace rtengine::procparams; +class EditorPanel::MonitorProfileSelector +{ +private: + MyComboBoxText profileBox; + PopUpButton intentBox; + sigc::connection profileConn, intentConn; + + rtengine::StagedImageProcessor* const& processor; + +private: + void prepareProfileBox () + { + profileBox.set_size_request (100, -1); + + profileBox.append_text (M("PREFERENCES_PROFILE_NONE")); +#ifdef WIN32 + profileBox.append_text (M("MONITOR_PROFILE_SYSTEM") + " (" + rtengine::iccStore->getDefaultMonitorProfileName() + ")"); + profileBox.set_active (options.rtSettings.autoMonitorProfile ? 1 : 0); +#else + profileBox.set_active (0); +#endif + + const std::vector profiles = rtengine::iccStore->getProfiles (); + for (std::vector::const_iterator iterator = profiles.begin (); iterator != profiles.end (); ++iterator) { + profileBox.append_text (*iterator); + } + } + + void prepareIntentBox () + { + intentBox.addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); + intentBox.addEntry("intent-perceptual.png", M("PREFERENCES_INTENT_PERCEPTUAL")); + intentBox.addEntry("intent-absolute.png", M("PREFERENCES_INTENT_ABSOLUTE")); + + intentBox.setSelected(0); + intentBox.show (); + } + + void profileBoxChanged () + { + updateParameters (); + + profileBox.set_tooltip_text (profileBox.get_active_text ()); + } + + void intentBoxChanged (int) + { + updateParameters (); + } + + void updateParameters () + { + ConnectionBlocker profileBlocker (profileConn); + ConnectionBlocker intentBlocker (intentConn); + + Glib::ustring profile; + +#ifdef WIN32 + if (profileBox.get_active_row_number () == 1) { + profile = rtengine::iccStore->getDefaultMonitorProfileName (); + if (profile.empty ()) { + profile = options.rtSettings.monitorProfile; + } + if (profile.empty ()) { + profile = "sRGB IEC61966-2.1"; + } + } else if (profileBox.get_active_row_number () > 1) { + profile = profileBox.get_active_text (); + } +#else + profile = profileBox.get_active_row_number () > 0 ? profileBox.get_active_text () : Glib::ustring (); +#endif + + if (profileBox.get_active_row_number () == 0) { + + profile.clear(); + + intentBox.set_sensitive (false); + intentBox.setSelected (0); + + } else { + const std::uint8_t supportedIntents = rtengine::iccStore->getProofIntents (profile); + const bool supportsRelativeColorimetric = supportedIntents & 1 << INTENT_RELATIVE_COLORIMETRIC; + const bool supportsPerceptual = supportedIntents & 1 << INTENT_PERCEPTUAL; + const bool supportsAbsoluteColorimetric = supportedIntents & 1 << INTENT_ABSOLUTE_COLORIMETRIC; + + if (supportsPerceptual || supportsRelativeColorimetric || supportsAbsoluteColorimetric) { + intentBox.set_sensitive (true); + intentBox.setItemSensitivity(0, supportsRelativeColorimetric); + intentBox.setItemSensitivity(1, supportsPerceptual); + intentBox.setItemSensitivity(2, supportsAbsoluteColorimetric); + } else { + intentBox.set_sensitive (false); + intentBox.setSelected (0); + } + } + + rtengine::RenderingIntent intent; + switch (intentBox.getSelected ()) { + default: + case 0: + intent = rtengine::RI_RELATIVE; + break; + case 1: + intent = rtengine::RI_PERCEPTUAL; + break; + case 2: + intent = rtengine::RI_ABSOLUTE; + break; + } + + if (!processor) { + return; + } + + processor->beginUpdateParams (); + processor->setMonitorProfile (profile, intent); + processor->endUpdateParams (rtengine::EvMonitorTransform); + } + +public: + MonitorProfileSelector (rtengine::StagedImageProcessor* const& ipc) : + intentBox (Glib::ustring (), true), + processor (ipc) + { + prepareProfileBox (); + prepareIntentBox (); + + reset (); + + profileConn = profileBox.signal_changed ().connect (sigc::mem_fun (this, &MonitorProfileSelector::profileBoxChanged)); + intentConn = intentBox.signal_changed ().connect (sigc::mem_fun (this, &MonitorProfileSelector::intentBoxChanged)); + } + + void pack_end_in (Gtk::Box* box) + { + box->pack_end (*intentBox.buttonGroup, Gtk::PACK_SHRINK, 0); + box->pack_end (profileBox, Gtk::PACK_SHRINK, 0); + } + + void reset () + { + ConnectionBlocker profileBlocker (profileConn); + ConnectionBlocker intentBlocker (intentConn); + +#ifdef WIN32 + if (options.rtSettings.autoMonitorProfile) { + setActiveTextOrIndex (profileBox, options.rtSettings.monitorProfile, 1); + } else { + setActiveTextOrIndex (profileBox, options.rtSettings.monitorProfile, 0); + } +#else + setActiveTextOrIndex (profileBox, options.rtSettings.monitorProfile, 0); +#endif + + switch (options.rtSettings.monitorIntent) + { + default: + case rtengine::RI_RELATIVE: + intentBox.setSelected (0); + break; + case rtengine::RI_PERCEPTUAL: + intentBox.setSelected (1); + break; + case rtengine::RI_ABSOLUTE: + intentBox.setSelected (2); + break; + } + + updateParameters (); + } + +}; + EditorPanel::EditorPanel (FilePanel* filePanel) : realized(false), iHistoryShow(NULL), iHistoryHide(NULL), iTopPanel_1_Show(NULL), iTopPanel_1_Hide(NULL), iRightPanel_1_Show(NULL), iRightPanel_1_Hide(NULL), iBeforeLockON(NULL), iBeforeLockOFF(NULL), beforePreviewHandler(NULL), beforeIarea(NULL), beforeBox(NULL), afterBox(NULL), afterHeaderBox(NULL), parent(NULL), openThm(NULL), ipc(NULL), beforeIpc(NULL), isProcessing(false), catalogPane(NULL) { @@ -179,6 +355,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) // Save buttons Gtk::HBox* iops = Gtk::manage (new Gtk::HBox ()); + iops->set_spacing(2); //Gtk::Image *saveButtonImage = Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)); Gtk::Image *saveButtonImage = Gtk::manage (new RTImage ("gtk-save-large.png")); @@ -262,6 +439,12 @@ EditorPanel::EditorPanel (FilePanel* filePanel) iops->pack_end (*navPrev, Gtk::PACK_SHRINK, 0); } + iops->pack_end (*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_SHRINK, 0); + + // Monitor profile buttons + monitorProfile.reset (new MonitorProfileSelector (ipc)); + monitorProfile->pack_end_in (iops); + editbox->pack_start (*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0); editbox->pack_start (*iops, Gtk::PACK_SHRINK, 0); editbox->show_all (); @@ -568,6 +751,8 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) } history->resetSnapShotNumber(); + + monitorProfile->reset (); } void EditorPanel::close () diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index cf446da97..6de9928bd 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -84,6 +84,9 @@ protected: Gtk::Button* navNext; Gtk::Button* navPrev; + class MonitorProfileSelector; + std::auto_ptr monitorProfile; + ImageAreaPanel* iareapanel; PreviewHandler* previewHandler; PreviewHandler* beforePreviewHandler; // for the before-after view diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index e464b050e..915f0d84e 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1152,6 +1152,7 @@ void FileCatalog::developRequested (std::vector tbe, bool fas params.icm.input = options.fastexport_icm_input ; params.icm.working = options.fastexport_icm_working ; params.icm.output = options.fastexport_icm_output ; + params.icm.outputIntent = options.fastexport_icm_outputIntent ; params.icm.gamma = options.fastexport_icm_gamma ; params.resize.enabled = options.fastexport_resize_enabled ; params.resize.scale = options.fastexport_resize_scale ; diff --git a/rtgui/flatcurveeditorsubgroup.cc b/rtgui/flatcurveeditorsubgroup.cc index 516bed44a..691fbe3dd 100644 --- a/rtgui/flatcurveeditorsubgroup.cc +++ b/rtgui/flatcurveeditorsubgroup.cc @@ -31,6 +31,7 @@ #include "myflatcurve.h" #include "curveeditor.h" #include "flatcurveeditorsubgroup.h" +#include "rtimage.h" FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::ustring& curveDir) : CurveEditorSubGroup(curveDir) { diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 1e65f2753..79f050c2f 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -76,6 +76,22 @@ public: } }; +class ConnectionBlocker +{ +public: + ConnectionBlocker (sigc::connection& connection) : connection (connection) + { + wasBlocked = connection.block(); + } + ~ConnectionBlocker () + { + connection.block(wasBlocked); + } +private: + sigc::connection& connection; + bool wasBlocked; +}; + /** * @brief Glue box to control visibility of the MyExpender's content ; also handle the frame around it */ @@ -496,5 +512,12 @@ public: } }; +inline void setActiveTextOrIndex (Gtk::ComboBoxText& comboBox, const Glib::ustring& text, int index) +{ + comboBox.set_active_text (text); + + if (comboBox.get_active_row_number () < 0) + comboBox.set_active (index); +} #endif diff --git a/rtgui/history.cc b/rtgui/history.cc index 57f7549db..689ea6394 100644 --- a/rtgui/history.cc +++ b/rtgui/history.cc @@ -24,7 +24,6 @@ using namespace rtengine; using namespace rtengine::procparams; Glib::ustring eventDescrArray[NUMOFEVENTS]; -extern Glib::ustring argv0; History::History (bool bookmarkSupport) : blistener(NULL), tpc (NULL), bmnum (1) { @@ -204,8 +203,8 @@ void History::bookmarkSelectionChanged () void History::procParamsChanged (ProcParams* params, ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) { - // to prevent recursion, we filter out the events triggered by the history - if (ev == EvHistoryBrowsed) { + // to prevent recursion, we filter out the events triggered by the history and events that should not be registered + if (ev == EvHistoryBrowsed || ev == EvMonitorTransform) { return; } diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index e9e4e05ff..8b8057d45 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -83,7 +83,8 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch dcpFrame = Gtk::manage (new Gtk::Frame ("DCP")); Gtk::VBox* dcpFrameVBox = Gtk::manage (new Gtk::VBox ()); - dcpFrameVBox->set_border_width(4); + dcpFrameVBox->set_border_width(0); + dcpFrameVBox->set_spacing(2); Gtk::HBox* dcpIllHBox = Gtk::manage (new Gtk::HBox ()); dcpIllLabel = Gtk::manage (new Gtk::Label (M("TP_ICM_DCPILLUMINANT") + ":")); @@ -101,29 +102,25 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch dcpIllHBox->pack_start(*dcpIllLabel, Gtk::PACK_SHRINK, 4); dcpIllHBox->pack_start(*dcpIll); - Gtk::HBox* c1HBox = Gtk::manage ( new Gtk::HBox(true, 4)); ckbToneCurve = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_TONECURVE"))); ckbToneCurve->set_sensitive (false); ckbToneCurve->set_tooltip_text (M("TP_ICM_TONECURVE_TOOLTIP")); ckbApplyHueSatMap = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_APPLYHUESATMAP"))); ckbApplyHueSatMap->set_sensitive (false); ckbApplyHueSatMap->set_tooltip_text (M("TP_ICM_APPLYHUESATMAP_TOOLTIP")); - c1HBox->pack_start (*ckbToneCurve); - c1HBox->pack_start (*ckbApplyHueSatMap); - Gtk::HBox* c2HBox = Gtk::manage ( new Gtk::HBox(true, 4)); ckbApplyLookTable = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_APPLYLOOKTABLE"))); ckbApplyLookTable->set_sensitive (false); ckbApplyLookTable->set_tooltip_text (M("TP_ICM_APPLYLOOKTABLE_TOOLTIP")); ckbApplyBaselineExposureOffset = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_APPLYBASELINEEXPOSUREOFFSET"))); ckbApplyBaselineExposureOffset->set_sensitive (false); ckbApplyBaselineExposureOffset->set_tooltip_text (M("TP_ICM_APPLYBASELINEEXPOSUREOFFSET_TOOLTIP")); - c2HBox->pack_start (*ckbApplyLookTable); - c2HBox->pack_start (*ckbApplyBaselineExposureOffset); - dcpFrameVBox->pack_start(*dcpIllHBox); - dcpFrameVBox->pack_start(*c1HBox); - dcpFrameVBox->pack_start(*c2HBox); + dcpFrameVBox->pack_start(*dcpIllHBox, Gtk::PACK_SHRINK, 0); + dcpFrameVBox->pack_start(*ckbToneCurve, Gtk::PACK_SHRINK,0); + dcpFrameVBox->pack_start(*ckbApplyHueSatMap, Gtk::PACK_SHRINK,0); + dcpFrameVBox->pack_start(*ckbApplyLookTable, Gtk::PACK_SHRINK,0); + dcpFrameVBox->pack_start(*ckbApplyBaselineExposureOffset, Gtk::PACK_SHRINK,0); dcpFrame->add(*dcpFrameVBox); dcpFrame->set_sensitive(false); iVBox->pack_start (*dcpFrame); @@ -185,7 +182,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch onames->append_text (M("TP_ICM_NOICM")); onames->set_active (0); - std::vector opnames = iccStore->getOutputProfiles (); + std::vector opnames = iccStore->getProfiles (); for (size_t i = 0; i < opnames.size(); i++) { onames->append_text (opnames[i]); @@ -193,6 +190,19 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch onames->set_active (0); + // Rendering intent + Gtk::HBox *riHBox = Gtk::manage ( new Gtk::HBox()); + Gtk::Label* outputIntentLbl = Gtk::manage (new Gtk::Label(M("TP_ICM_PROFILEINTENT")+":")); + riHBox->pack_start (*outputIntentLbl, Gtk::PACK_SHRINK); + ointent = Gtk::manage (new MyComboBoxText ()); + riHBox->pack_start (*ointent, Gtk::PACK_EXPAND_WIDGET); + ointent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); + ointent->append_text (M("PREFERENCES_INTENT_RELATIVE")); + ointent->append_text (M("PREFERENCES_INTENT_SATURATION")); + ointent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); + ointent->set_active (1); + oVBox->pack_start(*riHBox, Gtk::PACK_SHRINK); + // Output gamma Gtk::HBox* gaHBox = Gtk::manage (new Gtk::HBox ()); @@ -282,6 +292,7 @@ ICMPanel::ICMPanel () : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunch wnames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::wpChanged) ); onames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::opChanged) ); + ointent->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::oiChanged) ); wgamma->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::gpChanged) ); dcpIll->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::dcpIlluminantChanged) ); @@ -507,6 +518,7 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) if (onames->get_active_row_number() == -1) { onames->set_active_text (M("TP_ICM_NOICM")); } + ointent->set_active(pp->icm.outputIntent); ckbToneCurve->set_active (pp->icm.toneCurve); lastToneCurve = pp->icm.toneCurve; @@ -545,6 +557,10 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) onames->set_active_text(M("GENERAL_UNCHANGED")); } + if (!pedited->icm.outputIntent) { + ointent->set_active_text(M("GENERAL_UNCHANGED")); + } + if (!pedited->icm.dcpIlluminant) { dcpIll->set_active_text(M("GENERAL_UNCHANGED")); } @@ -605,6 +621,13 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) pp->icm.output = onames->get_active_text(); } + int ointentVal = ointent->get_active_row_number(); + if (ointentVal >= 0 && ointentVal < RI__COUNT) { + pp->icm.outputIntent = static_cast(ointentVal); + } else { + pp->icm.outputIntent = rtengine::RI_RELATIVE; + } + pp->icm.freegamma = freegamma->get_active(); DCPProfile* dcp = NULL; @@ -641,6 +664,7 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) pedited->icm.input = !iunchanged->get_active (); pedited->icm.working = wnames->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.output = onames->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->icm.outputIntent = ointent->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.dcpIlluminant = dcpIll->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent (); pedited->icm.applyLookTable = !ckbApplyLookTable->get_inconsistent (); @@ -880,6 +904,14 @@ void ICMPanel::opChanged () } } +void ICMPanel::oiChanged () +{ + + if (listener) { + listener->panelChanged (EvOIntent, ointent->get_active_text()); + } +} + void ICMPanel::setRawMeta (bool raw, const rtengine::ImageData* pMeta) { @@ -979,6 +1011,7 @@ void ICMPanel::setBatchMode (bool batchMode) iVBox->reorder_child (*iunchanged, 5); removeIfThere (this, saveRef); onames->append_text (M("GENERAL_UNCHANGED")); + ointent->append_text (M("GENERAL_UNCHANGED")); wnames->append_text (M("GENERAL_UNCHANGED")); wgamma->append_text (M("GENERAL_UNCHANGED")); dcpIll->append_text (M("GENERAL_UNCHANGED")); diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 93828f5fd..863e88a46 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -78,6 +78,7 @@ private: MyComboBoxText* wgamma; MyComboBoxText* onames; + MyComboBoxText* ointent; Gtk::RadioButton* ofromdir; Gtk::RadioButton* ofromfile; Gtk::RadioButton* iunchanged; @@ -107,6 +108,7 @@ public: void wpChanged (); void opChanged (); + void oiChanged (); void ipChanged (); void gpChanged (); void GamChanged (); diff --git a/rtgui/options.cc b/rtgui/options.cc index 6d0b6a0d0..e6c697983 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -470,6 +470,7 @@ void Options::setDefaults () fastexport_icm_input = "(camera)"; fastexport_icm_working = "ProPhoto"; fastexport_icm_output = "RT_sRGB"; + fastexport_icm_outputIntent = rtengine::RI_RELATIVE; fastexport_icm_gamma = "default"; fastexport_resize_enabled = true; fastexport_resize_scale = 1; @@ -626,7 +627,6 @@ void Options::setDefaults () #else rtSettings.iccDirectory = "/usr/share/color/icc"; #endif - rtSettings.colorimetricIntent = 1; rtSettings.viewingdevice = 0; rtSettings.viewingdevicegrey = 3; rtSettings.viewinggreySc = 1; @@ -636,7 +636,8 @@ void Options::setDefaults () rtSettings.leveldnliss = 0; rtSettings.leveldnautsimpl = 0; - rtSettings.monitorProfile = ""; + rtSettings.monitorProfile = Glib::ustring(); + rtSettings.monitorIntent = rtengine::RI_RELATIVE; rtSettings.autoMonitorProfile = false; rtSettings.adobe = "RT_Medium_gsRGB"; // put the name of yours profiles (here windows) rtSettings.prophoto = "RT_Large_gBT709"; // these names appear in the menu "output profile" @@ -1461,7 +1462,7 @@ int Options::readFromFile (Glib::ustring fname) } if (keyFile.has_key ("Color Management", "Intent")) { - rtSettings.colorimetricIntent = keyFile.get_integer("Color Management", "Intent"); + rtSettings.monitorIntent = static_cast(keyFile.get_integer("Color Management", "Intent")); } if (keyFile.has_key ("Color Management", "CRI")) { @@ -2008,7 +2009,7 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_boolean ("Color Management", "AutoMonitorProfile", rtSettings.autoMonitorProfile); keyFile.set_boolean ("Color Management", "Autocielab", rtSettings.autocielab); keyFile.set_boolean ("Color Management", "RGBcurvesLumamode_Gamut", rtSettings.rgbcurveslumamode_gamut); - keyFile.set_integer ("Color Management", "Intent", rtSettings.colorimetricIntent); + keyFile.set_integer ("Color Management", "Intent", rtSettings.monitorIntent); keyFile.set_integer ("Color Management", "view", rtSettings.viewingdevice); keyFile.set_integer ("Color Management", "grey", rtSettings.viewingdevicegrey); keyFile.set_integer ("Color Management", "greySc", rtSettings.viewinggreySc); @@ -2075,6 +2076,7 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_string ("Fast Export", "fastexport_icm_input" , fastexport_icm_input ); keyFile.set_string ("Fast Export", "fastexport_icm_working" , fastexport_icm_working ); keyFile.set_string ("Fast Export", "fastexport_icm_output" , fastexport_icm_output ); + keyFile.set_integer ("Fast Export", "fastexport_icm_output_intent" , fastexport_icm_outputIntent ); keyFile.set_string ("Fast Export", "fastexport_icm_gamma" , fastexport_icm_gamma ); keyFile.set_boolean ("Fast Export", "fastexport_resize_enabled" , fastexport_resize_enabled ); keyFile.set_double ("Fast Export", "fastexport_resize_scale" , fastexport_resize_scale ); diff --git a/rtgui/options.h b/rtgui/options.h index 614042fa2..b896f4129 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -264,6 +264,7 @@ public: Glib::ustring fastexport_icm_input; Glib::ustring fastexport_icm_working; Glib::ustring fastexport_icm_output; + rtengine::RenderingIntent fastexport_icm_outputIntent; Glib::ustring fastexport_icm_gamma; bool fastexport_resize_enabled; double fastexport_resize_scale; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 35f26c58c..062c61ba2 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -351,6 +351,7 @@ void ParamsEdited::set (bool v) icm.dcpIlluminant = v; icm.working = v; icm.output = v; + icm.outputIntent = v; icm.gamma = v; icm.freegamma = v; icm.gampos = v; @@ -840,6 +841,7 @@ void ParamsEdited::initFrom (const std::vector icm.dcpIlluminant = icm.dcpIlluminant && p.icm.dcpIlluminant == other.icm.dcpIlluminant; icm.working = icm.working && p.icm.working == other.icm.working; icm.output = icm.output && p.icm.output == other.icm.output; + icm.outputIntent = icm.outputIntent && p.icm.outputIntent == other.icm.outputIntent; icm.gamma = icm.gamma && p.icm.gamma == other.icm.gamma; icm.freegamma = icm.freegamma && p.icm.freegamma == other.icm.freegamma; icm.gampos = icm.gampos && p.icm.gampos == other.icm.gampos; @@ -2193,6 +2195,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.icm.output = mods.icm.output; } + if (icm.outputIntent) { + toEdit.icm.outputIntent = mods.icm.outputIntent; + } + //if (icm.gampos) toEdit.icm.gampos = mods.icm.gampos; //if (icm.slpos) toEdit.icm.slpos = mods.icm.slpos; if (icm.gampos) { diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 60fbbdb81..261da1753 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -542,6 +542,7 @@ public: bool dcpIlluminant; bool working; bool output; + bool outputIntent; bool gamma; bool gampos; bool slpos; diff --git a/rtgui/popupbutton.cc b/rtgui/popupbutton.cc index 440d7b420..554f41cc6 100644 --- a/rtgui/popupbutton.cc +++ b/rtgui/popupbutton.cc @@ -21,6 +21,8 @@ #include "popupbutton.h" +#include + /* * PopUpButton::PopUpButton (const Glib::ustring& label, bool imgRight) * @@ -28,8 +30,14 @@ * * Parameters: * label = label displayed in the button + * nextOnClicked = selects the next entry if the button is clicked */ -PopUpButton::PopUpButton (const Glib::ustring& label) : Gtk::Button(), PopUpCommon(this, label) { } +PopUpButton::PopUpButton (const Glib::ustring& label, bool nextOnClicked) + : Gtk::Button () + , PopUpCommon (this, label) + , nextOnClicked(nextOnClicked) +{ +} void PopUpButton::show() { @@ -39,3 +47,27 @@ void PopUpButton::set_tooltip_text (const Glib::ustring &text) { PopUpCommon::set_tooltip_text (text); } + +void PopUpButton::set_sensitive (bool isSensitive) +{ + buttonGroup->set_sensitive(isSensitive); +} + +bool PopUpButton::on_button_release_event (GdkEventButton* event) +{ + if (nextOnClicked && getEntryCount () > 1) + { + const int last = getEntryCount () - 1; + int next = getSelected (); + + if (event->state & GDK_SHIFT_MASK) { + next = next > 0 ? next - 1 : last; + } else { + next = next < last ? next + 1 : 0; + } + + entrySelected (next); + } + + return Gtk::Button::on_button_release_event(event); +} diff --git a/rtgui/popupbutton.h b/rtgui/popupbutton.h index 23a9211a8..245d29aee 100644 --- a/rtgui/popupbutton.h +++ b/rtgui/popupbutton.h @@ -21,16 +21,24 @@ #ifndef _POPUPBUTTON_ #define _POPUPBUTTON_ -#include +#include #include "popupcommon.h" class PopUpButton : public Gtk::Button, public PopUpCommon { public: - PopUpButton (const Glib::ustring& label = ""); + PopUpButton (const Glib::ustring& label = Glib::ustring (), bool nextOnClicked = false); void show (); void set_tooltip_text (const Glib::ustring &text); + void set_sensitive (bool isSensitive=true); + +protected: + bool on_button_release_event (GdkEventButton* event); + +private: + bool nextOnClicked; + }; #endif diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc index 881994589..f7e667219 100644 --- a/rtgui/popupcommon.cc +++ b/rtgui/popupcommon.cc @@ -19,12 +19,16 @@ * Class created by Jean-Christophe FRISCH, aka 'Hombre' */ +#include #include "multilangmgr.h" #include "popupcommon.h" #include "../rtengine/safegtk.h" #include "rtimage.h" PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) + : selected (-1) // -1 means that the button is invalid + , menu (0) + , buttonImage (0) { button = thisButton; hasMenu = false; @@ -41,15 +45,6 @@ PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) // Create the global container and put the button in it buttonGroup = Gtk::manage( new Gtk::HBox(false, 0)); buttonGroup->pack_start(*button, Gtk::PACK_EXPAND_WIDGET, 0); - // Create the list entry - imageFilenames.clear(); - images.clear(); - sItems.clear(); - items.clear(); - selected = -1; // -1 : means that the button is invalid - menu = 0; - buttonImage = 0; - buttonHint = ""; } PopUpCommon::~PopUpCommon () @@ -58,83 +53,68 @@ PopUpCommon::~PopUpCommon () delete *i; } - for (std::vector::iterator i = items.begin(); i != items.end(); ++i) { - delete *i; - } - - if (menu) { - delete menu; - } - - if (buttonImage) { - delete buttonImage; - } - - delete buttonGroup; + delete menu; + delete buttonImage; } -PopUpCommon::type_signal_changed PopUpCommon::signal_changed() +bool PopUpCommon::addEntry (const Glib::ustring& fileName, const Glib::ustring& label) { - return message; -} + if (label.empty ()) + return false; -bool PopUpCommon::addEntry (Glib::ustring fileName, Glib::ustring label) -{ - bool added = false; + // Create the image + RTImage* newImage = new RTImage(fileName); + images.push_back(newImage); + imageFilenames.push_back(fileName); + int currPos = (int)images.size(); + // Create the menu item + Gtk::ImageMenuItem* newItem = Gtk::manage(new Gtk::ImageMenuItem (*newImage, label)); - if ( label.size() ) { - imageFilenames.push_back(fileName); - sItems.push_back(label); - // Create the image - RTImage* newImage = new RTImage(fileName); - images.push_back(newImage); - int currPos = (int)images.size(); - // Create the menu item - Gtk::ImageMenuItem* newItem = new Gtk::ImageMenuItem (*newImage, label); - items.push_back(newItem); - - if (selected == -1) { - // Create the menu on the first item - menu = new Gtk::Menu (); - // Create the image for the button - buttonImage = new RTImage(fileName); - // Use the first image by default - imageContainer->pack_start(*buttonImage, Gtk::PACK_EXPAND_WIDGET); - selected = 0; - } - - // When there is at least 1 choice, we add the arrow button - if (images.size() == 1) { - Gtk::Button* arrowButton = Gtk::manage( new Gtk::Button() ); - RTImage* arrowImage = Gtk::manage( new RTImage("popuparrow.png") ); - arrowButton->add(*arrowImage); //menuSymbol); - arrowButton->set_relief (Gtk::RELIEF_NONE); - arrowButton->set_border_width (0); - buttonGroup->pack_start(*arrowButton, Gtk::PACK_SHRINK, 0); - arrowButton->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) ); - hasMenu = true; - } - - newItem->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &PopUpCommon::entrySelected), currPos - 1)); - menu->attach (*newItem, 0, 1, currPos - 1, currPos); - // The item has been created - added = true; + if (selected == -1) { + // Create the menu on the first item + menu = new Gtk::Menu (); + // Create the image for the button + buttonImage = new RTImage(fileName); + // Use the first image by default + imageContainer->pack_start(*buttonImage, Gtk::PACK_EXPAND_WIDGET); + selected = 0; } - return added; + // When there is at least 1 choice, we add the arrow button + if (images.size() == 1) { + Gtk::Button* arrowButton = Gtk::manage( new Gtk::Button() ); + RTImage* arrowImage = Gtk::manage( new RTImage("popuparrow.png") ); + arrowButton->add(*arrowImage); //menuSymbol); + arrowButton->set_relief (Gtk::RELIEF_NONE); + arrowButton->set_border_width (0); + buttonGroup->pack_start(*arrowButton, Gtk::PACK_SHRINK, 0); + arrowButton->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) ); + hasMenu = true; + } + + newItem->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &PopUpCommon::entrySelected), currPos - 1)); + menu->attach (*newItem, 0, 1, currPos - 1, currPos); + + return true; } // TODO: 'PopUpCommon::removeEntry' method to be created... void PopUpCommon::entrySelected (int i) { - if (setSelected((unsigned int)i)) - // Emit a a signal if the selected item has changed - { - message.emit(selected); + // Emit a a signal if the selected item has changed + if (setSelected (i)) + message (selected); +} + +void PopUpCommon::setItemSensitivity (int i, bool isSensitive) { + Gtk::Menu_Helpers::MenuList items = menu->items(); + if (i < items.size()) { + items[i].set_sensitive(isSensitive); } } + /* * Set the button image with the selected item */ @@ -172,7 +152,12 @@ void PopUpCommon::setButtonHint() } if (selected > -1) { - hint += sItems.at(selected); + // HACK: Gtk::MenuItem::get_label does not seem to work reliably. + Gtk::MenuItem& item = menu->items ()[selected]; + Gtk::Label* label = dynamic_cast(item.get_child ()); + + if (label) + hint += label->get_text (); } button->set_tooltip_markup(hint); diff --git a/rtgui/popupcommon.h b/rtgui/popupcommon.h index 872beb434..b5cb757f4 100644 --- a/rtgui/popupcommon.h +++ b/rtgui/popupcommon.h @@ -21,11 +21,21 @@ #ifndef _POPUPCOMMON_ #define _POPUPCOMMON_ +#include +#include +#include -#include -#include -#include "rtimage.h" +namespace Gtk +{ +class HBox; +class Menu; +class Button; +class ImageMenuItem; +} +typedef struct _GdkEventButton GdkEventButton; + +class RTImage; class PopUpCommon { @@ -37,27 +47,20 @@ public: PopUpCommon (Gtk::Button* button, const Glib::ustring& label = ""); virtual ~PopUpCommon (); - bool addEntry (Glib::ustring fileName, Glib::ustring label); + bool addEntry (const Glib::ustring& fileName, const Glib::ustring& label); + int getEntryCount () const; bool setSelected (int entryNum); - int getSelected () - { - return selected; - } + int getSelected () const; void setButtonHint(); void show (); void set_tooltip_text (const Glib::ustring &text); + void setItemSensitivity (int i, bool isSensitive); private: type_signal_changed message; - /* - TODO: MenuItem::get_label() doesn't return any string, or an empty string !? - That's why we store entries strings in sItems, but it would be nice to get ride of it... - */ - std::vector sItems; std::vector imageFilenames; std::vector images; - std::vector items; Glib::ustring buttonHint; RTImage* buttonImage; Gtk::HBox* imageContainer; @@ -67,8 +70,25 @@ private: bool hasMenu; void showMenu(GdkEventButton* event); + +protected: void entrySelected (int i); }; +inline PopUpCommon::type_signal_changed PopUpCommon::signal_changed () +{ + return message; +} + +inline int PopUpCommon::getEntryCount () const +{ + return images.size(); +} + +inline int PopUpCommon::getSelected () const +{ + return selected; +} + #endif diff --git a/rtgui/popuptogglebutton.h b/rtgui/popuptogglebutton.h index 58342e66c..930fae4f2 100644 --- a/rtgui/popuptogglebutton.h +++ b/rtgui/popuptogglebutton.h @@ -21,7 +21,7 @@ #ifndef _POPUPTOGGLEBUTTON_ #define _POPUPTOGGLEBUTTON_ -#include "popupbutton.h" +#include #include "popupcommon.h" class PopUpToggleButton : public Gtk::ToggleButton, public PopUpCommon diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index dca0eff17..f5adf43e0 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -687,32 +687,29 @@ Gtk::Widget* Preferences::getColorManagementPanel () Gtk::VBox* mvbcm = Gtk::manage (new Gtk::VBox ()); mvbcm->set_border_width (4); - /* - Gtk::Label* intlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_CMETRICINTENT")+":", Gtk::ALIGN_LEFT)); - intent = Gtk::manage (new Gtk::ComboBoxText ()); - intent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); - intent->append_text (M("PREFERENCES_INTENT_RELATIVE")); - intent->append_text (M("PREFERENCES_INTENT_SATURATION")); - intent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); - */ iccDir = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_ICCDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); Gtk::Label* pdlabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_ICCDIR") + ":", Gtk::ALIGN_LEFT)); - Gtk::FileFilter monProfileFilter_colprof; - monProfileFilter_colprof.set_name(M("FILECHOOSER_FILTER_COLPROF")); - monProfileFilter_colprof.add_pattern("*.icc"); - monProfileFilter_colprof.add_pattern("*.ICC"); - monProfileFilter_colprof.add_pattern("*.icm"); - monProfileFilter_colprof.add_pattern("*.ICM"); - Gtk::FileFilter monProfileFilter_any; - monProfileFilter_any.set_name(M("FILECHOOSER_FILTER_ANY")); - monProfileFilter_any.add_pattern("*"); + monProfile = Gtk::manage (new Gtk::ComboBoxText ()); + Gtk::Label* mplabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONPROFILE") + ":", Gtk::ALIGN_LEFT)); - monProfile = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_MONITORICC"), Gtk::FILE_CHOOSER_ACTION_OPEN)); - monProfile->add_filter (monProfileFilter_colprof); - monProfile->add_filter (monProfileFilter_any); - Gtk::Label* mplabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONITORICC") + ":", Gtk::ALIGN_LEFT)); + monIntent = Gtk::manage (new Gtk::ComboBoxText ()); + Gtk::Label* milabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONINTENT")+":", Gtk::ALIGN_LEFT)); + + monProfile->append_text (M("PREFERENCES_PROFILE_NONE")); + monProfile->set_active (0); + + const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfiles (); + for (std::vector::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) + monProfile->append_text (*profile); + + monIntent->append_text (M("PREFERENCES_INTENT_RELATIVE")); + monIntent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); + monIntent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); + monIntent->set_active (1); + + iccDir->signal_selection_changed ().connect (sigc::mem_fun (this, &Preferences::iccDirChanged)); #if defined(WIN32) // Auto-detection not implemented for Linux, see issue 851 cbAutoMonProfile = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_AUTOMONPROFILE"))); @@ -720,17 +717,21 @@ Gtk::Widget* Preferences::getColorManagementPanel () #endif Gtk::Table* colt = Gtk::manage (new Gtk::Table (3, 2)); - //colt->attach (*intlab, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - //colt->attach (*intent, 1, 2, 0, 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); - colt->attach (*pdlabel, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*iccDir, 1, 2, 1, 2, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + int row = 0; + colt->attach (*pdlabel, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*iccDir, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); #if !defined(__APPLE__) // monitor profile not supported on apple - colt->attach (*mplabel, 0, 1, 2, 3, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*monProfile, 1, 2, 2, 3, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + ++row; + colt->attach (*mplabel, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*monProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); #if defined(WIN32) - colt->attach (*cbAutoMonProfile, 1, 2, 3, 4, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + ++row; + colt->attach (*cbAutoMonProfile, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); #endif #endif + ++row; + colt->attach (*milabel, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*monIntent, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); mvbcm->pack_start (*colt, Gtk::PACK_SHRINK, 4); #if defined(WIN32) @@ -1445,10 +1446,25 @@ void Preferences::storePreferences () moptions.CPBPath = txtCustProfBuilderPath->get_text(); moptions.CPBKeys = CPBKeyType(custProfBuilderLabelType->get_active_row_number()); - moptions.rtSettings.monitorProfile = monProfile->get_filename (); +#if !defined(__APPLE__) // monitor profile not supported on apple + moptions.rtSettings.monitorProfile = monProfile->get_active_text (); + switch (monIntent->get_active_row_number ()) { + default: + case 0: + moptions.rtSettings.monitorIntent = rtengine::RI_RELATIVE; + break; + case 1: + moptions.rtSettings.monitorIntent = rtengine::RI_PERCEPTUAL; + break; + case 2: + moptions.rtSettings.monitorIntent = rtengine::RI_ABSOLUTE; + break; + } #if defined(WIN32) moptions.rtSettings.autoMonitorProfile = cbAutoMonProfile->get_active (); #endif +#endif + moptions.rtSettings.iccDirectory = iccDir->get_filename (); //moptions.rtSettings.colorimetricIntent = intent->get_active_row_number (); moptions.rtSettings.viewingdevice = view->get_active_row_number (); @@ -1561,13 +1577,18 @@ void Preferences::fillPreferences () rememberZoomPanCheckbutton->set_active (moptions.rememberZoomAndPan); ctiffserialize->set_active(moptions.serializeTiffRead); #if !defined(__APPLE__) // monitor profile not supported on apple - - if (safe_file_test (moptions.rtSettings.monitorProfile, Glib::FILE_TEST_EXISTS)) { - monProfile->set_filename (moptions.rtSettings.monitorProfile); - } - - if (moptions.rtSettings.monitorProfile.empty()) { - monProfile->set_current_folder (moptions.rtSettings.iccDirectory); + setActiveTextOrIndex (*monProfile, moptions.rtSettings.monitorProfile, 0); + switch (moptions.rtSettings.monitorIntent) { + default: + case rtengine::RI_RELATIVE: + monIntent->set_active (0); + break; + case rtengine::RI_PERCEPTUAL: + monIntent->set_active (1); + break; + case rtengine::RI_ABSOLUTE: + monIntent->set_active (2); + break; } #if defined(WIN32) @@ -1579,7 +1600,6 @@ void Preferences::fillPreferences () iccDir->set_current_folder (moptions.rtSettings.iccDirectory); } - //intent->set_active (moptions.rtSettings.colorimetricIntent); view->set_active (moptions.rtSettings.viewingdevice); grey->set_active (moptions.rtSettings.viewingdevicegrey); greySc->set_active (moptions.rtSettings.viewinggreySc); @@ -1931,6 +1951,21 @@ void Preferences::bundledProfilesChanged () rpconn.block (false); } +void Preferences::iccDirChanged () +{ + const Glib::ustring currentSelection = monProfile->get_active_text (); + + monProfile->clear(); + + monProfile->append_text (M("PREFERENCES_PROFILE_NONE")); + monProfile->set_active (0); + const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfilesFromDir (iccDir->get_filename ()); + for (std::vector::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) + monProfile->append_text (*profile); + + monProfile->set_active_text (currentSelection); +} + void Preferences::storeCurrentValue() { // TODO: Find a way to get and restore the current selection; the following line can't work anymore diff --git a/rtgui/preferences.h b/rtgui/preferences.h index ee885c568..1cfb435cf 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -95,7 +95,8 @@ protected: Gtk::CheckButton* showExpComp; Gtk::FileChooserButton* iccDir; - Gtk::FileChooserButton* monProfile; + Gtk::ComboBoxText* monProfile; + Gtk::ComboBoxText* monIntent; Gtk::CheckButton* cbAutoMonProfile; //Gtk::CheckButton* cbAutocielab; Gtk::CheckButton* cbciecamfloat; @@ -106,7 +107,6 @@ protected: Gtk::SpinButton* panFactor; Gtk::CheckButton* rememberZoomPanCheckbutton; - Gtk::ComboBoxText* intent; Gtk::ComboBoxText* view; Gtk::ComboBoxText* grey; Gtk::ComboBoxText* greySc; @@ -212,7 +212,8 @@ protected: void forRAWComboChanged (); void forImageComboChanged (); void layoutComboChanged (); - void bundledProfilesChanged(); + void bundledProfilesChanged (); + void iccDirChanged (); void switchThemeTo (Glib::ustring newTheme, bool slimInterface); void switchFontTo (Glib::ustring newFont); bool splashClosed(GdkEventAny* event); diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index eca9f7a91..fb69de3e3 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -3,6 +3,7 @@ */ #include "retinex.h" #include "mycurve.h" +#include "rtimage.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc index 4bebb10ad..abab1d2d1 100644 --- a/rtgui/wavelet.cc +++ b/rtgui/wavelet.cc @@ -21,6 +21,7 @@ #include #include "edit.h" #include "guiutils.h" +#include "rtimage.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/tools/source_icons/scalable/intent-absolute.file b/tools/source_icons/scalable/intent-absolute.file new file mode 100644 index 000000000..57278bff2 --- /dev/null +++ b/tools/source_icons/scalable/intent-absolute.file @@ -0,0 +1 @@ +intent-absolute.png,w25,actions diff --git a/tools/source_icons/scalable/intent-absolute.svg b/tools/source_icons/scalable/intent-absolute.svg new file mode 100644 index 000000000..b5092b0c5 --- /dev/null +++ b/tools/source_icons/scalable/intent-absolute.svg @@ -0,0 +1,1376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/tools/source_icons/scalable/intent-perceptual.file b/tools/source_icons/scalable/intent-perceptual.file new file mode 100644 index 000000000..3e7520042 --- /dev/null +++ b/tools/source_icons/scalable/intent-perceptual.file @@ -0,0 +1 @@ +intent-perceptual.png,w25,actions diff --git a/tools/source_icons/scalable/intent-perceptual.svg b/tools/source_icons/scalable/intent-perceptual.svg new file mode 100644 index 000000000..3c949c91e --- /dev/null +++ b/tools/source_icons/scalable/intent-perceptual.svg @@ -0,0 +1,1362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/tools/source_icons/scalable/intent-relative.file b/tools/source_icons/scalable/intent-relative.file new file mode 100644 index 000000000..5191a25c3 --- /dev/null +++ b/tools/source_icons/scalable/intent-relative.file @@ -0,0 +1 @@ +intent-relative.png,w25,actions diff --git a/tools/source_icons/scalable/intent-relative.svg b/tools/source_icons/scalable/intent-relative.svg new file mode 100644 index 000000000..706de23d1 --- /dev/null +++ b/tools/source_icons/scalable/intent-relative.svg @@ -0,0 +1,1361 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/tools/source_icons/scalable/intent-saturation.file b/tools/source_icons/scalable/intent-saturation.file new file mode 100644 index 000000000..9f33b978e --- /dev/null +++ b/tools/source_icons/scalable/intent-saturation.file @@ -0,0 +1 @@ +intent-saturation.png,w25,actions diff --git a/tools/source_icons/scalable/intent-saturation.svg b/tools/source_icons/scalable/intent-saturation.svg new file mode 100644 index 000000000..1af08f4f2 --- /dev/null +++ b/tools/source_icons/scalable/intent-saturation.svg @@ -0,0 +1,1362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/tools/source_icons/scalable/softProof.file b/tools/source_icons/scalable/softProof.file new file mode 100644 index 000000000..e275113ec --- /dev/null +++ b/tools/source_icons/scalable/softProof.file @@ -0,0 +1 @@ +softProof.png,w22,actions diff --git a/tools/source_icons/scalable/softProof.svg b/tools/source_icons/scalable/softProof.svg new file mode 100644 index 000000000..d09f316a2 --- /dev/null +++ b/tools/source_icons/scalable/softProof.svg @@ -0,0 +1,1389 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + +