From b50de693a0f015f406a6a4ee307ed8673057fabf Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 9 Jun 2016 21:49:13 +0200 Subject: [PATCH 1/7] Replace expensive dcp srgb gamma calculations by access to lookup table => no difference in output and much faster --- rtengine/color.cc | 15 ++++++++++----- rtengine/color.h | 2 ++ rtengine/dcp.cc | 7 +++++-- rtengine/improcfun.cc | 1 + 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/rtengine/color.cc b/rtengine/color.cc index 4e180690e..c5874d110 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -38,7 +38,9 @@ LUTf Color::gamma2curve; LUTf Color::gammatab; LUTuc Color::gammatabThumb; LUTf Color::igammatab_srgb; +LUTf Color::igammatab_srgb1; LUTf Color::gammatab_srgb; +LUTf Color::gammatab_srgb1; // LUTf Color::igammatab_709; // LUTf Color::gammatab_709; LUTf Color::igammatab_55; @@ -143,7 +145,9 @@ void Color::init () gammatabThumb(maxindex, 0); igammatab_srgb(maxindex, 0); + igammatab_srgb1(maxindex, 0); gammatab_srgb(maxindex, 0); + gammatab_srgb1(maxindex, 0); igammatab_55(maxindex, 0); gammatab_55(maxindex, 0); igammatab_4(maxindex, 0); @@ -187,19 +191,20 @@ void Color::init () { for (int i = 0; i < maxindex; i++) { - gammatab_srgb[i] = 65535.0 * gamma2(i / 65535.0); + gammatab_srgb[i] = gammatab_srgb1[i] = gamma2(i / 65535.0); } - + gammatab_srgb *= 65535.f; gamma2curve.share(gammatab_srgb, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); // shares the buffer with gammatab_srgb but has different clip flags } #ifdef _OPENMP #pragma omp section #endif - +{ for (int i = 0; i < maxindex; i++) { - igammatab_srgb[i] = 65535.0 * igamma2 (i / 65535.0); + igammatab_srgb[i] = igammatab_srgb1[i] = igamma2 (i / 65535.0); } - + igammatab_srgb *= 65535.f; +} #ifdef _OPENMP #pragma omp section #endif diff --git a/rtengine/color.h b/rtengine/color.h index be7740e2a..31c361c86 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -129,7 +129,9 @@ public: // look-up tables for the standard srgb gamma and its inverse (filled by init()) static LUTf igammatab_srgb; + static LUTf igammatab_srgb1; static LUTf gammatab_srgb; + static LUTf gammatab_srgb1; static LUTf igammatab_55; static LUTf gammatab_55; static LUTf igammatab_4; diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 775428a4e..a42c80bf6 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -25,6 +25,8 @@ #include "rawimagesource.h" #include "improcfun.h" #include "rt_math.h" +#define BENCHMARK +#include "StopWatch.h" using namespace rtengine; using namespace rtexif; @@ -1022,6 +1024,7 @@ void DCPProfile::apply( bool apply_look_table ) const { + BENCHFUN const TMatrix work_matrix = iccStore->workingSpaceInverseMatrix(working_space); Matrix xyz_cam; // Camera RGB to XYZ D50 matrix @@ -1715,7 +1718,7 @@ void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector Date: Thu, 9 Jun 2016 23:42:32 +0200 Subject: [PATCH 2/7] Speedup for DCPProfile::apply --- rtengine/color.h | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/rtengine/color.h b/rtengine/color.h index 31c361c86..1e1cb9679 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -230,7 +230,36 @@ public: * @param v value channel [0 ; 1] (return value) */ static void rgb2hsv (float r, float g, float b, float &h, float &s, float &v); + + static inline void rgb2hsvdcp(float r, float g, float b, float &h, float &s, float &v) + { + float var_Min = min(r, g, b); + float var_Max = max(r, g, b); + float del_Max = var_Max - var_Min; + v = var_Max / 65535.f; + + if (fabsf(del_Max) < 0.00001f) { + h = 0.f; + 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; + } + + if ( h < 0.f ) { + h += 6.f; + } else if ( h > 6.f ) { + h -= 6.f; + } + } + } /** * @brief Convert hue saturation value in red green blue @@ -242,6 +271,45 @@ public: * @param b blue channel [0 ; 65535] (return value) */ static void hsv2rgb (float h, float s, float v, float &r, float &g, float &b); + +static inline void hsv2rgbdcp (float h, float s, float v, float &r, float &g, float &b) +{ + // special version for dcp which saves 1 division (in caller) and six multiplications (inside this function) + int i = h; // sector 0 to 5, floor() is very slow, and h is always >0 + float f = h - i; // fractional part of h + + v *= 65535.f; + float vs = v * s; + float p = v - vs; + float q = v - f * vs; + float t = p + v - q; + + if (i == 1) { + r = q; + g = v; + b = p; + } else if (i == 2) { + r = p; + g = v; + b = t; + } else if (i == 3) { + r = p; + g = q; + b = v; + } else if (i == 4) { + r = t; + g = p; + b = v; + } else if (i == 5) { + r = v; + g = p; + b = q; + } else { /*i==(0|6)*/ + r = v; + g = t; + b = p; + } +} static void hsv2rgb (float h, float s, float v, int &r, int &g, int &b); From 3aa9947a37a2ae4d66ff0f9b9e60488a873309db Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 9 Jun 2016 23:43:55 +0200 Subject: [PATCH 3/7] Forgot to add dcp.cc with last commit --- rtengine/dcp.cc | 41 ++++++++--------------------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index a42c80bf6..722fec7cc 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -1071,7 +1071,7 @@ void DCPProfile::apply( } } else { // LUT available --> Calculate matrix for conversion raw>ProPhoto - double pro_photo[3][3] = {}; + float pro_photo[3][3] = {}; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { @@ -1081,7 +1081,7 @@ void DCPProfile::apply( } } - double work[3][3] = {}; + float work[3][3] = {}; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { @@ -1093,56 +1093,31 @@ void DCPProfile::apply( // Convert to ProPhoto and apply LUT #ifdef _OPENMP - #pragma omp parallel for + #pragma omp parallel for schedule(dynamic,16) #endif for (int y = 0; y < img->height; ++y) { - float h, s, v, hs, ss, vs; - for (int x = 0; x < img->width; x++) { float newr = pro_photo[0][0] * img->r(y, x) + pro_photo[0][1] * img->g(y, x) + pro_photo[0][2] * img->b(y, x); float newg = pro_photo[1][0] * img->r(y, x) + pro_photo[1][1] * img->g(y, x) + pro_photo[1][2] * img->b(y, x); float newb = pro_photo[2][0] * img->r(y, x) + pro_photo[2][1] * img->g(y, x) + pro_photo[2][2] * img->b(y, x); // If point is in negative area, just the matrix, but not the LUT - if ( - ( - apply_hue_sat_map - || apply_look_table - ) - && newr >= 0 - && newg >= 0 - && newb >= 0 - ) { + if (newr >= 0 && newg >= 0 && newb >= 0) { float h; float s; float v; - Color::rgb2hsv(newr, newg, newb, h , s, v); - h *= 6.0f; // RT calculates in [0,1] + Color::rgb2hsvdcp(newr, newg, newb, h , s, v); - if (apply_hue_sat_map) { - hsdApply(delta_info, delta_base, h, s, v); - } - - if (apply_look_table) { - hsdApply(look_info, look_table, h, s, v); - } + hsdApply(delta_info, delta_base, h, s, v); // RT range correction if (h < 0.0f) { h += 6.0f; - } - - if (h >= 6.0f) { + } else if (h >= 6.0f) { h -= 6.0f; } - h /= 6.f; - - Color::hsv2rgb(h, s, v, newr, newg, newb); - } - - if (use_tone_curve) { - tone_curve.Apply(newr, newg, newb); + Color::hsv2rgbdcp(h, s, v, newr, newg, newb); } img->r(y, x) = work[0][0] * newr + work[0][1] * newg + work[0][2] * newb; From eedb9f39bcf8f04fdd2d99f923a3aab5c9738781 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 10 Jun 2016 00:20:03 +0200 Subject: [PATCH 4/7] Another 'small' speedup for dcp --- rtengine/dcp.cc | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 722fec7cc..19ccc2359 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -420,8 +420,8 @@ void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint) } struct DCPProfile::ApplyState::Data { - double pro_photo[3][3]; - double work[3][3]; + float pro_photo[3][3]; + float work[3][3]; bool already_pro_photo; bool use_tone_curve; bool apply_look_table; @@ -1200,11 +1200,9 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int float g = gc[y * tile_width + x]; float b = bc[y * tile_width + x]; - if (exp_scale != 1.0) { - r *= exp_scale; - g *= exp_scale; - b *= exp_scale; - } + r *= exp_scale; + g *= exp_scale; + b *= exp_scale; float newr, newg, newb; @@ -1225,8 +1223,7 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int if (as_in.data->apply_look_table) { float h, s, v; - Color::rgb2hsv(newr, newg, newb, h, s, v); - h *= 6.f; // RT calculates in [0,1] + Color::rgb2hsvdcp(newr, newg, newb, h, s, v); hsdApply(look_info, look_table, h, s, v); s = CLIP01(s); @@ -1235,14 +1232,11 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int // RT range correction if (h < 0.0f) { h += 6.0f; - } - - if (h >= 6.0f) { + } else if (h >= 6.0f) { h -= 6.0f; } - h /= 6.f; - Color::hsv2rgb( h, s, v, newr, newg, newb); + Color::hsv2rgbdcp( h, s, v, newr, newg, newb); } if (as_in.data->use_tone_curve) { From b8749f8484555ab255ef5a53df0ec70164f86d7f Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 10 Jun 2016 18:30:07 +0200 Subject: [PATCH 5/7] dcp speedup cleanup --- rtengine/color.h | 129 +++++++++++++++++++++---------------- rtengine/dcp.cc | 110 +++++++++++++------------------ rtengine/dcp.h | 4 +- rtengine/rawimagesource.cc | 2 +- 4 files changed, 120 insertions(+), 125 deletions(-) diff --git a/rtengine/color.h b/rtengine/color.h index 1e1cb9679..bf42140c5 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -230,34 +230,41 @@ public: * @param v value channel [0 ; 1] (return value) */ static void rgb2hsv (float r, float g, float b, float &h, float &s, float &v); - - static inline void rgb2hsvdcp(float r, float g, float b, float &h, float &s, float &v) + + static inline bool rgb2hsvdcp(float r, float g, float b, float &h, float &s, float &v) { float var_Min = min(r, g, b); - float var_Max = max(r, g, b); - float del_Max = var_Max - var_Min; - v = var_Max / 65535.f; - if (fabsf(del_Max) < 0.00001f) { - h = 0.f; - s = 0.f; + if(var_Min < 0.f) { + return false; } else { - s = del_Max / var_Max; + float var_Max = max(r, g, b); + float del_Max = var_Max - var_Min; + v = var_Max / 65535.f; - 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; + if (fabsf(del_Max) < 0.00001f) { + h = 0.f; + 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; + } + + if ( h < 0.f ) { + h += 6.f; + } else if ( h > 6.f ) { + h -= 6.f; + } } - if ( h < 0.f ) { - h += 6.f; - } else if ( h > 6.f ) { - h -= 6.f; - } + return true; } } @@ -272,44 +279,56 @@ public: */ static void hsv2rgb (float h, float s, float v, float &r, float &g, float &b); -static inline void hsv2rgbdcp (float h, float s, float v, float &r, float &g, float &b) -{ - // special version for dcp which saves 1 division (in caller) and six multiplications (inside this function) - int i = h; // sector 0 to 5, floor() is very slow, and h is always >0 - float f = h - i; // fractional part of h + static inline void hsv2rgbdcp (float h, float s, float v, float &r, float &g, float &b) + { + // special version for dcp which saves 1 division (in caller) and six multiplications (inside this function) + int sector = h; // sector 0 to 5, floor() is very slow, and h is always >0 + float f = h - sector; // fractional part of h - v *= 65535.f; - float vs = v * s; - float p = v - vs; - float q = v - f * vs; - float t = p + v - q; + v *= 65535.f; + float vs = v * s; + float p = v - vs; + float q = v - f * vs; + float t = p + v - q; - if (i == 1) { - r = q; - g = v; - b = p; - } else if (i == 2) { - r = p; - g = v; - b = t; - } else if (i == 3) { - r = p; - g = q; - b = v; - } else if (i == 4) { - r = t; - g = p; - b = v; - } else if (i == 5) { - r = v; - g = p; - b = q; - } else { /*i==(0|6)*/ - r = v; - g = t; - b = p; + switch (sector) { + case 1: + r = q; + g = v; + b = p; + break; + + case 2: + r = p; + g = v; + b = t; + break; + + case 3: + r = p; + g = q; + b = v; + break; + + case 4: + r = t; + g = p; + b = v; + break; + + case 5: + r = v; + g = p; + b = q; + break; + + default: + r = v; + g = t; + b = p; + } } -} + static void hsv2rgb (float h, float s, float v, int &r, int &g, int &b); diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 19ccc2359..02cc8f0f4 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -35,25 +35,6 @@ namespace { // This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here -float srgbGammaForward(float x) -{ - return - x <= 0.0031308f - ? x * 12.92f - : x > 1.0f - ? 1.0f + (x - 1.0f) * (1.055f * (1.0f / 2.4f)) // Linear extension - : 1.055f * pow(x, 1.0f / 2.4f) - 0.055f; -} - -float srgbGammaInverse(float y) -{ - return - y <= 0.0031308f * 12.92f - ? y * (1.0f / 12.92f) - : y > 1.0f - ? 1.0f + (y - 1.0f) / (1.055f * (1.0f / 2.4f)) - : pow ((y + 0.055f) * (1.0f / 1.055f), 2.4f); -} void invert3x3(const DCPProfile::Matrix& a, DCPProfile::Matrix& b) { @@ -143,10 +124,11 @@ void mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple& // Use the linearized Bradford adaptation matrix const DCPProfile::Matrix mb = {{ - { 0.8951, 0.2664, -0.1614 }, - { -0.7502, 1.7135, 0.0367 }, - { 0.0389, -0.0685, 1.0296 } - }}; + { 0.8951, 0.2664, -0.1614 }, + { -0.7502, 1.7135, 0.0367 }, + { 0.0389, -0.0685, 1.0296 } + } + }; DCPProfile::Triple w1; multiply3x3_v3(mb, white1, w1); @@ -735,13 +717,13 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : Tag* tag = tagDir->getTag(toUnderlying(TagKey::CALIBRATION_ILLUMINANT_1)); light_source_1 = tag - ? tag->toInt(0, rtexif::SHORT) - : -1; + ? tag->toInt(0, rtexif::SHORT) + : -1; tag = tagDir->getTag(toUnderlying(TagKey::CALIBRATION_ILLUMINANT_2)); light_source_2 = tag - ? tag->toInt(0, rtexif::SHORT) - : -1; + ? tag->toInt(0, rtexif::SHORT) + : -1; temperature_1 = calibrationIlluminantToTemperature(light_source_1); temperature_2 = calibrationIlluminantToTemperature(light_source_2); @@ -813,8 +795,8 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Precalculated constants for table application look_info.pc.h_scale = look_info.hue_divisions < 2 - ? 0.0f - : static_cast(look_info.hue_divisions) / 6.0f; + ? 0.0f + : static_cast(look_info.hue_divisions) / 6.0f; look_info.pc.s_scale = look_info.sat_divisions - 1; look_info.pc.v_scale = look_info.val_divisions - 1; look_info.pc.max_hue_index0 = look_info.hue_divisions - 1; @@ -847,8 +829,8 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : delta_info.pc.h_scale = delta_info.hue_divisions < 2 - ? 0.0f - : static_cast(delta_info.hue_divisions) / 6.0f; + ? 0.0f + : static_cast(delta_info.hue_divisions) / 6.0f; delta_info.pc.s_scale = delta_info.sat_divisions - 1; delta_info.pc.v_scale = delta_info.val_divisions - 1; delta_info.pc.max_hue_index0 = delta_info.hue_divisions - 1; @@ -868,8 +850,8 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : for (int col = 0; col < 3; ++col) { color_matrix_2[row][col] = tag - ? tag->toDouble((col + row * 3) * 8) - : color_matrix_1[row][col]; + ? tag->toDouble((col + row * 3) * 8) + : color_matrix_1[row][col]; } } @@ -1019,9 +1001,7 @@ void DCPProfile::apply( const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, - bool use_tone_curve, - bool apply_hue_sat_map, - bool apply_look_table + bool apply_hue_sat_map ) const { BENCHFUN @@ -1036,15 +1016,9 @@ void DCPProfile::apply( apply_hue_sat_map = false; } - if (look_table.empty()) { - apply_look_table = false; - } - - use_tone_curve = use_tone_curve && tone_curve; - - if (!apply_hue_sat_map && !apply_look_table && !use_tone_curve) { - // The fast path: No LUT and not tone curve --> Calculate matrix for direct conversion raw>working space - double mat[3][3] = {}; + if (!apply_hue_sat_map) { + // The fast path: No LUT --> Calculate matrix for direct conversion raw -> working space + float mat[3][3] = {}; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { @@ -1058,6 +1032,7 @@ void DCPProfile::apply( #ifdef _OPENMP #pragma omp parallel for #endif + for (int y = 0; y < img->height; ++y) { for (int x = 0; x < img->width; x++) { const float& newr = mat[0][0] * img->r(y, x) + mat[0][1] * img->g(y, x) + mat[0][2] * img->b(y, x); @@ -1095,18 +1070,19 @@ void DCPProfile::apply( #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif + for (int y = 0; y < img->height; ++y) { for (int x = 0; x < img->width; x++) { float newr = pro_photo[0][0] * img->r(y, x) + pro_photo[0][1] * img->g(y, x) + pro_photo[0][2] * img->b(y, x); float newg = pro_photo[1][0] * img->r(y, x) + pro_photo[1][1] * img->g(y, x) + pro_photo[1][2] * img->b(y, x); float newb = pro_photo[2][0] * img->r(y, x) + pro_photo[2][1] * img->g(y, x) + pro_photo[2][2] * img->b(y, x); - // If point is in negative area, just the matrix, but not the LUT - if (newr >= 0 && newg >= 0 && newb >= 0) { - float h; - float s; - float v; - Color::rgb2hsvdcp(newr, newg, newb, h , s, v); + // If point is in negative area, just the matrix, but not the LUT. This is checked inside Color::rgb2hsvdcp + float h; + float s; + float v; + + if(Color::rgb2hsvdcp(newr, newg, newb, h , s, v)) { hsdApply(delta_info, delta_base, h, s, v); @@ -1178,11 +1154,10 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int #define FCLIP(a) ((a)>0.0?((a)<65535.5?(a):65535.5):0.0) #define CLIP01(a) ((a)>0?((a)<1?(a):1):0) - float exp_scale = 1.0; - exp_scale *= as_in.data->bl_scale; + float exp_scale = as_in.data->bl_scale; if (!as_in.data->use_tone_curve && !as_in.data->apply_look_table) { - if (exp_scale == 1.0) { + if (exp_scale == 1.f) { return; } @@ -1370,10 +1345,11 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu invert3x3(cam_wb_matrix, cam_xyz); Matrix cam_rgb; constexpr Matrix xyz_srgb = {{ - {xyz_sRGB[0][0], xyz_sRGB[0][1], xyz_sRGB[0][2]}, - {xyz_sRGB[1][0], xyz_sRGB[1][1], xyz_sRGB[1][2]}, - {xyz_sRGB[2][0], xyz_sRGB[2][1], xyz_sRGB[2][2]} - }}; + {xyz_sRGB[0][0], xyz_sRGB[0][1], xyz_sRGB[0][2]}, + {xyz_sRGB[1][0], xyz_sRGB[1][1], xyz_sRGB[1][2]}, + {xyz_sRGB[2][0], xyz_sRGB[2][1], xyz_sRGB[2][2]} + } + }; multiply3x3(cam_xyz, xyz_srgb, cam_rgb); double camwb_red = cam_rgb[0][0] * r + cam_rgb[0][1] * g + cam_rgb[0][2] * b; double camwb_green = cam_rgb[1][0] * r + cam_rgb[1][1] * g + cam_rgb[1][2] * b; @@ -1499,10 +1475,11 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu multiply3x3_v3(color_matrix, white_xyz, camera_white); const Matrix white_diag = {{ - {camera_white[0], 0, 0}, - {0, camera_white[1], 0}, - {0, 0, camera_white[2]} - }}; + {camera_white[0], 0, 0}, + {0, camera_white[1], 0}, + {0, 0, camera_white[2]} + } + }; Matrix white_diag_inv; invert3x3(white_diag, white_diag_inv); @@ -1594,14 +1571,15 @@ std::vector DCPProfile::makeHueSatMap(const ColorTemp& wh const bool reverse = temperature_1 > temperature_2; const double t1 = reverse - ? temperature_2 - : temperature_1; + ? temperature_2 + : temperature_1; const double t2 = reverse - ? temperature_1 - : temperature_2; + ? temperature_1 + : temperature_2; double mix; + if (white_balance.getTemp() <= t1) { mix = 1.0; } else if (white_balance.getTemp() >= t2) { diff --git a/rtengine/dcp.h b/rtengine/dcp.h index ace32869a..7db44950d 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -80,9 +80,7 @@ public: const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, - bool use_tone_curve = false, - bool apply_hue_sat_map = true, - bool apply_look_table = false + bool apply_hue_sat_map = true ) const; void setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out); void step2ApplyTile(float* r, float* g, float* b, int width, int height, int tile_width, const ApplyState& as_in) const; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 1c04f1af3..218ba9fe2 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -3737,7 +3737,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam {camMatrix[1][0], camMatrix[1][1], camMatrix[1][2]}, {camMatrix[2][0], camMatrix[2][1], camMatrix[2][2]} }}; - dcpProf->apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul_row, cam_matrix, false, cmp.applyHueSatMap, false); + dcpProf->apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul_row, cam_matrix, cmp.applyHueSatMap); return; } From 97dae796c6b4e65ddbc4ceb1d387cc9a5303b96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Sun, 12 Jun 2016 12:07:15 +0200 Subject: [PATCH 6/7] Additional cleanups for `dcp.*` (#3343) --- rtengine/dcp.cc | 367 ++++++++++++++++++----------------------- rtengine/dcp.h | 8 +- rtengine/iccmatrices.h | 202 +++++++++++++++-------- 3 files changed, 295 insertions(+), 282 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 02cc8f0f4..f02ba8aaa 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ +#include #include #include "dcp.h" @@ -36,104 +37,92 @@ namespace // This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here -void invert3x3(const DCPProfile::Matrix& a, DCPProfile::Matrix& b) +DCPProfile::Matrix invert3x3(const DCPProfile::Matrix& a) { - const double& a00 = a[0][0]; - const double& a01 = a[0][1]; - const double& a02 = a[0][2]; - const double& a10 = a[1][0]; - const double& a11 = a[1][1]; - const double& a12 = a[1][2]; - const double& a20 = a[2][0]; - const double& a21 = a[2][1]; - const double& a22 = a[2][2]; + const double res00 = a[1][1] * a[2][2] - a[2][1] * a[1][2]; + const double res10 = a[2][0] * a[1][2] - a[1][0] * a[2][2]; + const double res20 = a[1][0] * a[2][1] - a[2][0] * a[1][1]; - double temp[3][3]; + const double det = a[0][0] * res00 + a[0][1] * res10 + a[0][2] * res20; - temp[0][0] = a11 * a22 - a21 * a12; - temp[0][1] = a21 * a02 - a01 * a22; - temp[0][2] = a01 * a12 - a11 * a02; - temp[1][0] = a20 * a12 - a10 * a22; - temp[1][1] = a00 * a22 - a20 * a02; - temp[1][2] = a10 * a02 - a00 * a12; - temp[2][0] = a10 * a21 - a20 * a11; - temp[2][1] = a20 * a01 - a00 * a21; - temp[2][2] = a00 * a11 - a10 * a01; - - const double det = a00 * temp[0][0] + a01 * temp[1][0] + a02 * temp[2][0]; - - if (fabs(det) < 1.0e-10) { - abort(); // Can't be inverted, we shouldn't be dealing with such matrices + if (std::fabs(det) < 1.0e-10) { + std::cerr << "DCP matrix cannot be inverted! Expect weird output." << std::endl; + return a; } - for (int j = 0; j < 3; ++j) { - for (int k = 0; k < 3; ++k) { - b[j][k] = temp[j][k] / det; - } - } + DCPProfile::Matrix res; + + res[0][0] = res00 / det; + res[0][1] = (a[2][1] * a[0][2] - a[0][1] * a[2][2]) / det; + res[0][2] = (a[0][1] * a[1][2] - a[1][1] * a[0][2]) / det; + res[1][0] = res10 / det; + res[1][1] = (a[0][0] * a[2][2] - a[2][0] * a[0][2]) / det; + res[1][2] = (a[1][0] * a[0][2] - a[0][0] * a[1][2]) / det; + res[2][0] = res20 / det; + res[2][1] = (a[2][0] * a[0][1] - a[0][0] * a[2][1]) / det; + res[2][2] = (a[0][0] * a[1][1] - a[1][0] * a[0][1]) / det; + + return res; } -void multiply3x3(const DCPProfile::Matrix& a, const DCPProfile::Matrix& b, DCPProfile::Matrix& c) +DCPProfile::Matrix multiply3x3(const DCPProfile::Matrix& a, const DCPProfile::Matrix& b) { - // Use temp to support having output same as input - DCPProfile::Matrix m; + DCPProfile::Matrix res; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - m[i][j] = 0; + res[i][j] = 0; for (int k = 0; k < 3; ++k) { - m[i][j] += a[i][k] * b[k][j]; + res[i][j] += a[i][k] * b[k][j]; } } } - c = m; + return res; } -void multiply3x3_v3(const DCPProfile::Matrix& a, const DCPProfile::Triple& b, DCPProfile::Triple& c) +DCPProfile::Triple multiply3x3_v3(const DCPProfile::Matrix& a, const DCPProfile::Triple& b) { - // Use temp to support having output same as input - DCPProfile::Triple m = {}; + DCPProfile::Triple res = {}; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - m[i] += a[i][j] * b[j]; + res[i] += a[i][j] * b[j]; } } - c = m; + return res; } -void mix3x3(const DCPProfile::Matrix& a, double mul_a, const DCPProfile::Matrix& b, double mul_b, DCPProfile::Matrix& c) +DCPProfile::Matrix mix3x3(const DCPProfile::Matrix& a, double mul_a, const DCPProfile::Matrix& b, double mul_b) { - DCPProfile::Matrix m; + DCPProfile::Matrix res; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - m[i][j] = a[i][j] * mul_a + b[i][j] * mul_b; + res[i][j] = a[i][j] * mul_a + b[i][j] * mul_b; } } - c = m; + return res; } -void mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple& white2, DCPProfile::Matrix& b) +DCPProfile::Matrix mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple& white2) { // Code adapted from dng_color_spec::MapWhiteMatrix // Use the linearized Bradford adaptation matrix - const DCPProfile::Matrix mb = {{ + const DCPProfile::Matrix mb = { + { { 0.8951, 0.2664, -0.1614 }, { -0.7502, 1.7135, 0.0367 }, { 0.0389, -0.0685, 1.0296 } } }; - DCPProfile::Triple w1; - multiply3x3_v3(mb, white1, w1); - DCPProfile::Triple w2; - multiply3x3_v3(mb, white2, w2); + DCPProfile::Triple w1 = multiply3x3_v3(mb, white1); + DCPProfile::Triple w2 = multiply3x3_v3(mb, white2); // Negative white coordinates are kind of meaningless. w1[0] = std::max(w1[0], 0.0); @@ -149,44 +138,46 @@ void mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple& a[1][1] = std::max(0.1, std::min(w1[1] > 0.0 ? w2[1] / w1[1] : 10.0, 10.0)); a[2][2] = std::max(0.1, std::min(w1[2] > 0.0 ? w2[2] / w1[2] : 10.0, 10.0)); - DCPProfile::Matrix temp; - invert3x3(mb, temp); - multiply3x3(temp, a, temp); - multiply3x3(temp, mb, b); + return multiply3x3(multiply3x3(invert3x3(mb), a), mb); } -void xyzToXy(const DCPProfile::Triple& xyz, double xy[2]) +std::array xyzToXy(const DCPProfile::Triple& xyz) { const double total = xyz[0] + xyz[1] + xyz[2]; - if (total > 0.0) { - xy[0] = xyz[0] / total; - xy[1] = xyz[1] / total; - } else { - xy[0] = 0.3457; - xy[1] = 0.3585; - } + return + total > 0.0 + ? std::array{ + xyz[0] / total, + xyz[1] / total + } + : std::array{ + 0.3457, + 0.3585 + }; } -void xyToXyz(const double xy[2], DCPProfile::Triple& xyz) +DCPProfile::Triple xyToXyz(std::array xy) { - double temp[2] = {xy[0], xy[1]}; - // Restrict xy coord to someplace inside the range of real xy coordinates. // This prevents math from doing strange things when users specify // extreme temperature/tint coordinates. - temp[0] = std::max(0.000001, std::min(temp[0], 0.999999)); - temp[1] = std::max(0.000001, std::min(temp[1], 0.999999)); + xy[0] = std::max(0.000001, std::min(xy[0], 0.999999)); + xy[1] = std::max(0.000001, std::min(xy[1], 0.999999)); - if (temp[0] + temp[1] > 0.999999) { - double scale = 0.999999 / (temp[0] + temp[1]); - temp[0] *= scale; - temp[1] *= scale; + const double sum = xy[0] + xy[1]; + + if (sum > 0.999999) { + const double scale = 0.999999 / sum; + xy[0] *= scale; + xy[1] *= scale; } - xyz[0] = temp[0] / temp[1]; - xyz[1] = 1.0; - xyz[2] = (1.0 - temp[0] - temp[1]) / temp[1]; + return { + xy[0] / xy[1], + 1.0, + (1.0 - xy[0] - xy[1]) / xy[1] + }; } double calibrationIlluminantToTemperature(int light) @@ -277,7 +268,7 @@ double calibrationIlluminantToTemperature(int light) } } -void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint) +double xyCoordToTemperature(const std::array& white_xy) { struct Ruvt { double r; @@ -322,8 +313,7 @@ void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint) constexpr double tint_scale = -3000.0; - double temperature = 0; - double computed_tint = 0; + double res = 0; // Convert to uv space. double u = 2.0 * white_xy[0] / (1.5 - white_xy[0] + 6.0 * white_xy[1]); @@ -367,7 +357,7 @@ void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint) } // Interpolate the temperature. - temperature = 1.0e6 / (temp_table[index - 1].r * f + temp_table[index].r * (1.0 - f)); + res = 1.0e6 / (temp_table[index - 1].r * f + temp_table[index].r * (1.0 - f)); // Find delta from black body point to test coordinate. uu = u - (temp_table [index - 1].u * f + temp_table [index].u * (1.0 - f)); @@ -378,9 +368,6 @@ void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint) len = sqrt (du * du + dv * dv); du /= len; dv /= len; - - // Find distance along slope. - computed_tint = (uu * du + vv * dv) * tint_scale; break; } @@ -390,13 +377,7 @@ void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint) last_dv = dv; } - if (temp != nullptr) { - *temp = temperature; - } - - if (tint != nullptr) { - *tint = computed_tint; - } + return res; } } @@ -758,9 +739,8 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : tag = tagDir->getTag(toUnderlying(TagKey::COLOR_MATRIX_1)); if (!tag) { - // FIXME: better error handling - fprintf(stderr, "Bad DCP, no ColorMatrix1\n"); - abort(); + std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl; + return; } has_color_matrix_1 = true; @@ -963,6 +943,11 @@ DCPProfile::~DCPProfile() { } +DCPProfile::operator bool() const +{ + return has_color_matrix_1; +} + bool DCPProfile::getHasToneCurve() const { return has_tone_curve; @@ -1007,8 +992,7 @@ void DCPProfile::apply( BENCHFUN const TMatrix work_matrix = iccStore->workingSpaceInverseMatrix(working_space); - Matrix xyz_cam; // Camera RGB to XYZ D50 matrix - makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant, xyz_cam); + const Matrix xyz_cam = makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant); // Camera RGB to XYZ D50 matrix const std::vector delta_base = makeHueSatMap(white_balance, preferred_illuminant); @@ -1232,7 +1216,7 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int } } -void DCPProfile::findXyztoCamera(const double white_xy[2], int preferred_illuminant, Matrix& xyz_to_camera) const +DCPProfile::Matrix DCPProfile::findXyztoCamera(const std::array& white_xy, int preferred_illuminant) const { bool has_col_1 = has_color_matrix_1; bool has_col_2 = has_color_matrix_2; @@ -1248,17 +1232,14 @@ void DCPProfile::findXyztoCamera(const double white_xy[2], int preferred_illumin } // Mix if we have two matrices - double mix; - Matrix col; - if (has_col_1 && has_col_2) { - double wbtemp; /* Note: We're using DNG SDK reference code for XY to temperature translation to get the exact same mix as the reference code does. */ - xyCoordToTemperature(white_xy, &wbtemp, nullptr); + const double wbtemp = xyCoordToTemperature(white_xy); + double mix; if (wbtemp <= temperature_1) { mix = 1.0; } else if (wbtemp >= temperature_2) { @@ -1270,45 +1251,36 @@ void DCPProfile::findXyztoCamera(const double white_xy[2], int preferred_illumin // Interpolate if (mix >= 1.0) { - col = color_matrix_1; + return color_matrix_1; } else if (mix <= 0.0) { - col = color_matrix_2; + return color_matrix_2; } else { - mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, col); + return mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix); } } else if (has_col_1) { - col = color_matrix_1; + return color_matrix_1; } else { - col = color_matrix_2; + return color_matrix_2; } - - xyz_to_camera = col; } -void DCPProfile::neutralToXy(const Triple& neutral, int preferred_illuminant, double xy[2]) const +std::array DCPProfile::neutralToXy(const Triple& neutral, int preferred_illuminant) const { enum { MAX_PASSES = 30 }; - double last_xy[2] = {0.3457, 0.3585}; // D50 + std::array last_xy = {0.3457, 0.3585}; // D50 for (unsigned int pass = 0; pass < MAX_PASSES; ++pass) { - Matrix xyz_to_camera; - findXyztoCamera(last_xy, preferred_illuminant, xyz_to_camera); + const Matrix& xyz_to_camera = findXyztoCamera(last_xy, preferred_illuminant); + const Matrix& inv_m = invert3x3(xyz_to_camera); + const Triple& next_xyz = multiply3x3_v3(inv_m, neutral); - Matrix inv_m; - Triple next_xyz; - double next_xy[2]; - invert3x3(xyz_to_camera, inv_m); - multiply3x3_v3(inv_m, neutral, next_xyz); - xyzToXy(next_xyz, next_xy); + std::array next_xy = xyzToXy(next_xyz); - if (fabs(next_xy[0] - last_xy[0]) + - fabs(next_xy[1] - last_xy[1]) < 0.0000001) { - xy[0] = next_xy[0]; - xy[1] = next_xy[1]; - return; + if (std::fabs(next_xy[0] - last_xy[0]) + std::fabs(next_xy[1] - last_xy[1]) < 0.0000001) { + return next_xy; } // If we reach the limit without converging, we are most likely @@ -1319,15 +1291,13 @@ void DCPProfile::neutralToXy(const Triple& neutral, int preferred_illuminant, do next_xy[1] = (last_xy[1] + next_xy[1]) * 0.5; } - last_xy[0] = next_xy[0]; - last_xy[1] = next_xy[1]; + last_xy = next_xy; } - xy[0] = last_xy[0]; - xy[1] = last_xy[1]; + return last_xy; } -void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant, Matrix& xyz_cam) const +DCPProfile::Matrix DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant) const { // Code adapted from dng_color_spec::FindXYZtoCamera. // Note that we do not support monochrome or colorplanes > 3 (no reductionMatrix support), @@ -1340,32 +1310,24 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu double r, g, b; white_balance.getMultipliers(r, g, b); - // camWbMatrix == imatrices.xyz_cam - Matrix cam_xyz; - invert3x3(cam_wb_matrix, cam_xyz); - Matrix cam_rgb; - constexpr Matrix xyz_srgb = {{ + constexpr Matrix xyz_srgb = { + { {xyz_sRGB[0][0], xyz_sRGB[0][1], xyz_sRGB[0][2]}, {xyz_sRGB[1][0], xyz_sRGB[1][1], xyz_sRGB[1][2]}, {xyz_sRGB[2][0], xyz_sRGB[2][1], xyz_sRGB[2][2]} } }; - multiply3x3(cam_xyz, xyz_srgb, cam_rgb); + const Matrix cam_rgb = multiply3x3(invert3x3(cam_wb_matrix), xyz_srgb); double camwb_red = cam_rgb[0][0] * r + cam_rgb[0][1] * g + cam_rgb[0][2] * b; double camwb_green = cam_rgb[1][0] * r + cam_rgb[1][1] * g + cam_rgb[1][2] * b; double camwb_blue = cam_rgb[2][0] * r + cam_rgb[2][1] * g + cam_rgb[2][2] * b; neutral[0] = camwb_red / pre_mul[0]; neutral[1] = camwb_green / pre_mul[1]; neutral[2] = camwb_blue / pre_mul[2]; - double maxentry = 0; - for (int i = 0; i < 3; i++) { - if (neutral[i] > maxentry) { - maxentry = neutral[i]; - } - } + const double maxentry = std::max({neutral[0], neutral[1], neutral[2]}); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 3; ++i) { neutral[i] /= maxentry; } } @@ -1374,8 +1336,7 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu DCP ColorMatrix or ColorMatrices if dual-illuminant. This is the DNG reference code way to do it, which is a bit different from RT's own white balance model at the time of writing. When RT's white balance can make use of the DCP color matrices we could use that instead. */ - double white_xy[2]; - neutralToXy(neutral, preferred_illuminant, white_xy); + const std::array white_xy = neutralToXy(neutral, preferred_illuminant); bool has_fwd_1 = has_forward_matrix_1; bool has_fwd_2 = has_forward_matrix_2; @@ -1404,18 +1365,17 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu double mix = 1.0; if ((has_col_1 && has_col_2) || (has_fwd_1 && has_fwd_2)) { - double wbtemp; /* DNG ref way to convert XY to temperature, which affect matrix mixing. A different model here typically does not affect the result too much, ie it's probably not strictly necessary to use the DNG reference code here, but we do it for now. */ - xyCoordToTemperature(white_xy, &wbtemp, nullptr); + const double wbtemp = xyCoordToTemperature(white_xy); if (wbtemp <= temperature_1) { mix = 1.0; } else if (wbtemp >= temperature_2) { mix = 0.0; } else { - double invT = 1.0 / wbtemp; + const double& invT = 1.0 / wbtemp; mix = (invT - (1.0 / temperature_2)) / ((1.0 / temperature_1) - (1.0 / temperature_2)); } } @@ -1430,7 +1390,7 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu } else if (mix <= 0.0) { color_matrix = color_matrix_2; } else { - mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, color_matrix); + color_matrix = mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix); } } else if (has_col_1) { color_matrix = color_matrix_1; @@ -1446,8 +1406,7 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu will show incorrect color. */ - Triple white_xyz; - xyToXyz(white_xy, white_xyz); + const Triple white_xyz = xyToXyz(white_xy); Matrix cam_xyz; @@ -1462,7 +1421,7 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu } else if (mix <= 0.0) { fwd = forward_matrix_2; } else { - mix3x3(forward_matrix_1, mix, forward_matrix_2, 1.0 - mix, fwd); + fwd = mix3x3(forward_matrix_1, mix, forward_matrix_2, 1.0 - mix); } } else if (has_fwd_1) { fwd = forward_matrix_1; @@ -1471,76 +1430,66 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu } // adapted from dng_color_spec::SetWhiteXY - Triple camera_white; - multiply3x3_v3(color_matrix, white_xyz, camera_white); - - const Matrix white_diag = {{ + const Triple camera_white = multiply3x3_v3(color_matrix, white_xyz); + const Matrix white_diag = { + { {camera_white[0], 0, 0}, {0, camera_white[1], 0}, {0, 0, camera_white[2]} } }; - Matrix white_diag_inv; - invert3x3(white_diag, white_diag_inv); - Matrix xyz_cam; - multiply3x3(fwd, white_diag_inv, xyz_cam); - invert3x3(xyz_cam, cam_xyz); + cam_xyz = invert3x3(multiply3x3(fwd, invert3x3(white_diag))); } else { - Matrix white_matrix; - const Triple white_d50 = {0.3457, 0.3585, 0.2958}; // D50 - mapWhiteMatrix(white_d50, white_xyz, white_matrix); - multiply3x3(color_matrix, white_matrix, cam_xyz); + constexpr Triple white_d50 = {0.3457, 0.3585, 0.2958}; // D50 + + cam_xyz = multiply3x3(color_matrix, mapWhiteMatrix(white_d50, white_xyz)); } // Convert cam_xyz (XYZ D50 to CameraRGB, "PCS to Camera" in DNG terminology) to mXYZCAM - { - // This block can probably be simplified, seems unnecessary to pass through the sRGB matrix - // (probably dcraw legacy), it does no harm though as we don't clip anything. - int i, j, k; + // This block can probably be simplified, seems unnecessary to pass through the sRGB matrix + // (probably dcraw legacy), it does no harm though as we don't clip anything. + int i, j, k; - // Multiply out XYZ colorspace - double cam_rgb[3][3] = {}; + // Multiply out XYZ colorspace + double cam_rgb[3][3] = {}; - for (i = 0; i < 3; ++i) { - for (j = 0; j < 3; ++j) { - for (k = 0; k < 3; ++k) { - cam_rgb[i][j] += cam_xyz[i][k] * xyz_sRGB[k][j]; - } - } - } - - // Normalize cam_rgb so that cam_rgb * (1,1,1) is (1,1,1,1) - double num; - - for (i = 0; i < 3; ++i) { - for (num = j = 0; j < 3; ++j) { - num += cam_rgb[i][j]; - } - - for (j = 0; j < 3; ++j) { - cam_rgb[i][j] /= num; - } - } - - double rgb_cam[3][3] = {}; - RawImageSource::inverse33(cam_rgb, rgb_cam); - - for (i = 0; i < 3; ++i) { - for (j = 0; j < 3; ++j) { - xyz_cam[i][j] = 0; - } - } - - for (i = 0; i < 3; ++i) { - for (j = 0; j < 3; ++j) { - for (k = 0; k < 3; ++k) { - xyz_cam[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; - } + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + for (k = 0; k < 3; ++k) { + cam_rgb[i][j] += cam_xyz[i][k] * xyz_sRGB[k][j]; } } } + + // Normalize cam_rgb so that cam_rgb * (1,1,1) is (1,1,1,1) + double num; + + for (i = 0; i < 3; ++i) { + for (num = j = 0; j < 3; ++j) { + num += cam_rgb[i][j]; + } + + for (j = 0; j < 3; ++j) { + cam_rgb[i][j] /= num; + } + } + + double rgb_cam[3][3] = {}; + RawImageSource::inverse33(cam_rgb, rgb_cam); + + Matrix res = {}; + + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + for (k = 0; k < 3; ++k) { + res[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; + } + } + } + + return res; } std::vector DCPProfile::makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const @@ -1670,7 +1619,7 @@ void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector(s_scaled, table_info.pc.max_sat_index0), 0); const int v_index0 = std::max(std::min(v_scaled, table_info.pc.max_val_index0), 0); @@ -1823,10 +1772,14 @@ DCPProfile* DCPStore::getProfile(const Glib::ustring& filename) const DCPProfile* const res = new DCPProfile(filename); - // Add profile - profile_cache[filename] = res; + if (*res) { + // Add profile + profile_cache[filename] = res; + return res; + } - return res; + delete res; + return nullptr; } DCPProfile* DCPStore::getStdProfile(const Glib::ustring& cam_short_name) const diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 7db44950d..11e368b80 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -66,6 +66,8 @@ public: DCPProfile(const Glib::ustring& filename); ~DCPProfile(); + explicit operator bool() const; + bool getHasToneCurve() const; bool getHasLookTable() const; bool getHasHueSatMap() const; @@ -112,9 +114,9 @@ private: } pc; }; - void findXyztoCamera(const double white_xy[2], int preferred_illuminant, Matrix& xyz_to_camera) const; - void neutralToXy(const Triple& neutral, int preferred_illuminant, double xy[2]) const; - void makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant, Matrix& xyz_cam) const; + Matrix findXyztoCamera(const std::array& white_xy, int preferred_illuminant) const; + std::array neutralToXy(const Triple& neutral, int preferred_illuminant) const; + Matrix makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant) const; std::vector makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const; void hsdApply(const HsdTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const; diff --git a/rtengine/iccmatrices.h b/rtengine/iccmatrices.h index 292f45612..a6fd8d9e6 100644 --- a/rtengine/iccmatrices.h +++ b/rtengine/iccmatrices.h @@ -20,184 +20,242 @@ #define _ICCMATRICES_ // Bradford transform between illuminants -const double d65_d50[3][3] = {{0.9555766, -0.0230393, 0.0631636}, +constexpr double d65_d50[3][3] = { + {0.9555766, -0.0230393, 0.0631636}, { -0.0282895, 1.0099416, 0.0210077}, {0.0122982, -0.0204830, 1.3299098} }; -const double d50_d65[3][3] = {{ 1.0478112, 0.0228866, -0.0501270}, +constexpr double d50_d65[3][3] = { + { 1.0478112, 0.0228866, -0.0501270}, {0.0295424, 0.9904844, -0.0170491}, { -0.0092345, 0.0150436, 0.7521316} }; // Color space conversion to/from XYZ; color spaces adapted to D65 -const double xyz_sRGBd65[3][3] = {{0.4124564, 0.3575761, 0.1804375}, +constexpr double xyz_sRGBd65[3][3] = { + {0.4124564, 0.3575761, 0.1804375}, {0.2126729, 0.7151522, 0.0721750}, // WARNING: the summ of this line is > 1.0 {0.0193339, 0.1191920, 0.9503041} }; -const double sRGBd65_xyz[3][3] = {{ 3.2404542, -1.5371385, -0.4985314}, +constexpr double sRGBd65_xyz[3][3] = { + { 3.2404542, -1.5371385, -0.4985314}, { -0.9692660, 1.8760108, 0.0415560}, {0.0556434, -0.2040259, 1.0572252} }; //%%%%%%%%%%%%%%%%%%%%%%%% // TEST using Gabor's matrices -/*const double xyz_sRGB[3][3] = {{0.435859, 0.385336, 0.143023}, +/*constexpr double xyz_sRGB[3][3] = { + {0.435859, 0.385336, 0.143023}, {0.222385, 0.717021, 0.0605936 }, {0.0139162, 0.0971389, 0.713817}}; -const double sRGB_xyz[3][3] = {{3.13593293538656, -1.61878246026431, -0.490913888760734}, +constexpr double sRGB_xyz[3][3] = { + {3.13593293538656, -1.61878246026431, -0.490913888760734}, {-0.978702373022194, 1.91609508555177, 0.0334453372795315}, {0.0720490013929888, -0.22919049060526, 1.40593851447263}};*/ //%%%%%%%%%%%%%%%%%%%%%%%% // Color space conversion to/from XYZ; color spaces adapted to D50 using Bradford transform -const double xyz_sRGB[3][3] = {{0.4360747, 0.3850649, 0.1430804}, +constexpr double xyz_sRGB[3][3] = { + {0.4360747, 0.3850649, 0.1430804}, {0.2225045, 0.7168786, 0.0606169}, {0.0139322, 0.0971045, 0.7141733} }; -const double sRGB_xyz[3][3] = {{3.1338561, -1.6168667, -0.4906146}, +constexpr double sRGB_xyz[3][3] = { + {3.1338561, -1.6168667, -0.4906146}, { -0.9787684, 1.9161415, 0.0334540}, {0.0719453, -0.2289914, 1.4052427} }; -const double xyz_adobe[3][3] = {{0.6097559, 0.2052401, 0.1492240}, +constexpr double xyz_adobe[3][3] = { + {0.6097559, 0.2052401, 0.1492240}, {0.3111242, 0.6256560, 0.0632197}, {0.0194811, 0.0608902, 0.7448387} }; -const double adobe_xyz[3][3] = {{1.9624274, -0.6105343, -0.3413404}, +constexpr double adobe_xyz[3][3] = { + {1.9624274, -0.6105343, -0.3413404}, { -0.9787684, 1.9161415, 0.0334540}, {0.0286869, -0.1406752, 1.3487655} }; -const double xyz_prophoto[3][3] = {{0.7976749, 0.1351917, 0.0313534}, +constexpr double xyz_prophoto[3][3] = { + {0.7976749, 0.1351917, 0.0313534}, {0.2880402, 0.7118741, 0.0000857}, {0.0000000, 0.0000000, 0.8252100} }; -const double prophoto_xyz[3][3] = {{1.3459433, -0.2556075, -0.0511118}, +constexpr double prophoto_xyz[3][3] = { + {1.3459433, -0.2556075, -0.0511118}, { -0.5445989, 1.5081673, 0.0205351}, {0.0000000, 0.0000000, 1.2118128} }; /* -const double xyz_rec2020[3][3] = {{0.636958, 0.144617, 0.168881}, +constexpr double xyz_rec2020[3][3] = { + {0.636958, 0.144617, 0.168881}, {0.262700, 0.677998, 0.059302}, {0.0000000, 0.028073, 1.060985} }; -const double rec2020_xyz[3][3] = {{1.716651, -0.355671, -0.253366}, +constexpr double rec2020_xyz[3][3] = { + {1.716651, -0.355671, -0.253366}, { -0.666684, 1.616481, 0.015769}, {0.017640, -0.042771, 0.942103} }; */ -const double xyz_rec2020[3][3] = {{0.6734241, 0.1656411, 0.1251286}, +constexpr double xyz_rec2020[3][3] = { + {0.6734241, 0.1656411, 0.1251286}, {0.2790177, 0.6753402, 0.0456377}, { -0.0019300, 0.0299784, 0.7973330} }; -const double rec2020_xyz[3][3] = {{1.6473376, -0.3935675, -0.2359961}, +constexpr double rec2020_xyz[3][3] = { + {1.6473376, -0.3935675, -0.2359961}, { -0.6826036, 1.6475887, 0.0128190}, {0.0296524, -0.0628993, 1.2531279} }; -const double xyz_widegamut[3][3] = {{0.7161046, 0.1009296, 0.1471858}, +constexpr double xyz_widegamut[3][3] = { + {0.7161046, 0.1009296, 0.1471858}, {0.2581874, 0.7249378, 0.0168748}, {0.0000000, 0.0517813, 0.7734287} }; -const double widegamut_xyz[3][3] = {{ 1.4628067, -0.1840623, -0.2743606}, +constexpr double widegamut_xyz[3][3] = { + { 1.4628067, -0.1840623, -0.2743606}, { -0.5217933, 1.4472381, 0.0677227}, {0.0349342, -0.0968930, 1.2884099} }; -const double xyz_bruce[3][3] = {{0.4941816, 0.3204834, 0.1495550}, +constexpr double xyz_bruce[3][3] = { + {0.4941816, 0.3204834, 0.1495550}, {0.2521531, 0.6844869, 0.0633600}, {0.0157886, 0.0629304, 0.7464909} }; -const double bruce_xyz[3][3] = {{2.6502856, -1.2014485, -0.4289936}, +constexpr double bruce_xyz[3][3] = { + {2.6502856, -1.2014485, -0.4289936}, { -0.9787684, 1.9161415, 0.0334540}, {0.0264570, -0.1361227, 1.3458542} }; -const double xyz_beta[3][3] = {{0.6712537, 0.1745834, 0.1183829}, +constexpr double xyz_beta[3][3] = { + {0.6712537, 0.1745834, 0.1183829}, {0.3032726, 0.6637861, 0.0329413}, {0.0000000, 0.0407010, 0.7845090} }; -const double beta_xyz[3][3] = {{1.6832270, -0.4282363, -0.2360185}, +constexpr double beta_xyz[3][3] = { + {1.6832270, -0.4282363, -0.2360185}, { -0.7710229, 1.7065571, 0.0446900}, {0.0400013, -0.0885376, 1.2723640} }; -const double xyz_best[3][3] = {{0.6326696, 0.2045558, 0.1269946}, +constexpr double xyz_best[3][3] = { + {0.6326696, 0.2045558, 0.1269946}, {0.2284569, 0.7373523, 0.0341908}, {0.0000000, 0.0095142, 0.8156958} }; -const double best_xyz[3][3] = {{1.7552599, -0.4836786, -0.2530000}, +constexpr double best_xyz[3][3] = { + {1.7552599, -0.4836786, -0.2530000}, { -0.5441336, 1.5068789, 0.0215528}, {0.0063467, -0.0175761, 1.2256959} }; -/*const double sRGB_d50[3][3] = {{0.4360520246092, 0.2224915978656, 0.0139291219896}, - {0.38508159282, 0.716886060114, 0.09709700166}, - {0.1430874138552, 0.0606214863936, 0.714185469944}}; +/* +constexpr double sRGB_d50[3][3] = { + {0.4360520246092, 0.2224915978656, 0.0139291219896}, + {0.38508159282, 0.716886060114, 0.09709700166}, + {0.1430874138552, 0.0606214863936, 0.714185469944} +}; -const double d50_sRGB[3][3] = {{3.13405134405167,-0.978762729953942, 0.0719425766617001}, - {-1.61702771153574,1.91614222810656, -0.228971178679309}, - {-0.49065220876631,0.0334496273068589, 1.40521830559074}};*/ +constexpr double d50_sRGB[3][3] = { + {3.13405134405167,-0.978762729953942, 0.0719425766617001}, + {-1.61702771153574,1.91614222810656, -0.228971178679309}, + {-0.49065220876631,0.0334496273068589, 1.40521830559074} +}; +*/ /* // Gabor's matrices -const double sRGB_d50[3][3] = {{0.435859, 0.222385, 0.0139162}, - {0.385336, 0.717021, 0.0971389}, - {0.143023, 0.0605936, 0.713817}}; +constexpr double sRGB_d50[3][3] = { + {0.435859, 0.222385, 0.0139162}, + {0.385336, 0.717021, 0.0971389}, + {0.143023, 0.0605936, 0.713817} +}; -const double d50_sRGB[3][3] = {{3.13593293538656, -0.978702373022194, 0.0720490013929888}, - {-1.61878246026431, 1.91609508555177, -0.22919049060526}, - {-0.490913888760734, 0.0334453372795315, 1.40593851447263}}; +constexpr double d50_sRGB[3][3] = { + {3.13593293538656, -0.978702373022194, 0.0720490013929888}, + {-1.61878246026431, 1.91609508555177, -0.22919049060526}, + {-0.490913888760734, 0.0334453372795315, 1.40593851447263} +}; -const double adobe_d50[3][3] = {{0.6097395054954, 0.3111142944042, 0.0194773131652}, - {0.2052518325737, 0.6256618480686, 0.0608872306106}, - {0.1492308013399, 0.0632241329247, 0.744846530711}}; -const double d50_adobe[3][3] = {{1.9624959949628, -0.978762712052774, 0.0286904764959749}, - {-0.610587687828765,1.91614073756734, -0.140667763143042}, - {-0.34136021627766, 0.0334501217627688, 1.34875045144924}}; -const double prophoto_d50[3][3] = {{0.797675, 0.288040, 0.000000}, - {0.135192, 0.711874, 0.000000}, - {0.0313534,0.000086, 0.825210}}; -const double d50_prophoto[3][3] = {{1.34594335079331, -0.544598514291158, 0}, - {-0.255608118122657, 1.50816768465213, 0}, - {-0.0511117387775285, 0.0205345459181255, 1.21181275069376}}; -const double widegamut_d50[3][3] = {{0.716105, 0.258187, 0.000000}, - {0.100930, 0.724938, 0.0517813}, - {0.147186, 0.0168748, 0.773429}}; -const double d50_widegamut[3][3] = {{1.46280597103052, -0.521792197260068, 0.0349341417298585}, - {-0.184062984909417, 1.44723786022891, -0.0968930022172314}, - {-0.27436071519732, 0.0677226440980744,1.28840945122198}}; -const double bruce_d50[3][3] = {{0.4941607255908, 0.2521412970174, 0.0157852934504}, - {0.3204990468435, 0.684494580042, 0.062927176507}, - {0.1495612990809, 0.0633643619597, 0.746498914581}}; -const double d50_bruce[3][3] = {{2.65042308164152, -0.978762745761462, 0.0264609493245811}, - {-1.20155941925411, 1.9161402914007, -0.136115844662896}, - {-0.42902228923717, 0.0334495071197919, 1.34583900936772}}; -const double beta_d50[3][3] = {{0.671254, 0.303273, 0.000000}, - {0.174583, 0.663786, 0.040701}, - {0.118383, 0.0329413, 0.784509}}; -const double d50_beta[3][3] = {{1.68322591962771, -0.771023599950842, 0.0400013658754702}, - {-0.428235060337656, 1.70655704781303, -0.0885376438040078}, - {-0.236018598193503, 0.0446902191738489,1.27236406897742}}; -const double best_d50[3][3] = {{0.632670, 0.228457, 0.000000}, - {0.204556, 0.737352, 0.00951424}, - {0.126995, 0.0341908, 0.815696}}; -const double d50_best[3][3] = {{1.75525923340349, -0.544133953997468, 0.00634675299435191}, - {-0.483679025800866, 1.50687975713407, -0.017576175021718}, - {-0.253000840399762, 0.0215532098817316,1.22569552576991}}; +constexpr double adobe_d50[3][3] = { + {0.6097395054954, 0.3111142944042, 0.0194773131652}, + {0.2052518325737, 0.6256618480686, 0.0608872306106}, + {0.1492308013399, 0.0632241329247, 0.744846530711} +}; +constexpr double d50_adobe[3][3] = { + {1.9624959949628, -0.978762712052774, 0.0286904764959749}, + {-0.610587687828765,1.91614073756734, -0.140667763143042}, + {-0.34136021627766, 0.0334501217627688, 1.34875045144924} +}; +constexpr double prophoto_d50[3][3] = { + {0.797675, 0.288040, 0.000000}, + {0.135192, 0.711874, 0.000000}, + {0.0313534,0.000086, 0.825210} +}; +constexpr double d50_prophoto[3][3] = { + {1.34594335079331, -0.544598514291158, 0}, + {-0.255608118122657, 1.50816768465213, 0}, + {-0.0511117387775285, 0.0205345459181255, 1.21181275069376} +}; +constexpr double widegamut_d50[3][3] = { + {0.716105, 0.258187, 0.000000}, + {0.100930, 0.724938, 0.0517813}, + {0.147186, 0.0168748, 0.773429} +}; +constexpr double d50_widegamut[3][3] = { + {1.46280597103052, -0.521792197260068, 0.0349341417298585}, + {-0.184062984909417, 1.44723786022891, -0.0968930022172314}, + {-0.27436071519732, 0.0677226440980744,1.28840945122198} +}; +constexpr double bruce_d50[3][3] = { + {0.4941607255908, 0.2521412970174, 0.0157852934504}, + {0.3204990468435, 0.684494580042, 0.062927176507}, + {0.1495612990809, 0.0633643619597, 0.746498914581} +}; +constexpr double d50_bruce[3][3] = { + {2.65042308164152, -0.978762745761462, 0.0264609493245811}, + {-1.20155941925411, 1.9161402914007, -0.136115844662896}, + {-0.42902228923717, 0.0334495071197919, 1.34583900936772} +}; +constexpr double beta_d50[3][3] = { + {0.671254, 0.303273, 0.000000}, + {0.174583, 0.663786, 0.040701}, + {0.118383, 0.0329413, 0.784509} +}; +constexpr double d50_beta[3][3] = { + {1.68322591962771, -0.771023599950842, 0.0400013658754702}, + {-0.428235060337656, 1.70655704781303, -0.0885376438040078}, + {-0.236018598193503, 0.0446902191738489,1.27236406897742} +}; +constexpr double best_d50[3][3] = { + {0.632670, 0.228457, 0.000000}, + {0.204556, 0.737352, 0.00951424}, + {0.126995, 0.0341908, 0.815696} +}; +constexpr double d50_best[3][3] = { + {1.75525923340349, -0.544133953997468, 0.00634675299435191}, + {-0.483679025800866, 1.50687975713407, -0.017576175021718}, + {-0.253000840399762, 0.0215532098817316,1.22569552576991} +}; */ #endif From a32e13400b3e8130ca3a17abf9bf17af17995dc5 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 12 Jun 2016 13:32:08 +0200 Subject: [PATCH 7/7] Removed stopwatches --- rtengine/dcp.cc | 4 +--- rtengine/improcfun.cc | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index f02ba8aaa..a597fa8db 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -26,8 +26,6 @@ #include "rawimagesource.h" #include "improcfun.h" #include "rt_math.h" -#define BENCHMARK -#include "StopWatch.h" using namespace rtengine; using namespace rtexif; @@ -989,7 +987,7 @@ void DCPProfile::apply( bool apply_hue_sat_map ) const { - BENCHFUN + const TMatrix work_matrix = iccStore->workingSpaceInverseMatrix(working_space); const Matrix xyz_cam = makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant); // Camera RGB to XYZ D50 matrix diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index d458bc351..8da4f689a 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -40,7 +40,7 @@ #include "improccoordinator.h" #include "clutstore.h" #include "ciecam02.h" -#define BENCHMARK +//#define BENCHMARK #include "StopWatch.h" #include "../rtgui/ppversion.h" #include "../rtgui/guiutils.h"