Skip to content

Commit 2073a5a

Browse files
committed
+add Base implementation of function BgrToLab (part 4: refactoring).
1 parent 83e524d commit 2073a5a

File tree

2 files changed

+101
-242
lines changed

2 files changed

+101
-242
lines changed

src/Simd/SimdBaseBgrToLab.cpp

+47-190
Original file line numberDiff line numberDiff line change
@@ -26,217 +26,74 @@
2626
#include "Simd/SimdMath.h"
2727
#include "Simd/SimdLog.h"
2828

29+
#define SIMD_BGR_TO_LAB_OPENCV_COMPATIBILITY
30+
2931
namespace Simd
3032
{
3133
namespace Base
3234
{
33-
#define SIMD_BGR_TO_LAB_OPENCV_COMPATIBILITY
35+
uint16_t LabGammaTab[LabGammaTabSize];
36+
uint16_t LabCbrtTab[LabCbrtTabSize];
37+
uint32_t LabCoeffsTab[9];
3438

35-
namespace LabV1
39+
SIMD_INLINE float ApplyGamma(float x)
3640
{
37-
inline double FromRaw(uint64_t raw)
38-
{
39-
return *((double*)&raw);
40-
}
41-
42-
SIMD_INLINE float mullAdd(float a, float b, float c)
43-
{
44-
return a * b + c;
45-
}
46-
47-
#define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n))
48-
const int xyz_shift = 12;
49-
50-
//const double D65[3] = { 0.950456, 1., 1.088754 };
51-
const double D65[3] = { FromRaw(0x3fee6a22b3892ee8),
52-
1.0 ,
53-
FromRaw(0x3ff16b8950763a19) };
54-
55-
//static const double sRGB2XYZ_D65[] =
56-
//{
57-
// 0.412453, 0.357580, 0.180423,
58-
// 0.212671, 0.715160, 0.072169,
59-
// 0.019334, 0.119193, 0.950227
60-
//};
61-
62-
const double sRGB2XYZ_D65[] =
63-
{
64-
FromRaw(0x3fda65a14488c60d),
65-
FromRaw(0x3fd6e297396d0918),
66-
FromRaw(0x3fc71819d2391d58),
67-
FromRaw(0x3fcb38cda6e75ff6),
68-
FromRaw(0x3fe6e297396d0918),
69-
FromRaw(0x3fb279aae6c8f755),
70-
FromRaw(0x3f93cc4ac6cdaf4b),
71-
FromRaw(0x3fbe836eb4e98138),
72-
FromRaw(0x3fee68427418d691)
73-
};
74-
75-
enum { LAB_CBRT_TAB_SIZE = 1024, GAMMA_TAB_SIZE = 1024 };
76-
77-
static const float GammaTabScale((int)GAMMA_TAB_SIZE);
78-
79-
static uint16_t sRGBGammaTab_b[256];
80-
81-
#undef lab_shift
82-
#define lab_shift xyz_shift
83-
#define gamma_shift 3
84-
#define lab_shift2 (lab_shift + gamma_shift)
85-
#define LAB_CBRT_TAB_SIZE_B (256*3/2*(1<<gamma_shift))
86-
static uint16_t LabCbrtTab_b[LAB_CBRT_TAB_SIZE_B];
87-
88-
//all constants should be presented through integers to keep bit-exactness
89-
static const double gammaThreshold = double(809) / double(20000); // 0.04045
90-
static const double gammaInvThreshold = double(7827) / double(2500000); // 0.0031308
91-
static const double gammaLowScale = double(323) / double(25); // 12.92
92-
static const double gammaPower = double(12) / double(5); // 2.4
93-
static const double gammaXshift = double(11) / double(200); // 0.055
41+
return x <= 0.04045f ? x * (1.f / 12.92f) : (float)std::pow((double)(x + 0.055) * (1. / 1.055), 2.4);
42+
}
9443

95-
static const float lthresh = float(216) / float(24389); // 0.008856f = (6/29)^3
96-
static const float lscale = float(841) / float(108); // 7.787f = (29/3)^3/(29*4)
97-
static const float lbias = float(16) / float(116);
44+
SIMD_INLINE float ApplyCbrt(float x)
45+
{
46+
static const float threshold = float(216) / float(24389);
47+
static const float scale = float(841) / float(108);
48+
static const float bias = float(16) / float(116);
49+
return x < threshold ? (x * scale + bias) : cbrt(x);
50+
}
9851

99-
static inline float applyGamma(float x)
52+
static bool LabTabsInited = false;
53+
void LabInitTabs()
54+
{
55+
if (LabTabsInited)
56+
return;
57+
const float intScale(255 * (1 << LAB_GAMMA_SHIFT));
58+
for (int i = 0; i < LabGammaTabSize; i++)
10059
{
101-
//return x <= 0.04045f ? x*(1.f/12.92f) : (float)std::pow((double)(x + 0.055)*(1./1.055), 2.4);
102-
103-
double xd = x;
104-
return (xd <= gammaThreshold ?
105-
xd / gammaLowScale :
106-
pow((xd + gammaXshift) / (1.0 + gammaXshift), gammaPower));
60+
float x = float(i) / 255.0f;
61+
LabGammaTab[i] = (uint16_t)(Round(intScale * ApplyGamma(x)));
10762
}
108-
109-
static void initLabTabs()
63+
const float tabScale(1.0 / (255.0 * (1 << LAB_GAMMA_SHIFT)));
64+
const float shift2(1 << LAB_SHIFT2);
65+
for (int i = 0; i < LabCbrtTabSize; i++)
11066
{
111-
static bool initialized = false;
112-
if (!initialized)
113-
{
114-
float scale = 1.0f / float(GammaTabScale);
115-
static const float intScale(255 * (1 << gamma_shift));
116-
for (int i = 0; i < 256; i++)
117-
{
118-
float x = float(i) / 255.0f;
119-
sRGBGammaTab_b[i] = (uint16_t)(Round(intScale * applyGamma(x)));
120-
}
121-
122-
static const float cbTabScale(1.0 / (255.0 * (1 << gamma_shift)));
123-
static const float lshift2(1 << lab_shift2);
124-
for (int i = 0; i < LAB_CBRT_TAB_SIZE_B; i++)
125-
{
126-
float x = cbTabScale * float(i);
127-
LabCbrtTab_b[i] = (uint16_t)(Round(lshift2 * (x < lthresh ? mullAdd(x, lscale, lbias) : cbrt(x))));
128-
}
129-
#if defined(SIMD_BGR_TO_LAB_OPENCV_COMPATIBILITY)
130-
if(LabCbrtTab_b[324] == 17746)
131-
LabCbrtTab_b[324] = 17745;
132-
if (LabCbrtTab_b[49] == 9455)
133-
LabCbrtTab_b[49] = 9454;
134-
#endif
135-
initialized = true;
136-
}
67+
float x = tabScale * float(i);
68+
LabCbrtTab[i] = (uint16_t)Round(shift2 * ApplyCbrt(x));
13769
}
138-
139-
struct RGB2Lab_b
140-
{
141-
typedef uint8_t channel_type;
142-
143-
RGB2Lab_b(int _srccn, int blueIdx)
144-
: srccn(_srccn)
145-
{
146-
initLabTabs();
147-
148-
double whitePt[3];
149-
for (int i = 0; i < 3; i++)
150-
whitePt[i] = D65[i];
151-
152-
const double lshift(1 << lab_shift);
153-
for (int i = 0; i < 3; i++)
154-
{
155-
double c[3];
156-
for (int j = 0; j < 3; j++)
157-
c[j] = sRGB2XYZ_D65[i * 3 + j];
158-
coeffs[i * 3 + (blueIdx ^ 2)] = Round(lshift * c[0] / whitePt[i]);
159-
coeffs[i * 3 + 1] = Round(lshift * c[1] / whitePt[i]);
160-
coeffs[i * 3 + blueIdx] = Round(lshift * c[2] / whitePt[i]);
161-
162-
assert(coeffs[i * 3] >= 0 && coeffs[i * 3 + 1] >= 0 && coeffs[i * 3 + 2] >= 0 &&
163-
coeffs[i * 3] + coeffs[i * 3 + 1] + coeffs[i * 3 + 2] < 2 * (1 << lab_shift));
164-
}
165-
}
166-
167-
void operator()(const uint8_t* src, uint8_t* dst, int n) const
168-
{
169-
const int Lscale = (116 * 255 + 50) / 100;
170-
const int Lshift = -((16 * 255 * (1 << lab_shift2) + 50) / 100);
171-
const uint16_t* tab = sRGBGammaTab_b;
172-
int i, scn = srccn;
173-
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2],
174-
C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5],
175-
C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8];
176-
177-
for (int i = 0; i < n; i++, src += scn, dst += 3)
178-
{
179-
int R = tab[src[0]], G = tab[src[1]], B = tab[src[2]];
180-
int fX = LabCbrtTab_b[CV_DESCALE(R * C0 + G * C1 + B * C2, lab_shift)];
181-
int fY = LabCbrtTab_b[CV_DESCALE(R * C3 + G * C4 + B * C5, lab_shift)];
182-
int fZ = LabCbrtTab_b[CV_DESCALE(R * C6 + G * C7 + B * C8, lab_shift)];
183-
184-
int L = CV_DESCALE(Lscale * fY + Lshift, lab_shift2);
185-
int a = CV_DESCALE(500 * (fX - fY) + 128 * (1 << lab_shift2), lab_shift2);
186-
int b = CV_DESCALE(200 * (fY - fZ) + 128 * (1 << lab_shift2), lab_shift2);
187-
188-
#if defined(_WIN32) && 0
189-
if (L == 45 && a == 165)
190-
{
191-
std::cout << i << " old Lab = {" << L << ", " << a << ", " << b << "}";
192-
193-
int R = tab[src[0]], G = tab[src[1]], B = tab[src[2]];
194-
int fX = LabCbrtTab_b[CV_DESCALE(R * C0 + G * C1 + B * C2, lab_shift)];
195-
int fY = LabCbrtTab_b[CV_DESCALE(R * C3 + G * C4 + B * C5, lab_shift)] - 1;
196-
int fZ = LabCbrtTab_b[CV_DESCALE(R * C6 + G * C7 + B * C8, lab_shift)];
197-
198-
int L = CV_DESCALE(Lscale * fY + Lshift, lab_shift2);
199-
int a = CV_DESCALE(500 * (fX - fY) + 128 * (1 << lab_shift2), lab_shift2);
200-
int b = CV_DESCALE(200 * (fY - fZ) + 128 * (1 << lab_shift2), lab_shift2);
201-
202-
std::cout << " new Lab = {" << L << ", " << a << ", " << b << "}";
203-
std::cout << " index " << CV_DESCALE(R * C3 + G * C4 + B * C5, lab_shift);
204-
std::cout << " value " << LabCbrtTab_b[CV_DESCALE(R * C3 + G * C4 + B * C5, lab_shift)];
205-
std::cout << std::endl;
206-
exit(0);
207-
}
70+
#if defined(SIMD_BGR_TO_LAB_OPENCV_COMPATIBILITY)
71+
if (LabCbrtTab[324] == 17746)
72+
LabCbrtTab[324] = 17745;
73+
if (LabCbrtTab[49] == 9455)
74+
LabCbrtTab[49] = 9454;
20875
#endif
209-
dst[0] = Base::RestrictRange(L);
210-
dst[1] = Base::RestrictRange(a);
211-
dst[2] = Base::RestrictRange(b);
212-
}
213-
}
214-
215-
int srccn;
216-
int coeffs[9];
217-
};
76+
const double D65[3] = { 0.950456, 1., 1.088754 };
77+
const double sRGB2XYZ_D65[9] = { 0.412453, 0.357580, 0.180423, 0.212671, 0.715160, 0.072169, 0.019334, 0.119193, 0.950227 };
78+
const double shift(1 << LAB_SHIFT);
79+
for (int i = 0; i < 3; i++)
80+
for (int j = 0; j < 3; j++)
81+
LabCoeffsTab[i * 3 + j] = Round(shift * sRGB2XYZ_D65[i * 3 + j] / D65[i]);
82+
LabTabsInited = true;
21883
}
21984

85+
//--------------------------------------------------------------------------------------------------
86+
22087
void BgrToLab(const uint8_t* bgr, size_t bgrStride, size_t width, size_t height, uint8_t* lab, size_t labStride)
22188
{
222-
#if 1
223-
LabV1::RGB2Lab_b _lab(3, 0);
89+
LabInitTabs();
22490
for (size_t row = 0; row < height; ++row)
22591
{
226-
const uint8_t* pBgr = bgr + row * bgrStride;
92+
const uint8_t* pBgr = bgr + row * bgrStride, * pEnd = pBgr + width * 3;
22793
uint8_t* pLab = lab + row * labStride;
228-
_lab(pBgr, pLab, width);
94+
for (; pBgr < pEnd; pBgr += 3, pLab += 3)
95+
RgbToLab(pBgr[2], pBgr[1], pBgr[0], pLab);
22996
}
230-
231-
#else
232-
for (size_t row = 0; row < height; ++row)
233-
{
234-
const uint8_t* pBgr = bgr + row * bgrStride;
235-
uint8_t* pLab = lab + row * labStride;
236-
for (const uint8_t* pBgrEnd = pBgr + width * 3; pBgr < pBgrEnd; pBgr += 3, pLab += 3)
237-
BgrToLab(pBgr[0], pBgr[1], pBgr[2], pLab);
238-
}
239-
#endif
24097
}
24198
}
24299
}

src/Simd/SimdBgrToLab.h

+54-52
Original file line numberDiff line numberDiff line change
@@ -24,67 +24,69 @@
2424
#ifndef __SimdBgrToLab_h__
2525
#define __SimdBgrToLab_h__
2626

27-
#include "Simd/SimdDefs.h"
27+
#include "Simd/SimdMath.h"
2828

2929
namespace Simd
3030
{
3131
namespace Base
3232
{
33-
namespace LabV0
33+
const int LAB_GAMMA_SHIFT = 3;
34+
35+
const int LabGammaTabSize = 256;
36+
extern uint16_t LabGammaTab[LabGammaTabSize];
37+
38+
const int LabCbrtTabSize = 256 * 3 / 2 * (1 << LAB_GAMMA_SHIFT);
39+
extern uint16_t LabCbrtTab[LabCbrtTabSize];
40+
41+
const int LabCoeffsTabSize = 9;
42+
extern uint32_t LabCoeffsTab[LabCoeffsTabSize];
43+
44+
void LabInitTabs();
45+
46+
const int LAB_SHIFT = 12;
47+
const int LAB_ROUND = 1 << (LAB_SHIFT - 1);
48+
49+
const int LAB_SHIFT2 = LAB_SHIFT + LAB_GAMMA_SHIFT;
50+
const int LAB_ROUND2 = 1 << (LAB_SHIFT2 - 1);
51+
52+
const int LAB_L_SCALE = (116 * 255 + 50) / 100;
53+
const int LAB_L_SHIFT = -((16 * 255 * (1 << LAB_SHIFT2) + 50) / 100);
54+
55+
const int LAB_A_SCALE = 500;
56+
const int LAB_B_SCALE = 200;
57+
const int LAB_AB_SHIFT = 128 * (1 << LAB_SHIFT2);
58+
59+
SIMD_INLINE int LabDescale(int value)
60+
{
61+
return (value + LAB_ROUND) >> LAB_SHIFT;
62+
}
63+
64+
SIMD_INLINE int LabDescale2(int value)
3465
{
35-
#define X(xyz) xyz.data[0]
36-
#define Y(xyz) xyz.data[1]
37-
#define Z(xyz) xyz.data[2]
38-
39-
typedef union
40-
{
41-
double data[3];
42-
struct { double r, g, b; };
43-
struct { double L, A, B; };
44-
struct { double l, c, h; };
45-
} DoubleTriplet;
46-
47-
const double eps = (6 * 6 * 6) / (29.0 * 29.0 * 29.0), kap = (29 * 29 * 29) / (3.0 * 3.0 * 3.0);
48-
49-
const DoubleTriplet xyzReferenceValues = { {0.95047, 1.0, 1.08883} };
50-
51-
SIMD_INLINE DoubleTriplet xyzFromRgb(DoubleTriplet rgb)
52-
{
53-
for (int i = 0; i < 3; ++i)
54-
{
55-
double v = rgb.data[i];
56-
rgb.data[i] = (v > 0.04045) ? pow(((v + 0.055) / 1.055), 2.4) : (v / 12.92);
57-
}
58-
DoubleTriplet temp = { {
59-
rgb.r * 0.4124564 + rgb.g * 0.3575761 + rgb.b * 0.1804375,
60-
rgb.r * 0.2126729 + rgb.g * 0.7151522 + rgb.b * 0.0721750,
61-
rgb.r * 0.0193339 + rgb.g * 0.1191920 + rgb.b * 0.9503041
62-
} };
63-
return temp;
64-
}
65-
66-
SIMD_INLINE DoubleTriplet labFromXyz(DoubleTriplet xyz)
67-
{
68-
for (int i = 0; i < 3; ++i)
69-
{
70-
xyz.data[i] /= xyzReferenceValues.data[i];
71-
double v = xyz.data[i];
72-
xyz.data[i] = (v > eps) ? pow(v, (1 / 3.0)) : ((kap * v + 16) / 116.0);
73-
}
74-
DoubleTriplet temp = { {(116 * Y(xyz)) - 16, 500 * (X(xyz) - Y(xyz)), 200 * (Y(xyz) - Z(xyz))} };
75-
return temp;
76-
}
77-
78-
DoubleTriplet labFromRgb(DoubleTriplet rgb) { return labFromXyz(xyzFromRgb(rgb)); }
66+
return (value + LAB_ROUND2) >> LAB_SHIFT2;
7967
}
8068

81-
SIMD_INLINE void BgrToLab(int blue, int green, int red, uint8_t* lab)
69+
SIMD_INLINE void RgbToLab(int red, int green, int blue, uint8_t *lab)
8270
{
83-
LabV0::DoubleTriplet _rgb{red / 255.0 , green / 255.0, blue / 255.0 };
84-
LabV0::DoubleTriplet _lab = labFromRgb(_rgb);
85-
lab[0] = int(_lab.data[0]);
86-
lab[1] = int(_lab.data[1]);
87-
lab[2] = int(_lab.data[2]);
71+
int R = LabGammaTab[red];
72+
int G = LabGammaTab[green];
73+
int B = LabGammaTab[blue];
74+
75+
int iX = LabDescale(R * LabCoeffsTab[0] + G * LabCoeffsTab[1] + B * LabCoeffsTab[2]);
76+
int iY = LabDescale(R * LabCoeffsTab[3] + G * LabCoeffsTab[4] + B * LabCoeffsTab[5]);
77+
int iZ = LabDescale(R * LabCoeffsTab[6] + G * LabCoeffsTab[7] + B * LabCoeffsTab[8]);
78+
79+
int fX = LabCbrtTab[iX];
80+
int fY = LabCbrtTab[iY];
81+
int fZ = LabCbrtTab[iZ];
82+
83+
int L = LabDescale2(LAB_L_SCALE * fY + LAB_L_SHIFT);
84+
int a = LabDescale2(LAB_A_SCALE * (fX - fY) + LAB_AB_SHIFT);
85+
int b = LabDescale2(LAB_B_SCALE * (fY - fZ) + LAB_AB_SHIFT);
86+
87+
lab[0] = Base::RestrictRange(L);
88+
lab[1] = Base::RestrictRange(a);
89+
lab[2] = Base::RestrictRange(b);
8890
}
8991
}
9092
}

0 commit comments

Comments
 (0)