From cb034284be3f33921952dd28acd6c0fa951b3e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Wed, 14 Sep 2016 21:36:44 +0200 Subject: [PATCH 1/6] Use full range in `ImageDatas::convertTo<>` (#3429) Kudos to @mmmtok for finding and fixing! --- rtengine/iimage.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/rtengine/iimage.h b/rtengine/iimage.h index 1f82ea3e6..2eded8208 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -58,10 +58,10 @@ enum TypeInterpolation { TI_Nearest, TI_Bilinear }; class ImageDatas : virtual public ImageDimensions { public: - template - void convertTo (S srcValue, D &dstValue) + template + void convertTo(S src, D& dst) const { - dstValue = static_cast(srcValue); + dst = src; } // parameters that will never be used, replaced by the subclasses r, g and b parameters! @@ -100,30 +100,30 @@ public: }; -template <> -inline void ImageDatas::convertTo (const unsigned short srcValue, unsigned char &dstValue) +template<> +inline void ImageDatas::convertTo(unsigned short src, unsigned char& dst) const { - dstValue = (unsigned char)(srcValue >> 8); + dst = src / 257; } -template <> -inline void ImageDatas::convertTo (const unsigned char srcValue, int &dstValue) +template<> +inline void ImageDatas::convertTo(unsigned char src, int& dst) const { - dstValue = (int)(srcValue) << 8; + dst = static_cast(src) * 257; } -template <> -inline void ImageDatas::convertTo (const unsigned char srcValue, unsigned short &dstValue) +template<> +inline void ImageDatas::convertTo(unsigned char src, unsigned short& dst) const { - dstValue = (unsigned short)(srcValue) << 8; + dst = static_cast(src) * 257; } -template <> -inline void ImageDatas::convertTo (const float srcValue, unsigned char &dstValue) +template<> +inline void ImageDatas::convertTo(float src, unsigned char& dst) const { - dstValue = (unsigned char)( (unsigned short)(srcValue) >> 8 ); + dst = static_cast(src) / 257; } -template <> -inline void ImageDatas::convertTo (const unsigned char srcValue, float &dstValue) +template<> +inline void ImageDatas::convertTo(unsigned char src, float& dst) const { - dstValue = float( (unsigned short)(srcValue) << 8 ); + dst = static_cast(src) * 257; } // -------------------------------------------------------------------- From 309b823f93d426367d192b2a9e5a5a03e5345b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Sat, 17 Sep 2016 17:32:46 +0200 Subject: [PATCH 2/6] Fix range in `Image*` classes (#3429) --- rtengine/image16.cc | 36 ++++++++++++++++++------------------ rtengine/image8.cc | 8 ++++---- rtengine/imagefloat.cc | 20 ++++++++++---------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/rtengine/image16.cc b/rtengine/image16.cc index 937e2d19d..9d41f96c5 100644 --- a/rtengine/image16.cc +++ b/rtengine/image16.cc @@ -28,9 +28,9 @@ namespace void getScanline8 (const uint16_t *red, const uint16_t *green, const uint16_t *blue, int width, unsigned char* buffer) { for (int i = 0, ix = 0; i < width; i++) { - buffer[ix++] = red[i] >> 8; - buffer[ix++] = green[i] >> 8; - buffer[ix++] = blue[i] >> 8; + buffer[ix++] = red[i] / 257; + buffer[ix++] = green[i] / 257; + buffer[ix++] = blue[i] / 257; } } @@ -92,10 +92,10 @@ void Image16::setScanline (int row, unsigned char* buffer, int bps, float *minVa case (IIOSF_UNSIGNED_CHAR): { int ix = 0; - for (int i = 0; i < width; i++) { - r(row, i) = (unsigned short)(buffer[ix++]) << 8; - g(row, i) = (unsigned short)(buffer[ix++]) << 8; - b(row, i) = (unsigned short)(buffer[ix++]) << 8; + for (int i = 0; i < width; ++i) { + r(row, i) = static_cast(buffer[ix++]) * 257; + g(row, i) = static_cast(buffer[ix++]) * 257; + b(row, i) = static_cast(buffer[ix++]) * 257; } break; @@ -105,7 +105,7 @@ void Image16::setScanline (int row, unsigned char* buffer, int bps, float *minVa unsigned short* sbuffer = (unsigned short*) buffer; int ix = 0; - for (int i = 0; i < width; i++) { + for (int i = 0; i < width; ++i) { r(row, i) = sbuffer[ix++]; g(row, i) = sbuffer[ix++]; b(row, i) = sbuffer[ix++]; @@ -298,11 +298,11 @@ Image16::to8() { Image8* img8 = new Image8(width, height); - for ( int h = 0; h < height; ++h ) { - for ( int w = 0; w < width; ++w ) { - img8->r(h, w) = (unsigned char)( r(h, w) >> 8); - img8->g(h, w) = (unsigned char)( g(h, w) >> 8); - img8->b(h, w) = (unsigned char)( b(h, w) >> 8); + for (int h = 0; h < height; ++h) { + for (int w = 0; w < width; ++w) { + img8->r(h, w) = r(h, w) / 257; + img8->g(h, w) = g(h, w) / 257; + img8->b(h, w) = b(h, w) / 257; } } @@ -314,11 +314,11 @@ Image16::tofloat() { Imagefloat* imgfloat = new Imagefloat(width, height); - for ( int h = 0; h < height; ++h ) { - for ( int w = 0; w < width; ++w ) { - imgfloat->r(h, w) = (float)r(h, w); - imgfloat->g(h, w) = (float)g(h, w); - imgfloat->b(h, w) = (float)b(h, w); + for (int h = 0; h < height; ++h) { + for (int w = 0; w < width; ++w) { + imgfloat->r(h, w) = r(h, w); + imgfloat->g(h, w) = g(h, w); + imgfloat->b(h, w) = b(h, w); } } diff --git a/rtengine/image8.cc b/rtengine/image8.cc index b27851a76..1cc648eb5 100644 --- a/rtengine/image8.cc +++ b/rtengine/image8.cc @@ -49,8 +49,8 @@ void Image8::getScanline (int row, unsigned char* buffer, int bps) } else if (bps == 16) { unsigned short* sbuffer = (unsigned short*) buffer; - for (int i = 0, ix = row * width * 3; i < width * 3; i++, ix++) { - sbuffer[i] = (unsigned short)(data[ix]) << 8; + for (int i = 0, ix = row * width * 3; i < width * 3; ++i, ++ix) { + sbuffer[i] = static_cast(data[ix]) * 257; } } } @@ -73,8 +73,8 @@ void Image8::setScanline (int row, unsigned char* buffer, int bps, float *minVal case (IIOSF_UNSIGNED_SHORT): { unsigned short* sbuffer = (unsigned short*) buffer; - for (int i = 0, ix = row * width * 3; i < width * 3; i++, ix++) { - data[ix] = sbuffer[i] >> 8; + for (int i = 0, ix = row * width * 3; i < width * 3; ++i, ++ix) { + data[ix] = sbuffer[i] / 257; } break; diff --git a/rtengine/imagefloat.cc b/rtengine/imagefloat.cc index 26ea8ae6e..fb4ccae2e 100644 --- a/rtengine/imagefloat.cc +++ b/rtengine/imagefloat.cc @@ -333,11 +333,11 @@ Imagefloat::to8() #pragma omp parallel for schedule(static) #endif - for ( int h = 0; h < height; ++h ) { - for ( int w = 0; w < width; ++w ) { - img8->r(h, w) = (unsigned char)( (unsigned short)(r(h, w)) >> 8); - img8->g(h, w) = (unsigned char)( (unsigned short)(g(h, w)) >> 8); - img8->b(h, w) = (unsigned char)( (unsigned short)(b(h, w)) >> 8); + for (int h = 0; h < height; ++h) { + for (int w = 0; w < width; ++w) { + img8->r(h, w) = static_cast(r(h, w)) / 257; + img8->g(h, w) = static_cast(g(h, w)) / 257; + img8->b(h, w) = static_cast(b(h, w)) / 257; } } @@ -352,11 +352,11 @@ Imagefloat::to16() #pragma omp parallel for schedule(static) #endif - for ( int h = 0; h < height; ++h ) { - for ( int w = 0; w < width; ++w ) { - img16->r( h, w) = (unsigned short)(r(h, w)); - img16->g( h, w) = (unsigned short)(g(h, w)); - img16->b( h, w) = (unsigned short)(b(h, w)); + for (int h = 0; h < height; ++h) { + for (int w = 0; w < width; ++w) { + img16->r(h, w) = r(h, w); + img16->g(h, w) = g(h, w); + img16->b(h, w) = b(h, w); } } From 1e7b8035c41196b0585b2c1c103761d71083e19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Wed, 21 Sep 2016 21:54:46 +0200 Subject: [PATCH 3/6] Round when converting to 8 bits (#3429) --- rtengine/iimage.h | 10 +++++----- rtengine/image16.cc | 12 ++++++------ rtengine/image8.cc | 2 +- rtengine/imagefloat.cc | 6 +++--- rtengine/iplab2rgb.cc | 12 ++++++------ 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/rtengine/iimage.h b/rtengine/iimage.h index 2eded8208..4362f369a 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -103,27 +103,27 @@ public: template<> inline void ImageDatas::convertTo(unsigned short src, unsigned char& dst) const { - dst = src / 257; + dst = (src + 128) / 257; } template<> inline void ImageDatas::convertTo(unsigned char src, int& dst) const { - dst = static_cast(src) * 257; + dst = src * 257; } template<> inline void ImageDatas::convertTo(unsigned char src, unsigned short& dst) const { - dst = static_cast(src) * 257; + dst = src * 257; } template<> inline void ImageDatas::convertTo(float src, unsigned char& dst) const { - dst = static_cast(src) / 257; + dst = (static_cast(src) + 128) / 257; } template<> inline void ImageDatas::convertTo(unsigned char src, float& dst) const { - dst = static_cast(src) * 257; + dst = src * 257; } // -------------------------------------------------------------------- diff --git a/rtengine/image16.cc b/rtengine/image16.cc index 9d41f96c5..11a05902f 100644 --- a/rtengine/image16.cc +++ b/rtengine/image16.cc @@ -28,9 +28,9 @@ namespace void getScanline8 (const uint16_t *red, const uint16_t *green, const uint16_t *blue, int width, unsigned char* buffer) { for (int i = 0, ix = 0; i < width; i++) { - buffer[ix++] = red[i] / 257; - buffer[ix++] = green[i] / 257; - buffer[ix++] = blue[i] / 257; + buffer[ix++] = (red[i] + 128) / 257; + buffer[ix++] = (green[i] + 128) / 257; + buffer[ix++] = (blue[i] + 128) / 257; } } @@ -300,9 +300,9 @@ Image16::to8() for (int h = 0; h < height; ++h) { for (int w = 0; w < width; ++w) { - img8->r(h, w) = r(h, w) / 257; - img8->g(h, w) = g(h, w) / 257; - img8->b(h, w) = b(h, w) / 257; + img8->r(h, w) = (r(h, w) + 128) / 257; + img8->g(h, w) = (g(h, w) + 128) / 257; + img8->b(h, w) = (b(h, w) + 128) / 257; } } diff --git a/rtengine/image8.cc b/rtengine/image8.cc index 1cc648eb5..41589993d 100644 --- a/rtengine/image8.cc +++ b/rtengine/image8.cc @@ -74,7 +74,7 @@ void Image8::setScanline (int row, unsigned char* buffer, int bps, float *minVal unsigned short* sbuffer = (unsigned short*) buffer; for (int i = 0, ix = row * width * 3; i < width * 3; ++i, ++ix) { - data[ix] = sbuffer[i] / 257; + data[ix] = (sbuffer[i] + 128) / 257; } break; diff --git a/rtengine/imagefloat.cc b/rtengine/imagefloat.cc index fb4ccae2e..7f84f1cab 100644 --- a/rtengine/imagefloat.cc +++ b/rtengine/imagefloat.cc @@ -335,9 +335,9 @@ Imagefloat::to8() for (int h = 0; h < height; ++h) { for (int w = 0; w < width; ++w) { - img8->r(h, w) = static_cast(r(h, w)) / 257; - img8->g(h, w) = static_cast(g(h, w)) / 257; - img8->b(h, w) = static_cast(b(h, w)) / 257; + img8->r(h, w) = (static_cast(r(h, w)) + 128) / 257; + img8->g(h, w) = (static_cast(g(h, w)) + 128) / 257; + img8->b(h, w) = (static_cast(b(h, w)) + 128) / 257; } } diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 489ca60bc..843bdaa9c 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -117,9 +117,9 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) /* copy RGB */ //int R1=((int)gamma2curve[(R)]) - data[ix++] = ((int)Color::gamma2curve[R]) >> 8; - data[ix++] = ((int)Color::gamma2curve[G]) >> 8; - data[ix++] = ((int)Color::gamma2curve[B]) >> 8; + data[ix++] = (static_cast(Color::gamma2curve[R]) + 128) / 257; + data[ix++] = (static_cast(Color::gamma2curve[G]) + 128) / 257; + data[ix++] = (static_cast(Color::gamma2curve[B]) + 128) / 257; } } } @@ -229,9 +229,9 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Color::xyz2rgb(x_, y_, z_, R, G, B, xyz_rgb); - image->data[ix++] = (int)Color::gamma2curve[R] >> 8; - image->data[ix++] = (int)Color::gamma2curve[G] >> 8; - image->data[ix++] = (int)Color::gamma2curve[B] >> 8; + image->data[ix++] = (static_cast(Color::gamma2curve[R]) + 128) / 257; + image->data[ix++] = (static_cast(Color::gamma2curve[G]) + 128) / 257; + image->data[ix++] = (static_cast(Color::gamma2curve[B]) + 128) / 257; } } } From 76355590628322f5484f8085e6370cecbac2eb63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Thu, 22 Sep 2016 21:22:35 +0200 Subject: [PATCH 4/6] Add Ingo's missing optimization (#3432) --- rtengine/iplab2rgb.cc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 9a3e710e7..419854523 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -101,15 +101,7 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) //float L1=rL[j],a1=ra[j],b1=rb[j];//for testing - fy = (0.00862069 * rL[j]) / 327.68 + 0.137932; // (L+16)/116 - fx = (0.002 * ra[j]) / 327.68 + fy; - fz = fy - (0.005 * rb[j]) / 327.68; - LL = rL[j] / 327.68; - - x_ = 65535.0 * Color::f2xyz(fx) * Color::D50x; - // y_ = 65535.0 * Color::f2xyz(fy); - z_ = 65535.0 * Color::f2xyz(fz) * Color::D50z; - y_ = (LL > Color::epskap) ? 65535.0 * fy * fy * fy : 65535.0 * LL / Color::kappa; + Color::Lab2XYZ(rL[j], ra[j], rb[j], x_, y_, z_ ); Color::xyz2srgb(x_, y_, z_, R, G, B); From 759676788b186a25fa5c6ebd287b94da62d4b6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Thu, 22 Sep 2016 21:52:07 +0200 Subject: [PATCH 5/6] Use BABL method for 16-to-8 bit conversion (#3429) --- rtengine/iimage.h | 4 ++-- rtengine/image16.cc | 12 ++++++------ rtengine/image8.cc | 2 +- rtengine/imagefloat.cc | 6 +++--- rtengine/iplab2rgb.cc | 12 ++++++------ rtengine/rt_math.h | 20 ++++++++++++-------- 6 files changed, 30 insertions(+), 26 deletions(-) diff --git a/rtengine/iimage.h b/rtengine/iimage.h index 4362f369a..cd49c1329 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -103,7 +103,7 @@ public: template<> inline void ImageDatas::convertTo(unsigned short src, unsigned char& dst) const { - dst = (src + 128) / 257; + dst = uint16ToUint8Rounded(src); } template<> inline void ImageDatas::convertTo(unsigned char src, int& dst) const @@ -118,7 +118,7 @@ inline void ImageDatas::convertTo(unsigned char src, unsigned short& dst) const template<> inline void ImageDatas::convertTo(float src, unsigned char& dst) const { - dst = (static_cast(src) + 128) / 257; + dst = uint16ToUint8Rounded(src); } template<> inline void ImageDatas::convertTo(unsigned char src, float& dst) const diff --git a/rtengine/image16.cc b/rtengine/image16.cc index 11a05902f..b61170e03 100644 --- a/rtengine/image16.cc +++ b/rtengine/image16.cc @@ -28,9 +28,9 @@ namespace void getScanline8 (const uint16_t *red, const uint16_t *green, const uint16_t *blue, int width, unsigned char* buffer) { for (int i = 0, ix = 0; i < width; i++) { - buffer[ix++] = (red[i] + 128) / 257; - buffer[ix++] = (green[i] + 128) / 257; - buffer[ix++] = (blue[i] + 128) / 257; + buffer[ix++] = rtengine::uint16ToUint8Rounded(red[i]); + buffer[ix++] = rtengine::uint16ToUint8Rounded(green[i]); + buffer[ix++] = rtengine::uint16ToUint8Rounded(blue[i]); } } @@ -300,9 +300,9 @@ Image16::to8() for (int h = 0; h < height; ++h) { for (int w = 0; w < width; ++w) { - img8->r(h, w) = (r(h, w) + 128) / 257; - img8->g(h, w) = (g(h, w) + 128) / 257; - img8->b(h, w) = (b(h, w) + 128) / 257; + img8->r(h, w) = uint16ToUint8Rounded(r(h, w)); + img8->g(h, w) = uint16ToUint8Rounded(g(h, w)); + img8->b(h, w) = uint16ToUint8Rounded(b(h, w)); } } diff --git a/rtengine/image8.cc b/rtengine/image8.cc index 41589993d..d7a49138b 100644 --- a/rtengine/image8.cc +++ b/rtengine/image8.cc @@ -74,7 +74,7 @@ void Image8::setScanline (int row, unsigned char* buffer, int bps, float *minVal unsigned short* sbuffer = (unsigned short*) buffer; for (int i = 0, ix = row * width * 3; i < width * 3; ++i, ++ix) { - data[ix] = (sbuffer[i] + 128) / 257; + data[ix] = uint16ToUint8Rounded(sbuffer[i]); } break; diff --git a/rtengine/imagefloat.cc b/rtengine/imagefloat.cc index 7f84f1cab..ae4a1a09b 100644 --- a/rtengine/imagefloat.cc +++ b/rtengine/imagefloat.cc @@ -335,9 +335,9 @@ Imagefloat::to8() for (int h = 0; h < height; ++h) { for (int w = 0; w < width; ++w) { - img8->r(h, w) = (static_cast(r(h, w)) + 128) / 257; - img8->g(h, w) = (static_cast(g(h, w)) + 128) / 257; - img8->b(h, w) = (static_cast(b(h, w)) + 128) / 257; + img8->r(h, w) = uint16ToUint8Rounded(r(h, w)); + img8->g(h, w) = uint16ToUint8Rounded(g(h, w)); + img8->b(h, w) = uint16ToUint8Rounded(b(h, w)); } } diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 419854523..8aff50886 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -107,9 +107,9 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) /* copy RGB */ //int R1=((int)gamma2curve[(R)]) - data[ix++] = (static_cast(Color::gamma2curve[R]) + 128) / 257; - data[ix++] = (static_cast(Color::gamma2curve[G]) + 128) / 257; - data[ix++] = (static_cast(Color::gamma2curve[B]) + 128) / 257; + data[ix++] = uint16ToUint8Rounded(Color::gamma2curve[R]); + data[ix++] = uint16ToUint8Rounded(Color::gamma2curve[G]); + data[ix++] = uint16ToUint8Rounded(Color::gamma2curve[B]); } } } @@ -218,9 +218,9 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Color::xyz2rgb(x_, y_, z_, R, G, B, xyz_rgb); - image->data[ix++] = (static_cast(Color::gamma2curve[R]) + 128) / 257; - image->data[ix++] = (static_cast(Color::gamma2curve[G]) + 128) / 257; - image->data[ix++] = (static_cast(Color::gamma2curve[B]) + 128) / 257; + image->data[ix++] = uint16ToUint8Rounded(Color::gamma2curve[R]); + image->data[ix++] = uint16ToUint8Rounded(Color::gamma2curve[G]); + image->data[ix++] = uint16ToUint8Rounded(Color::gamma2curve[B]); } } } diff --git a/rtengine/rt_math.h b/rtengine/rt_math.h index f55f7c1b2..67d883080 100644 --- a/rtengine/rt_math.h +++ b/rtengine/rt_math.h @@ -1,14 +1,15 @@ -#ifndef _MYMATH_ -#define _MYMATH_ -#include -#include +#pragma once +#include +#include +#include namespace rtengine { -static const int MAXVAL = 0xffff; -static const float MAXVALF = float(MAXVAL); // float version of MAXVAL -static const double MAXVALD = double(MAXVAL); // double version of MAXVAL + +constexpr int MAXVAL = 0xffff; +constexpr float MAXVALF = static_cast(MAXVAL); // float version of MAXVAL +constexpr double MAXVALD = static_cast(MAXVAL); // double version of MAXVAL template inline _Tp SQR (_Tp x) @@ -107,6 +108,9 @@ inline int float2uint16range(float d) // clips input to [0;65535] and rounds return d + 0.5f; } +constexpr std::uint8_t uint16ToUint8Rounded(std::uint16_t i) +{ + return ((i + 128) - ((i + 128) >> 8)) >> 8; } -#endif +} From 4076e1d5aada5d74d52f6c21fe93e08cd54600a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Mon, 26 Sep 2016 21:16:20 +0200 Subject: [PATCH 6/6] Add Ingo's optimization in another place, too (#3432) --- rtengine/iplab2rgb.cc | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 8aff50886..4c2da72a4 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -88,16 +88,16 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) #pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif - for (int i = 0; i < H; i++) { + for (int i = 0; i < H; ++i) { float* rL = lab->L[i]; float* ra = lab->a[i]; float* rb = lab->b[i]; int ix = i * 3 * W; float R, G, B; - float fy, fx, fz, x_, y_, z_, LL; + float x_, y_, z_; - for (int j = 0; j < W; j++) { + for (int j = 0; j < W; ++j) { //float L1=rL[j],a1=ra[j],b1=rb[j];//for testing @@ -197,24 +197,17 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, #pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif - for (int i = cy; i < cy + ch; i++) { - float R, G, B; + for (int i = cy; i < cy + ch; ++i) { float* rL = lab->L[i]; float* ra = lab->a[i]; float* rb = lab->b[i]; int ix = 3 * i * cw; - for (int j = cx; j < cx + cw; j++) { + float R, G, B; + float x_, y_, z_; - float fy = (0.00862069 * rL[j]) / 327.68 + 0.137932; // (L+16)/116 - float fx = (0.002 * ra[j]) / 327.68 + fy; - float fz = fy - (0.005 * rb[j]) / 327.68; - float LL = rL[j] / 327.68; - - float x_ = 65535.0 * Color::f2xyz(fx) * Color::D50x; - //float y_ = 65535.0 * Color::f2xyz(fy); - float z_ = 65535.0 * Color::f2xyz(fz) * Color::D50z; - float y_ = (LL > Color::epskap) ? 65535.0 * fy * fy * fy : 65535.0 * LL / Color::kappa; + for (int j = cx; j < cx + cw; ++j) { + Color::Lab2XYZ(rL[j], ra[j], rb[j], x_, y_, z_); Color::xyz2rgb(x_, y_, z_, R, G, B, xyz_rgb);