Skip to content

Commit f0ef7bd

Browse files
committed
Lab and Luv tests: rewritten, constants explained
1 parent 0e6c335 commit f0ef7bd

File tree

1 file changed

+76
-53
lines changed

1 file changed

+76
-53
lines changed

modules/imgproc/test/test_color.cpp

Lines changed: 76 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,17 +1010,22 @@ double CV_ColorLabTest::get_success_error_level( int /*test_case_idx*/, int i, i
10101010
}
10111011

10121012

1013-
static const double _1_3 = 0.333333333333;
1014-
const static float _1_3f = static_cast<float>(_1_3);
1015-
1016-
10171013
void CV_ColorLabTest::convert_row_bgr2abc_32f_c3(const float* src_row, float* dst_row, int n)
10181014
{
10191015
int depth = test_mat[INPUT][0].depth();
10201016
float Lscale = depth == CV_8U ? 255.f/100.f : depth == CV_16U ? 65535.f/100.f : 1.f;
10211017
float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f;
10221018
float M[9];
10231019

1020+
// 7.787f = (29/3)^3/(29*4)
1021+
static const float lowScale = 29.f*29.f/(27.f*4.f);
1022+
// 0.008856f = (6/29)^3
1023+
static const float lthresh = 6.f*6.f*6.f/(29.f*29.f*29.f);
1024+
// 903.3 = (29/3)^3
1025+
static const float yscale = 29.f*29.f*29.f/27.f;
1026+
1027+
static const float f16of116 = 16.f/116.f;
1028+
10241029
for (int j = 0; j < 9; j++ )
10251030
M[j] = (float)RGB2XYZ[j];
10261031

@@ -1031,25 +1036,14 @@ void CV_ColorLabTest::convert_row_bgr2abc_32f_c3(const float* src_row, float* ds
10311036
float B = src_row[x];
10321037

10331038
float X = (R * M[0] + G * M[1] + B * M[2]) / Xn;
1034-
float Y = R * M[3] + G * M[4] + B * M[5];
1039+
float Y = R * M[3] + G * M[4] + B * M[5];
10351040
float Z = (R * M[6] + G * M[7] + B * M[8]) / Zn;
1036-
float fX = X > 0.008856f ? pow(X, _1_3f) :
1037-
(7.787f * X + 16.f / 116.f);
1038-
float fZ = Z > 0.008856f ? pow(Z, _1_3f):
1039-
(7.787f * Z + 16.f / 116.f);
10401041

1041-
float L = 0.0f, fY = 0.0f;
1042-
if (Y > 0.008856f)
1043-
{
1044-
fY = pow(Y, _1_3f);
1045-
L = 116.f * fY - 16.f;
1046-
}
1047-
else
1048-
{
1049-
fY = 7.787f * Y + 16.f / 116.f;
1050-
L = 903.3f * Y;
1051-
}
1042+
float fX = X > lthresh ? cubeRoot(X) : (lowScale * X + f16of116);
1043+
float fY = Y > lthresh ? cubeRoot(Y) : (lowScale * Y + f16of116);
1044+
float fZ = Z > lthresh ? cubeRoot(Z) : (lowScale * Z + f16of116);
10521045

1046+
float L = Y > lthresh ? (116.f*fY - 16.f) : (yscale*Y);
10531047
float a = 500.f * (fX - fY);
10541048
float b = 200.f * (fY - fZ);
10551049

@@ -1069,19 +1063,27 @@ void CV_ColorLabTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* d
10691063
for(int j = 0; j < 9; j++ )
10701064
M[j] = (float)XYZ2RGB[j];
10711065

1072-
static const float lthresh = 903.3f * 0.008856f;
1073-
static const float thresh = 7.787f * 0.008856f + 16.0f / 116.0f;
1066+
// 0.008856f * 903.3f = (6/29)^3*(29/3)^3 = 8
1067+
static const float lThresh = 8.f;
1068+
// 7.787f * 0.008856f + 16.0f / 116.0f = 6/29
1069+
static const float fThresh = 6.f/29.f;
1070+
static const float lbias = 16.f/116.f;
1071+
// 7.787f = (29/3)^3/(29*4)
1072+
static const float lowScale = 29.f*29.f/(27.f*4.f);
1073+
// 903.3 = (29/3)^3
1074+
static const float yscale = 29.f*29.f*29.f/27.f;
1075+
10741076
for (int x = 0, end = n * 3; x < end; x += 3)
10751077
{
10761078
float L = src_row[x] * Lscale;
10771079
float a = src_row[x + 1] - ab_bias;
10781080
float b = src_row[x + 2] - ab_bias;
10791081

10801082
float FY = 0.0f, Y = 0.0f;
1081-
if (L <= lthresh)
1083+
if (L <= lThresh)
10821084
{
1083-
Y = L / 903.3f;
1084-
FY = 7.787f * Y + 16.0f / 116.0f;
1085+
Y = L / yscale;
1086+
FY = lowScale * Y + lbias;
10851087
}
10861088
else
10871089
{
@@ -1095,8 +1097,8 @@ void CV_ColorLabTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* d
10951097
float FXZ[] = { FX, FZ };
10961098
for (int k = 0; k < 2; ++k)
10971099
{
1098-
if (FXZ[k] <= thresh)
1099-
FXZ[k] = (FXZ[k] - 16.0f / 116.0f) / 7.787f;
1100+
if (FXZ[k] <= fThresh)
1101+
FXZ[k] = (FXZ[k] - lbias) / lowScale;
11001102
else
11011103
FXZ[k] = FXZ[k] * FXZ[k] * FXZ[k];
11021104
}
@@ -1155,25 +1157,37 @@ void CV_ColorLuvTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* d
11551157
{
11561158
int depth = test_mat[INPUT][0].depth();
11571159
float Lscale = depth == CV_8U ? 255.f/100.f : depth == CV_16U ? 65535.f/100.f : 1.f;
1160+
static const float uLow = -134.f, uHigh = 220.f, uRange = uHigh - uLow;
1161+
static const float vLow = -140.f, vHigh = 122.f, vRange = vHigh - vLow;
11581162
int j;
11591163

11601164
float M[9];
1161-
float un = 4.f*Xn/(Xn + 15.f*1.f + 3*Zn);
1162-
float vn = 9.f*1.f/(Xn + 15.f*1.f + 3*Zn);
1165+
// Yn == 1
1166+
float dd = Xn + 15.f*1.f + 3.f*Zn;
1167+
float un = 4.f*13.f*Xn/dd;
1168+
float vn = 9.f*13.f/dd;
1169+
11631170
float u_scale = 1.f, u_bias = 0.f;
11641171
float v_scale = 1.f, v_bias = 0.f;
11651172

11661173
for( j = 0; j < 9; j++ )
11671174
M[j] = (float)RGB2XYZ[j];
11681175

1176+
//0.72033 = 255/(220+134), 96.525 = 134*255/(220+134)
1177+
//0.9732 = 255/(140+122), 136.259 = 140*255/(140+122)
11691178
if( depth == CV_8U )
11701179
{
1171-
u_scale = 0.720338983f;
1172-
u_bias = 96.5254237f;
1173-
v_scale = 0.973282442f;
1174-
v_bias = 136.2595419f;
1180+
u_scale = 255.f/uRange;
1181+
u_bias = -uLow*255.f/uRange;
1182+
v_scale = 255.f/vRange;
1183+
v_bias = -vLow*255.f/vRange;
11751184
}
11761185

1186+
// 0.008856f = (6/29)^3
1187+
static const float lthresh = 6.f*6.f*6.f/(29.f*29.f*29.f);
1188+
// 903.3 = (29/3)^3
1189+
static const float yscale = 29.f*29.f*29.f/27.f;
1190+
11771191
for( j = 0; j < n*3; j += 3 )
11781192
{
11791193
float r = src_row[j+2];
@@ -1189,14 +1203,14 @@ void CV_ColorLuvTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* d
11891203
L = u = v = 0;
11901204
else
11911205
{
1192-
if( Y > 0.008856f )
1193-
L = (float)(116.*pow((double)Y,_1_3) - 16.);
1206+
if( Y > lthresh )
1207+
L = 116.f*cubeRoot(Y) - 16.f;
11941208
else
1195-
L = 903.3f * Y;
1209+
L = yscale * Y;
11961210

1197-
d = 1.f/d;
1198-
u = 13*L*(4*X*d - un);
1199-
v = 13*L*(9*Y*d - vn);
1211+
d = 4.f*13.f/d;
1212+
u = L*(X*d - un);
1213+
v = L*(9.f/4.f*Y*d - vn);
12001214
}
12011215
dst_row[j] = L*Lscale;
12021216
dst_row[j+1] = u*u_scale + u_bias;
@@ -1209,24 +1223,34 @@ void CV_ColorLuvTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* d
12091223
{
12101224
int depth = test_mat[INPUT][0].depth();
12111225
float Lscale = depth == CV_8U ? 100.f/255.f : depth == CV_16U ? 100.f/65535.f : 1.f;
1226+
static const float uLow = -134.f, uHigh = 220.f, uRange = uHigh - uLow;
1227+
static const float vLow = -140.f, vHigh = 122.f, vRange = vHigh - vLow;
1228+
12121229
int j;
12131230
float M[9];
1214-
float un = 4.f*Xn/(Xn + 15.f*1.f + 3*Zn);
1215-
float vn = 9.f*1.f/(Xn + 15.f*1.f + 3*Zn);
1231+
// Yn == 1
1232+
float dd = Xn + 15.f*1.f + 3.f*Zn;
1233+
float un = 4*13.f*Xn/dd;
1234+
float vn = 9*13.f*1.f/dd;
1235+
12161236
float u_scale = 1.f, u_bias = 0.f;
12171237
float v_scale = 1.f, v_bias = 0.f;
12181238

12191239
for( j = 0; j < 9; j++ )
12201240
M[j] = (float)XYZ2RGB[j];
12211241

1242+
//0.72033 = 255/(220+134), 96.525 = 134*255/(220+134)
1243+
//0.9732 = 255/(140+122), 136.259 = 140*255/(140+122)
12221244
if( depth == CV_8U )
12231245
{
1224-
u_scale = 1.f/0.720338983f;
1225-
u_bias = 96.5254237f;
1226-
v_scale = 1.f/0.973282442f;
1227-
v_bias = 136.2595419f;
1246+
u_scale = uRange/255.f;
1247+
u_bias = -uLow*255.f/uRange;
1248+
v_scale = vRange/255.f;
1249+
v_bias = -vLow*255.f/vRange;
12281250
}
12291251

1252+
// (1 / 903.3) = (3/29)^3
1253+
static const float yscale = 27.f/(29.f*29.f*29.f);
12301254
for( j = 0; j < n*3; j += 3 )
12311255
{
12321256
float L = src_row[j]*Lscale;
@@ -1241,16 +1265,15 @@ void CV_ColorLuvTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* d
12411265
}
12421266
else
12431267
{
1244-
Y = L * (1.f/903.3f);
1245-
if( L == 0 )
1246-
L = 0.001f;
1268+
Y = L * yscale;
12471269
}
12481270

1249-
u = u/(13*L) + un;
1250-
v = v/(13*L) + vn;
1251-
1252-
X = -9*Y*u/((u - 4)*v - u*v);
1253-
Z = (9*Y - 15*v*Y - v*X)/(3*v);
1271+
float up = 3.f*(u + L*un);
1272+
float vp = 0.25f/(v + L*vn);
1273+
if(vp > 0.25f) vp = 0.25f;
1274+
if(vp < -0.25f) vp = -0.25f;
1275+
X = Y*3.f*up*vp;
1276+
Z = Y*(((12.f*13.f)*L - up)*vp - 5.f);
12541277

12551278
float r = M[0]*X + M[1]*Y + M[2]*Z;
12561279
float g = M[3]*X + M[4]*Y + M[5]*Z;

0 commit comments

Comments
 (0)