Skip to content

Commit f56e46d

Browse files
committed
+add Base implementation of function BgrToLab (part 2).
1 parent fc7578f commit f56e46d

File tree

3 files changed

+206
-1
lines changed

3 files changed

+206
-1
lines changed

src/Simd/SimdBaseBgrToLab.cpp

+169
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,189 @@
2323
*/
2424
#include "Simd/SimdBgrToLab.h"
2525
#include "Simd/SimdBase.h"
26+
#include "Simd/SimdMath.h"
2627

2728
namespace Simd
2829
{
2930
namespace Base
3031
{
32+
namespace LabV1
33+
{
34+
inline double FromRaw(uint64_t raw)
35+
{
36+
return *((double*)&raw);
37+
}
38+
39+
#define CV_DESCALE(x,n) (((x) + (1 << ((n)-1))) >> (n))
40+
const int xyz_shift = 12;
41+
42+
//const double D65[3] = { 0.950456, 1., 1.088754 };
43+
const double D65[3] = { FromRaw(0x3fee6a22b3892ee8),
44+
1.0 ,
45+
FromRaw(0x3ff16b8950763a19) };
46+
47+
//static const double sRGB2XYZ_D65[] =
48+
//{
49+
// 0.412453, 0.357580, 0.180423,
50+
// 0.212671, 0.715160, 0.072169,
51+
// 0.019334, 0.119193, 0.950227
52+
//};
53+
54+
const double sRGB2XYZ_D65[] =
55+
{
56+
FromRaw(0x3fda65a14488c60d),
57+
FromRaw(0x3fd6e297396d0918),
58+
FromRaw(0x3fc71819d2391d58),
59+
FromRaw(0x3fcb38cda6e75ff6),
60+
FromRaw(0x3fe6e297396d0918),
61+
FromRaw(0x3fb279aae6c8f755),
62+
FromRaw(0x3f93cc4ac6cdaf4b),
63+
FromRaw(0x3fbe836eb4e98138),
64+
FromRaw(0x3fee68427418d691)
65+
};
66+
67+
enum { LAB_CBRT_TAB_SIZE = 1024, GAMMA_TAB_SIZE = 1024 };
68+
static const float LabCbrtTabScale = float(LAB_CBRT_TAB_SIZE * 2) / float(3);
69+
70+
static const float GammaTabScale((int)GAMMA_TAB_SIZE);
71+
72+
static uint16_t sRGBGammaTab_b[256];
73+
74+
#undef lab_shift
75+
#define lab_shift xyz_shift
76+
#define gamma_shift 3
77+
#define lab_shift2 (lab_shift + gamma_shift)
78+
#define LAB_CBRT_TAB_SIZE_B (256*3/2*(1<<gamma_shift))
79+
static uint16_t LabCbrtTab_b[LAB_CBRT_TAB_SIZE_B];
80+
81+
//all constants should be presented through integers to keep bit-exactness
82+
static const double gammaThreshold = double(809) / double(20000); // 0.04045
83+
static const double gammaInvThreshold = double(7827) / double(2500000); // 0.0031308
84+
static const double gammaLowScale = double(323) / double(25); // 12.92
85+
static const double gammaPower = double(12) / double(5); // 2.4
86+
static const double gammaXshift = double(11) / double(200); // 0.055
87+
88+
static const float lthresh = float(216) / float(24389); // 0.008856f = (6/29)^3
89+
static const float lscale = float(841) / float(108); // 7.787f = (29/3)^3/(29*4)
90+
static const float lbias = float(16) / float(116);
91+
//static const softfloat f255(255);
92+
93+
94+
static inline float applyGamma(float x)
95+
{
96+
//return x <= 0.04045f ? x*(1.f/12.92f) : (float)std::pow((double)(x + 0.055)*(1./1.055), 2.4);
97+
98+
double xd = x;
99+
return (xd <= gammaThreshold ?
100+
xd / gammaLowScale :
101+
pow((xd + gammaXshift) / (1.0 + gammaXshift), gammaPower));
102+
}
103+
104+
static void initLabTabs()
105+
{
106+
static bool initialized = false;
107+
if (!initialized)
108+
{
109+
float scale = 1.0f / float(GammaTabScale);
110+
static const float intScale(255 * (1 << gamma_shift));
111+
for (int i = 0; i < 256; i++)
112+
{
113+
float x = float(i) / 255.0f;
114+
sRGBGammaTab_b[i] = (uint16_t)(Round(intScale * applyGamma(x)));
115+
}
116+
117+
static const float cbTabScale(1.0 / (255.0 * (1 << gamma_shift)));
118+
static const float lshift2(1 << lab_shift2);
119+
for (int i = 0; i < LAB_CBRT_TAB_SIZE_B; i++)
120+
{
121+
float x = cbTabScale * float(i);
122+
LabCbrtTab_b[i] = (uint16_t)(Round(lshift2 * (x < lthresh ? (x * lscale + lbias) : cbrt(x))));
123+
}
124+
125+
initialized = true;
126+
}
127+
}
128+
129+
struct RGB2Lab_b
130+
{
131+
typedef uint8_t channel_type;
132+
133+
RGB2Lab_b(int _srccn, int blueIdx)
134+
: srccn(_srccn)
135+
{
136+
initLabTabs();
137+
138+
double whitePt[3];
139+
for (int i = 0; i < 3; i++)
140+
whitePt[i] = D65[i];
141+
142+
const double lshift(1 << lab_shift);
143+
for (int i = 0; i < 3; i++)
144+
{
145+
double c[3];
146+
for (int j = 0; j < 3; j++)
147+
c[j] = sRGB2XYZ_D65[i * 3 + j];
148+
coeffs[i * 3 + (blueIdx ^ 2)] = Round(lshift * c[0] / whitePt[i]);
149+
coeffs[i * 3 + 1] = Round(lshift * c[1] / whitePt[i]);
150+
coeffs[i * 3 + blueIdx] = Round(lshift * c[2] / whitePt[i]);
151+
152+
assert(coeffs[i * 3] >= 0 && coeffs[i * 3 + 1] >= 0 && coeffs[i * 3 + 2] >= 0 &&
153+
coeffs[i * 3] + coeffs[i * 3 + 1] + coeffs[i * 3 + 2] < 2 * (1 << lab_shift));
154+
}
155+
}
156+
157+
void operator()(const uint8_t* src, uint8_t* dst, int n) const
158+
{
159+
const int Lscale = (116 * 255 + 50) / 100;
160+
const int Lshift = -((16 * 255 * (1 << lab_shift2) + 50) / 100);
161+
const uint16_t* tab = sRGBGammaTab_b;
162+
int i, scn = srccn;
163+
int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2],
164+
C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5],
165+
C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8];
166+
167+
for (int i = 0; i < n; i++, src += scn, dst += 3)
168+
{
169+
int R = tab[src[0]], G = tab[src[1]], B = tab[src[2]];
170+
int fX = LabCbrtTab_b[CV_DESCALE(R * C0 + G * C1 + B * C2, lab_shift)];
171+
int fY = LabCbrtTab_b[CV_DESCALE(R * C3 + G * C4 + B * C5, lab_shift)];
172+
int fZ = LabCbrtTab_b[CV_DESCALE(R * C6 + G * C7 + B * C8, lab_shift)];
173+
174+
int L = CV_DESCALE(Lscale * fY + Lshift, lab_shift2);
175+
int a = CV_DESCALE(500 * (fX - fY) + 128 * (1 << lab_shift2), lab_shift2);
176+
int b = CV_DESCALE(200 * (fY - fZ) + 128 * (1 << lab_shift2), lab_shift2);
177+
178+
dst[0] = Base::RestrictRange(L);
179+
dst[1] = Base::RestrictRange(a);
180+
dst[2] = Base::RestrictRange(b);
181+
}
182+
}
183+
184+
int srccn;
185+
int coeffs[9];
186+
};
187+
}
188+
31189
void BgrToLab(const uint8_t* bgr, size_t bgrStride, size_t width, size_t height, uint8_t* lab, size_t labStride)
32190
{
191+
#if 1
192+
LabV1::RGB2Lab_b _lab(3, 0);
193+
for (size_t row = 0; row < height; ++row)
194+
{
195+
const uint8_t* pBgr = bgr + row * bgrStride;
196+
uint8_t* pLab = lab + row * labStride;
197+
_lab(pBgr, pLab, width);
198+
}
199+
200+
#else
33201
for (size_t row = 0; row < height; ++row)
34202
{
35203
const uint8_t* pBgr = bgr + row * bgrStride;
36204
uint8_t* pLab = lab + row * labStride;
37205
for (const uint8_t* pBgrEnd = pBgr + width * 3; pBgr < pBgrEnd; pBgr += 3, pLab += 3)
38206
BgrToLab(pBgr[0], pBgr[1], pBgr[2], pLab);
39207
}
208+
#endif
40209
}
41210
}
42211
}

src/Test/Test.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ namespace Test
9595
TEST_ADD_GROUP_A0(BgrToGray);
9696
TEST_ADD_GROUP_A0(BgrToHsl);
9797
TEST_ADD_GROUP_A0(BgrToHsv);
98-
TEST_ADD_GROUP_A0(BgrToLab);
98+
TEST_ADD_GROUP_AS(BgrToLab);
9999
TEST_ADD_GROUP_A0(BgrToRgb);
100100
TEST_ADD_GROUP_A0(GrayToBgr);
101101
TEST_ADD_GROUP_A0(GrayToY);

src/Test/TestAnyToAny.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
#include "Test/TestString.h"
2828
#include "Test/TestRandom.h"
2929

30+
#ifdef SIMD_OPENCV_ENABLE
31+
#include <opencv2/core/core.hpp>
32+
#include <opencv2/imgproc/imgproc.hpp>
33+
#endif
34+
3035
namespace Test
3136
{
3237
namespace
@@ -531,4 +536,35 @@ namespace Test
531536

532537
return result;
533538
}
539+
540+
//-----------------------------------------------------------------------------------------------------
541+
542+
bool BgrToLabSpecialTest()
543+
{
544+
bool result = true;
545+
#ifdef SIMD_OPENCV_ENABLE
546+
TEST_LOG_SS(Info, "Test OpenCV and Simd image conversion from BGR to LAB pixel format.");
547+
548+
View src(W, H, View::Bgr24, NULL, TEST_ALIGN(W));
549+
FillRandom(src);
550+
551+
View dst1(W, H, View::Bgr24, NULL, TEST_ALIGN(W));
552+
View dst2(W, H, View::Bgr24, NULL, TEST_ALIGN(W));
553+
554+
Simd::Fill(dst1, 1);
555+
Simd::Fill(dst2, 2);
556+
557+
src.data[0] = 89;
558+
src.data[1] = 162;
559+
src.data[2] = 252;
560+
561+
TEST_EXECUTE_AT_LEAST_MIN_TIME(cv::cvtColor((cv::Mat)src, (cv::Mat)(dst1.Ref()), cv::COLOR_BGR2Lab, 3));
562+
563+
TEST_EXECUTE_AT_LEAST_MIN_TIME(Simd::BgrToLab(src, dst2));
564+
565+
result = result && Compare(dst1, dst2, 0, true, 64);
566+
#endif
567+
return result;
568+
}
569+
534570
}

0 commit comments

Comments
 (0)