From e7d90ec1a2e2f29a280341f02a3c6e31a9418485 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 29 Jan 2018 21:17:34 +0100 Subject: [PATCH] Improve accuracy of Y to L conversion, fixes #4338 --- rtengine/color.cc | 239 +++++++++++++++++++---------------- rtengine/color.h | 28 +++- rtengine/improcfun.cc | 5 +- rtengine/iplab2rgb.cc | 2 +- rtengine/ipvibrance.cc | 2 +- rtgui/histogrampanel.cc | 151 +--------------------- rtgui/histogrampanel.h | 3 +- rtgui/lockablecolorpicker.cc | 4 +- rtgui/navigator.cc | 4 +- 9 files changed, 163 insertions(+), 275 deletions(-) diff --git a/rtengine/color.cc b/rtengine/color.cc index 68fd467e2..4a71d222b 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -34,6 +34,7 @@ extern const Settings* settings; cmsToneCurve* Color::linearGammaTRC; LUTf Color::cachef; +LUTf Color::cachefy; LUTf Color::gamma2curve; LUTf Color::gammatab; @@ -65,6 +66,9 @@ const double Color::eps_max = 580.40756; //(MAXVALF* 216.0f/24389.0); const double Color::eps = 216.0f / 24389.0; //0.008856 const double Color::kappa = 24389.0 / 27.0; //903.29630; +const float Color::epsf = eps; +const float Color::kappaf = kappa; + const float Color::D50x = 0.9642f; //0.96422; const float Color::D50z = 0.8249f; //0.82521; const double Color::u0 = 4.0 * D50x / (D50x + 15 + 3 * D50z); @@ -137,6 +141,7 @@ void Color::init () constexpr auto maxindex = 65536; cachef(maxindex, LUT_CLIP_BELOW); + cachefy(maxindex, LUT_CLIP_BELOW); gammatab(maxindex, 0); gammatabThumb(maxindex, 0); @@ -180,6 +185,23 @@ void Color::init () } #ifdef _OPENMP #pragma omp section +#endif + { + int i = 0; + int epsmaxint = eps_max; + + for (; i <= epsmaxint; i++) + { + cachefy[i] = 327.68 * (kappa * i / MAXVALF); + } + + for(; i < maxindex; i++) + { + cachefy[i] = 327.68 * (116.0 * std::cbrt((double)i / MAXVALF) - 16.0); + } + } +#ifdef _OPENMP + #pragma omp section #endif { for (int i = 0; i < maxindex; i++) @@ -360,150 +382,122 @@ void Color::cleanup () } } -void Color::rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace) -{ - double xyz_rgb[3][3]; - const double ep = 216.0 / 24389.0; - const double ka = 24389.0 / 27.0; +void Color::rgb2lab01 (const Glib::ustring &profile, const Glib::ustring &profileW, float r, float g, float b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace) +{ // do not use this function in a loop. It really eats processing time caused by Glib::ustring comparisons - double var_R = r / 65535.0; - double var_G = g / 65535.0; - double var_B = b / 65535.0; - - Glib::ustring profileCalc; - profileCalc = "sRGB"; //default - - if (workingSpace) { - profileCalc = profileW; //display working - } - - else {// if you want display = output space - if (profile == "RT_sRGB" || profile == "RT_sRGB_gBT709" || profile == "RT_sRGB_g10") { - profileCalc = "sRGB"; - } - - if (profile == "ProPhoto" || profile == "RT_Large_gBT709" || profile == "RT_Large_g10" || profile == "RT_Large_gsRGB") { - profileCalc = "ProPhoto"; - } - - if (profile == "AdobeRGB1998" || profile == "RT_Medium_gsRGB") { - profileCalc = "Adobe RGB"; - } - - if (profile == "WideGamutRGB") { - profileCalc = "WideGamut"; - } - } + Glib::ustring profileCalc = "sRGB"; //default if (workingSpace) {//display working + profileCalc = profileW; //display working if (profileW == "sRGB") { //apply sRGB inverse gamma - if ( var_R > 0.04045 ) { - var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); + if (r > 0.04045f) { + r = pow_F(((r + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve); } else { - var_R = var_R / 12.92; + r /= 12.92f; } - if ( var_G > 0.04045 ) { - var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); + if (g > 0.04045f) { + g = pow_F(((g + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve); } else { - var_G = var_G / 12.92; + g /= 12.92f; } - if ( var_B > 0.04045 ) { - var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); + if (b > 0.04045f) { + b = pow_F(((b + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve); } else { - var_B = var_B / 12.92; + b /= 12.92f; } } else if (profileW == "ProPhoto") { // apply inverse gamma 1.8 - var_R = pow ( var_R, 1.8); - var_G = pow ( var_G, 1.8); - var_B = pow ( var_B, 1.8); + r = pow_F(r, 1.8f); + g = pow_F(g, 1.8f); + b = pow_F(b, 1.8f); } else { // apply inverse gamma 2.2 - var_R = pow ( var_R, 2.2); - var_G = pow ( var_G, 2.2); - var_B = pow ( var_B, 2.2); + r = pow_F(r, 2.2f); + g = pow_F(g, 2.2f); + b = pow_F(b, 2.2f); + } + } else { //display output profile + if (profile == "RT_sRGB" || profile == "RT_sRGB_gBT709" || profile == "RT_sRGB_g10") { // use default "sRGB" + } else if (profile == "ProPhoto" || profile == "RT_Large_gBT709" || profile == "RT_Large_g10" || profile == "RT_Large_gsRGB") { + profileCalc = "ProPhoto"; + } else if (profile == "AdobeRGB1998" || profile == "RT_Medium_gsRGB") { + profileCalc = "Adobe RGB"; + } else if (profile == "WideGamutRGB") { + profileCalc = "WideGamut"; } - } else { //display outout profile if (profile == "RT_sRGB" || profile == "RT_Large_gsRGB" || profile == "RT_Medium_gsRGB") { //apply sRGB inverse gamma - if ( var_R > 0.04045 ) { - var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); + if (r > 0.04045f) { + r = pow_F(((r + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve); } else { - var_R = var_R / 12.92; + r /= 12.92f; } - if ( var_G > 0.04045 ) { - var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); + if (g > 0.04045f) { + g = pow_F(((g + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve); } else { - var_G = var_G / 12.92; + g /= 12.92f; } - if ( var_B > 0.04045 ) { - var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); + if (b > 0.04045f) { + b = pow_F(((b + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve); } else { - var_B = var_B / 12.92; + b /= 12.92f; } - } - - else if (profile == "RT_sRGB_gBT709" || profile == "RT_Large_gBT709") { // - if ( var_R > 0.0795 ) { - var_R = pow ( ( ( var_R + 0.0954 ) / 1.0954 ), 2.2); + } else if (profile == "RT_sRGB_gBT709" || profile == "RT_Large_gBT709") { // + if (r > 0.0795f) { + r = pow_F(((r + 0.0954f) / 1.0954f), 2.2f); } else { - var_R = var_R / 4.5; + r /= 4.5f; } - if ( var_G > 0.0795 ) { - var_G = pow ( ( ( var_G + 0.0954 ) / 1.0954 ), 2.2); + if (g > 0.0795f) { + g = pow_F(((g + 0.0954f) / 1.0954f), 2.2f); } else { - var_G = var_G / 4.5; + g /= 4.5f; } - if ( var_B > 0.0795 ) { - var_B = pow ( ( ( var_B + 0.0954 ) / 1.0954 ), 2.2); + if (b > 0.0795f) { + b = pow_F(((b + 0.0954f) / 1.0954f), 2.2f); } else { - var_B = var_B / 4.5; + b /= 4.5f; } } else if (profile == "ProPhoto") { // apply inverse gamma 1.8 - var_R = pow ( var_R, 1.8); - var_G = pow ( var_G, 1.8); - var_B = pow ( var_B, 1.8); - } else if (profile == "RT_sRGB_g10" || profile == "RT_Large_g10") { // apply inverse gamma 1.8 + r = pow_F(r, 1.8f); + g = pow_F(g, 1.8f); + b = pow_F(b, 1.8f); + } else if (profile == "RT_sRGB_g10" || profile == "RT_Large_g10") { // gamma 1.0, do nothing - var_R = pow ( var_R, 1.); - var_G = pow ( var_G, 1.); - var_B = pow ( var_B, 1.); - } + } else {// apply inverse gamma 2.2 - else {// apply inverse gamma 2.2 - var_R = pow ( var_R, 2.2); - var_G = pow ( var_G, 2.2); - var_B = pow ( var_B, 2.2); + r = pow_F(r, 2.2f); + g = pow_F(g, 2.2f); + b = pow_F(b, 2.2f); } } - // TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileW); + TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix(profileCalc); - TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileCalc); + float xyz_rgb[3][3]; for (int m = 0; m < 3; m++) for (int n = 0; n < 3; n++) { xyz_rgb[m][n] = wprof[m][n]; } - double varxx, varyy, varzz; - double var_X = ( xyz_rgb[0][0] * var_R + xyz_rgb[0][1] * var_G + xyz_rgb[0][2] * var_B ) / Color::D50x; - double var_Y = ( xyz_rgb[1][0] * var_R + xyz_rgb[1][1] * var_G + xyz_rgb[1][2] * var_B ) ; - double var_Z = ( xyz_rgb[2][0] * var_R + xyz_rgb[2][1] * var_G + xyz_rgb[2][2] * var_B ) / Color::D50z; + float var_X = (xyz_rgb[0][0] * r + xyz_rgb[0][1] * g + xyz_rgb[0][2] * b) / Color::D50x; + float var_Y = (xyz_rgb[1][0] * r + xyz_rgb[1][1] * g + xyz_rgb[1][2] * b); + float var_Z = (xyz_rgb[2][0] * r + xyz_rgb[2][1] * g + xyz_rgb[2][2] * b) / Color::D50z; - varxx = var_X > ep ? cbrt(var_X) : ( ka * var_X + 16.0) / 116.0 ; - varyy = var_Y > ep ? cbrt(var_Y) : ( ka * var_Y + 16.0) / 116.0 ; - varzz = var_Z > ep ? cbrt(var_Z) : ( ka * var_Z + 16.0) / 116.0 ; - LAB_l = ( 116 * varyy ) - 16; - LAB_a = 500 * ( varxx - varyy ); - LAB_b = 200 * ( varyy - varzz ); + float varxx = var_X > epsf ? xcbrtf(var_X) : (kappaf * var_X + 16.f) / 116.f ; + float varyy = var_Y > epsf ? xcbrtf(var_Y) : (kappaf * var_Y + 16.f) / 116.f ; + float varzz = var_Z > epsf ? xcbrtf(var_Z) : (kappaf * var_Z + 16.f) / 116.f ; + LAB_l = var_Y > epsf ? (xcbrtf(var_Y) * 116.f) - 16.f : kappaf * var_Y; + LAB_a = 500.f * ( varxx - varyy ); + LAB_b = 200.f * ( varyy - varzz ); } @@ -746,6 +740,37 @@ void Color::rgb2hsv(float r, float g, float b, float &h, float &s, float &v) } } +void Color::rgb2hsv01(float r, float g, float b, float &h, float &s, float &v) +{ + + const float var_Min = min(r, g, b); + const float var_Max = max(r, g, b); + const float del_Max = var_Max - var_Min; + + h = 0.f; + v = var_Max; + + if (del_Max < 0.00001f) { + s = 0.f; + } else { + s = del_Max / var_Max; + + if (r == var_Max) { + h = (g - b) / del_Max; + } else if (g == var_Max) { + h = 2.f + (b - r) / del_Max; + } else if (b == var_Max) { + h = 4.f + (r - g) / del_Max; + } + + h /= 6.f; + + if (h < 0.f) { + h += 1.f; + } + } +} + void Color::hsv2rgb (float h, float s, float v, float &r, float &g, float &b) { @@ -1683,7 +1708,7 @@ void Color::Lab2XYZ(float L, float a, float b, float &x, float &y, float &z) float LL = L / 327.68f; float aa = a / 327.68f; float bb = b / 327.68f; - float fy = (0.00862069f * LL) + 0.137932f; // (L+16)/116 + float fy = (c1By116 * LL) + c16By116; // (L+16)/116 float fx = (0.002f * aa) + fy; float fz = fy - (0.005f * bb); x = 65535.0f * f2xyz(fx) * D50x; @@ -1694,7 +1719,7 @@ void Color::Lab2XYZ(float L, float a, float b, float &x, float &y, float &z) void Color::L2XYZ(float L, float &x, float &y, float &z) // for black & white { float LL = L / 327.68f; - float fy = (0.00862069f * LL) + 0.137932f; // (L+16)/116 + float fy = (c1By116 * LL) + c16By116; // (L+16)/116 float fxz = 65535.f * f2xyz(fy); x = fxz * D50x; z = fxz * D50z; @@ -1709,7 +1734,7 @@ void Color::Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat & L /= c327d68; a /= c327d68; b /= c327d68; - vfloat fy = F2V(0.00862069f) * L + F2V(0.137932f); + vfloat fy = F2V(c1By116) * L + F2V(c16By116); vfloat fx = F2V(0.002f) * a + fy; vfloat fz = fy - (F2V(0.005f) * b); vfloat c65535 = F2V(65535.f); @@ -1727,8 +1752,6 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b, #ifdef __SSE2__ vfloat maxvalfv = F2V(MAXVALF); - vfloat c116v = F2V(116.f); - vfloat c5242d88v = F2V(5242.88f); vfloat c500v = F2V(500.f); vfloat c200v = F2V(200.f); #endif @@ -1753,7 +1776,7 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b, float fy = (y <= 65535.f ? cachef[y] : (327.68f * xcbrtf(y / MAXVALF))); float fz = (z <= 65535.f ? cachef[z] : (327.68f * xcbrtf(z / MAXVALF))); - L[i + k] = (116.f * fy - 5242.88f); //5242.88=16.0*327.68; + L[i + k] = (y <= 65535.0f ? cachefy[y] : 327.68f * (116.f * xcbrtf(y / MAXVALF) - 16.f)); a[i + k] = (500.f * (fx - fy) ); b[i + k] = (200.f * (fy - fz) ); } @@ -1762,7 +1785,7 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b, const vfloat fy = cachef[yv]; const vfloat fz = cachef[zv]; - STVFU(L[i], c116v * fy - c5242d88v); //5242.88=16.0*327.68; + STVFU(L[i], cachefy[yv]); STVFU(a[i], c500v * (fx - fy)); STVFU(b[i], c200v * (fy - fz)); } @@ -1781,7 +1804,7 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b, fy = (y <= 65535.0f ? cachef[y] : (327.68f * xcbrtf(y / MAXVALF))); fz = (z <= 65535.0f ? cachef[z] : (327.68f * xcbrtf(z / MAXVALF))); - L[i] = 116.0f * fy - 5242.88f; //5242.88=16.0*327.68; + L[i] = (y <= 65535.0f ? cachefy[y] : 327.68f * (116.f * xcbrtf(y / MAXVALF) - 16.f)); a[i] = 500.0f * (fx - fy); b[i] = 200.0f * (fy - fz); } @@ -1799,14 +1822,14 @@ void Color::XYZ2Lab(float X, float Y, float Z, float &L, float &a, float &b) fy = (y <= 65535.0f ? cachef[y] : (327.68f * xcbrtf(y / MAXVALF))); fz = (z <= 65535.0f ? cachef[z] : (327.68f * xcbrtf(z / MAXVALF))); - L = (116.0f * fy - 5242.88f); //5242.88=16.0*327.68; + L = (y <= 65535.0f ? cachefy[y] : 327.68f * (116.f * xcbrtf(y / MAXVALF) - 16.f)); a = (500.0f * (fx - fy) ); b = (200.0f * (fy - fz) ); } void Color::Lab2Yuv(float L, float a, float b, float &Y, float &u, float &v) { - float fy = (0.00862069 * L / 327.68) + 0.137932; // (L+16)/116 + float fy = (c1By116 * L / 327.68) + c16By116; // (L+16)/116 float fx = (0.002 * a / 327.68) + fy; float fz = fy - (0.005 * b / 327.68); float LL = L / 327.68; @@ -1835,7 +1858,7 @@ void Color::Yuv2Lab(float Yin, float u, float v, float &L, float &a, float &b, c float fy = (Y <= 65535.0 ? cachef[Y] : (327.68 * std::cbrt(Y / MAXVALF))); float fz = (Z <= 65535.0 ? cachef[Z] : (327.68 * std::cbrt(Z / MAXVALF))); - L = (116.0 * fy - 5242.88); //5242.88=16.0*327.68; + L = (Y <= 65535.0f ? cachefy[Y] : 327.68f * (116.f * xcbrtf(Y / MAXVALF) - 16.f)); a = (500.0 * (fx - fy) ); b = (200.0 * (fy - fz) ); } @@ -2304,7 +2327,7 @@ void Color::gamutLchonly (float HH, float &Lprov1, float &Chprov1, float &R, flo float bprov1 = Chprov1 * sincosval.x; //conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction - float fy = (0.00862069f * Lprov1 ) + 0.137932f; + float fy = (c1By116 * Lprov1 ) + c16By116; float fx = (0.002f * aprov1) + fy; float fz = fy - (0.005f * bprov1); @@ -2424,7 +2447,7 @@ void Color::gamutLchonly (float HH, float2 sincosval, float &Lprov1, float &Chpr float bprov1 = Chprov1 * sincosval.x; //conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction - float fy = (0.00862069f * Lprov1 ) + 0.137932f; + float fy = (c1By116 * Lprov1 ) + c16By116; float fx = (0.002f * aprov1) + fy; float fz = fy - (0.005f * bprov1); @@ -2533,7 +2556,7 @@ void Color::gamutLchonly (float2 sincosval, float &Lprov1, float &Chprov1, const float bprov1 = Chprov1 * sincosval.x; //conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction - float fy = (0.00862069f * Lprov1 ) + 0.137932f; + float fy = (c1By116 * Lprov1 ) + c16By116; float fx = (0.002f * aprov1) + fy; float fz = fy - (0.005f * bprov1); diff --git a/rtengine/color.h b/rtengine/color.h index d56b30e52..06b9dceb8 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -123,12 +123,15 @@ public: const static double sRGBGamma; // standard average gamma const static double sRGBGammaCurve; // 2.4 in the curve const static double eps, eps_max, kappa, epskap; + const static float epsf, kappaf; const static float D50x, D50z; const static double u0, v0; - + constexpr static float c1By116 = 0.00862068965517241379310344827586f; // 1/116 + constexpr static float c16By116 = 0.13793103448275862068965517241379f; // 16/116 static cmsToneCurve* linearGammaTRC; static LUTf cachef; + static LUTf cachefy; static LUTf gamma2curve; // look-up tables for the standard srgb gamma and its inverse (filled by init()) @@ -184,16 +187,16 @@ public: * @brief Convert red/green/blue to hue/saturation/luminance * @param profile output profile name * @param profileW working profile name - * @param r red channel [0 ; 65535] - * @param g green channel [0 ; 65535] - * @param b blue channel [0 ; 65535] + * @param r red channel [0 ; 1] + * @param g green channel [0 ; 1] + * @param b blue channel [0 ; 1] * @param L Lab L channel [0 ; 1] (return value) - * @param a Lab a channel [0 ; 1] (return value) + * @param a Lab a channel [0 ; 1] (return value) * @param b Lab b channel [0; 1] (return value) * @param workingSpace true: compute the Lab value using the Working color space ; false: use the Output color space */ - static void rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace); - + // do not use this function in a loop. It really eats processing time caused by Glib::ustring comparisons + static void rgb2lab01 (const Glib::ustring &profile, const Glib::ustring &profileW, float r, float g, float b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace); /** * @brief Convert red/green/blue to hue/saturation/luminance @@ -327,6 +330,17 @@ public: */ static void rgb2hsv (float r, float g, float b, float &h, float &s, float &v); + /** + * @brief Convert red green blue to hue saturation value + * @param r red channel [0 ; 1] + * @param g green channel [0 ; 1] + * @param b blue channel [0 ; 1] + * @param h hue channel [0 ; 1] (return value) + * @param s saturation channel [0 ; 1] (return value) + * @param v value channel [0 ; 1] (return value) + */ + static void rgb2hsv01 (float r, float g, float b, float &h, float &s, float &v); + static inline float rgb2s(float r, float g, float b) // fast version if only saturation is needed { float var_Min = min(r, g, b); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index a76d4cd84..1a545bdf5 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -3877,8 +3877,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer // Luminosity after // only Luminance in Lab float newy = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; - float newfy = newy < MAXVALF ? Color::cachef[newy] : 327.68f * std::cbrt (newy / MAXVALF); - float L_2 = 116.0f * newfy - 5242.88f; + float L_2 = newy <= MAXVALF ? Color::cachefy[newy] : 327.68f * (116.f * xcbrtf(newy / MAXVALF) - 16.f); //gamut control if (settings->rgbcurveslumamode_gamut) { @@ -5775,7 +5774,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW float aprov1 = Chprov2 * sincosval.y; float bprov1 = Chprov2 * sincosval.x; - float fy = (0.00862069f * Lprov1 ) + 0.137932f; + float fy = (Color::c1By116 * Lprov1 ) + Color::c1By116; float fx = (0.002f * aprov1) + fy; float fz = fy - (0.005f * bprov1); diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index ba2fe6ffb..853b8ae53 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -318,7 +318,7 @@ Imagefloat* ImProcFunctions::lab2rgbOut (LabImage* lab, int cx, int cy, int cw, for (int j = cx; j < cx + cw; j++) { - float fy = (0.0086206897f * rL[j]) / 327.68f + 0.1379310345f; // (L+16)/116 + float fy = (Color::c1By116 * rL[j]) / 327.68f + Color::c16By116; // (L+16)/116 float fx = (0.002f * ra[j]) / 327.68f + fy; float fz = fy - (0.005f * rb[j]) / 327.68f; float LL = rL[j] / 327.68f; diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index f17d5d9b1..d7fb0da97 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -700,7 +700,7 @@ void ImProcFunctions::vibrance (LabImage* lab) aprovn = Chprov * sincosval.y; bprovn = Chprov * sincosval.x; - float fyy = (0.00862069f * Lprov ) + 0.137932f; + float fyy = (Color::c1By116 * Lprov ) + Color::c16By116; float fxx = (0.002f * aprovn) + fyy; float fzz = fyy - (0.005f * bprovn); float xx_ = 65535.f * Color::f2xyz (fxx) * Color::D50x; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 51e288951..c713b51a8 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -476,7 +476,7 @@ void HistogramRGBArea::updateFreeze (bool f) return; } -void HistogramRGBArea::updateBackBuffer (int r, int g, int b, Glib::ustring profile, Glib::ustring profileW) +void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) { if (!get_realized () || frozen || !showMode) { return; @@ -531,7 +531,7 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, Glib::ustring prof if(needLuma || needChroma) { float Lab_L, Lab_a, Lab_b; - rgb2lab( profile, profileW, r, g, b, Lab_L, Lab_a, Lab_b); + rtengine::Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, Lab_L, Lab_a, Lab_b, options.rtSettings.HistogramWorking); if (needLuma) { // Luma @@ -557,153 +557,6 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, Glib::ustring prof setDirty(false); } -void HistogramRGBArea::rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b) -{ - double xyz_rgb[3][3]; - const double ep = 216.0 / 24389.0; - const double ka = 24389.0 / 27.0; - - double var_R = r / 255.0; - double var_G = g / 255.0; - double var_B = b / 255.0; - - Glib::ustring profileCalc; - profileCalc = "sRGB"; //default - - if(options.rtSettings.HistogramWorking) { - profileCalc = profileW; //display working - } - - else {// if you want display = output space - if (profile == "RT_sRGB" || profile == "RT_sRGB_gBT709" || profile == "RT_sRGB_g10") { - profileCalc = "sRGB"; - } - - if (profile == "ProPhoto" || profile == "RT_Large_gBT709" || profile == "RT_Large_g10" || profile == "RT_Large_gsRGB") { - profileCalc = "ProPhoto"; - } - - if (profile == "AdobeRGB1998" || profile == "RT_Medium_gsRGB") { - profileCalc = "Adobe RGB"; - } - - if (profile == "WideGamutRGB") { - profileCalc = "WideGamut"; - } - } - - if(options.rtSettings.HistogramWorking) {//display working - if (profileW == "sRGB") { //apply sRGB inverse gamma - - if ( var_R > 0.04045 ) { - var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); - } else { - var_R = var_R / 12.92; - } - - if ( var_G > 0.04045 ) { - var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); - } else { - var_G = var_G / 12.92; - } - - if ( var_B > 0.04045 ) { - var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); - } else { - var_B = var_B / 12.92; - } - } else if (profileW == "ProPhoto") { // apply inverse gamma 1.8 - var_R = pow ( var_R, 1.8); - var_G = pow ( var_G, 1.8); - var_B = pow ( var_B, 1.8); - } else { // apply inverse gamma 2.2 - var_R = pow ( var_R, 2.2); - var_G = pow ( var_G, 2.2); - var_B = pow ( var_B, 2.2); - } - } else { //display outout profile - - if (profile == "RT_sRGB" || profile == "RT_Large_gsRGB" || profile == "RT_Medium_gsRGB") { //apply sRGB inverse gamma - if ( var_R > 0.04045 ) { - var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); - } else { - var_R = var_R / 12.92; - } - - if ( var_G > 0.04045 ) { - var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); - } else { - var_G = var_G / 12.92; - } - - if ( var_B > 0.04045 ) { - var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve); - } else { - var_B = var_B / 12.92; - } - } - - else if (profile == "RT_sRGB_gBT709" || profile == "RT_Large_gBT709") { // - if ( var_R > 0.0795 ) { - var_R = pow ( ( ( var_R + 0.0954 ) / 1.0954 ), 2.2); - } else { - var_R = var_R / 4.5; - } - - if ( var_G > 0.0795 ) { - var_G = pow ( ( ( var_G + 0.0954 ) / 1.0954 ), 2.2); - } else { - var_G = var_G / 4.5; - } - - if ( var_B > 0.0795 ) { - var_B = pow ( ( ( var_B + 0.0954 ) / 1.0954 ), 2.2); - } else { - var_B = var_B / 4.5; - } - - } else if (profile == "ProPhoto") { // apply inverse gamma 1.8 - - var_R = pow ( var_R, 1.8); - var_G = pow ( var_G, 1.8); - var_B = pow ( var_B, 1.8); - } else if (profile == "RT_sRGB_g10" || profile == "RT_Large_g10") { // apply inverse gamma 1.8 - - var_R = pow ( var_R, 1.); - var_G = pow ( var_G, 1.); - var_B = pow ( var_B, 1.); - } - - else {// apply inverse gamma 2.2 - var_R = pow ( var_R, 2.2); - var_G = pow ( var_G, 2.2); - var_B = pow ( var_B, 2.2); - } - } - - // TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileW); - - TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileCalc); - - for (int m = 0; m < 3; m++) - for (int n = 0; n < 3; n++) { - xyz_rgb[m][n] = wprof[m][n]; - } - - double varxx, varyy, varzz; - double var_X = ( xyz_rgb[0][0] * var_R + xyz_rgb[0][1] * var_G + xyz_rgb[0][2] * var_B ) / Color::D50x; - double var_Y = ( xyz_rgb[1][0] * var_R + xyz_rgb[1][1] * var_G + xyz_rgb[1][2] * var_B ) ; - double var_Z = ( xyz_rgb[2][0] * var_R + xyz_rgb[2][1] * var_G + xyz_rgb[2][2] * var_B ) / Color::D50z; - - varxx = var_X > ep ? cbrt(var_X) : ( ka * var_X + 16.0) / 116.0 ; - varyy = var_Y > ep ? cbrt(var_Y) : ( ka * var_Y + 16.0) / 116.0 ; - varzz = var_Z > ep ? cbrt(var_Z) : ( ka * var_Z + 16.0) / 116.0 ; - LAB_l = ( 116 * varyy ) - 16; - LAB_a = 500 * ( varxx - varyy ); - LAB_b = 200 * ( varyy - varzz ); - -} - void HistogramRGBArea::update (int valh, int rh, int gh, int bh) { diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 25fa15c23..0ce62956c 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -76,7 +76,7 @@ public: HistogramRGBArea(); ~HistogramRGBArea(); - void updateBackBuffer (int r, int g, int b, Glib::ustring profile = "", Glib::ustring profileW = ""); + void updateBackBuffer (int r, int g, int b, const Glib::ustring &profile = "", const Glib::ustring &profileW = ""); void updateFreeze (bool f); bool getFreeze (); bool getShow (); @@ -92,7 +92,6 @@ public: bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr); bool on_button_press_event (GdkEventButton* event); private: - void rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b); Gtk::SizeRequestMode get_request_mode_vfunc () const; void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const; void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const; diff --git a/rtgui/lockablecolorpicker.cc b/rtgui/lockablecolorpicker.cc index d10dfb438..859057e2c 100644 --- a/rtgui/lockablecolorpicker.cc +++ b/rtgui/lockablecolorpicker.cc @@ -277,8 +277,8 @@ void LockableColorPicker::setRGB (const float R, const float G, const float B, c gpreview = previewG; bpreview = previewB; - rtengine::Color::rgb2hsv(r*65535.f, g*65535.f, b*65535.f, hue, sat, val); - rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 65535.f, g * 65535.f, b * 65535.f, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works? + rtengine::Color::rgb2hsv01(r, g, b, hue, sat, val); + rtengine::Color::rgb2lab01(*outputProfile, *workingProfile, r, g, b, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works? if (validity != Validity::OUTSIDE) { setDirty(true); diff --git a/rtgui/navigator.cc b/rtgui/navigator.cc index 7222436b6..7f159861d 100644 --- a/rtgui/navigator.cc +++ b/rtgui/navigator.cc @@ -290,13 +290,13 @@ void Navigator::pointerMoved (bool validPos, Glib::ustring profile, Glib::ustrin G->set_text (s2); B->set_text (s3); - Color::rgb2hsv (r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, h, s, v); + Color::rgb2hsv01(r / 255.f, g / 255.f, b / 255.f, h, s, v); getHSVText (h, s, v, s1, s2, s3); H->set_text (s1); S->set_text (s2); V->set_text (s3); - Color::rgb2lab (profile, profileW, r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, LAB_l, LAB_a, LAB_b, options.rtSettings.HistogramWorking); // TODO: Really sure this function works? + Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, LAB_l, LAB_a, LAB_b, options.rtSettings.HistogramWorking); // TODO: Really sure this function works? getLABText (LAB_l, LAB_a, LAB_b, s1, s2, s3); LAB_L->set_text (s1); LAB_A->set_text (s2);