@@ -70,11 +70,11 @@ class CV_ColorCvtBaseTest : public cvtest::ArrayTest
70
70
71
71
// called from default implementation of convert_backward
72
72
// for cases of bit-exact functions
73
- virtual int convert_row_abc2bgr_8u_c3 ( const uchar* src_row, uchar* dst_row, int n );
73
+ virtual int convert_row_abc2bgr_8u_c3 ( const uchar* src_row, uchar* dst_row, int n, int cn );
74
74
75
75
// called from default implementation of convert_forward
76
76
// for cases of bit-exact functions
77
- virtual int convert_row_bgr2abc_8u_c3 (const uchar *src_row, uchar *dst_row, int n );
77
+ virtual int convert_row_bgr2abc_8u_c3 (const uchar *src_row, uchar *dst_row, int n, int cn );
78
78
79
79
const char * fwd_code_str;
80
80
const char * inv_code_str;
@@ -237,7 +237,7 @@ void CV_ColorCvtBaseTest::convert_forward( const Mat& src, Mat& dst )
237
237
const uchar* src_row = src.ptr (i);
238
238
uchar* dst_row = dst.ptr (i);
239
239
240
- int processed = convert_row_bgr2abc_8u_c3 ( src_row, dst_row, cols );
240
+ int processed = convert_row_bgr2abc_8u_c3 ( src_row, dst_row, cols, cn );
241
241
if (processed != cols)
242
242
{
243
243
for ( j = 0 ; j < cols; j++ )
@@ -313,14 +313,14 @@ void CV_ColorCvtBaseTest::convert_row_abc2bgr_32f_c3( const float* /*src_row*/,
313
313
314
314
315
315
int CV_ColorCvtBaseTest::convert_row_abc2bgr_8u_c3 (const uchar * /* src_row*/ ,
316
- uchar * /* dst_row*/ , int /* n*/ )
316
+ uchar * /* dst_row*/ , int /* n*/ , int /* cn */ )
317
317
{
318
318
return 0 ;
319
319
}
320
320
321
321
322
- int CV_ColorCvtBaseTest::convert_row_bgr2abc_8u_c3 ( const uchar* /* src_row*/ ,
323
- uchar* /* dst_row*/ , int /* n*/ )
322
+ int CV_ColorCvtBaseTest::convert_row_bgr2abc_8u_c3 (const uchar* /* src_row*/ ,
323
+ uchar* /* dst_row*/ , int /* n*/ , int /* cn */ )
324
324
{
325
325
return 0 ;
326
326
}
@@ -349,7 +349,7 @@ void CV_ColorCvtBaseTest::convert_backward( const Mat& src, const Mat& dst, Mat&
349
349
const uchar* src_row = dst.ptr (i);
350
350
uchar* dst_row = dst2.ptr (i);
351
351
352
- int processed = convert_row_abc2bgr_8u_c3 (src_row, dst_row, dst_cols);
352
+ int processed = convert_row_abc2bgr_8u_c3 (src_row, dst_row, dst_cols, cn );
353
353
354
354
if (processed != dst_cols)
355
355
{
@@ -1027,6 +1027,57 @@ void CV_ColorXYZTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* d
1027
1027
1028
1028
1029
1029
// // rgb <=> L*a*b*
1030
+
1031
+ // taken from color.cpp
1032
+
1033
+ static ushort sRGBGammaTab_b [256 ], linearGammaTab_b[256 ];
1034
+ enum { inv_gamma_shift = 12 , INV_GAMMA_TAB_SIZE = (1 << inv_gamma_shift) };
1035
+ static ushort sRGBInvGammaTab_b [INV_GAMMA_TAB_SIZE], linearInvGammaTab_b[INV_GAMMA_TAB_SIZE];
1036
+ #undef lab_shift
1037
+ // #define lab_shift xyz_shift
1038
+ #define lab_shift 12
1039
+ #define gamma_shift 3
1040
+ #define lab_shift2 (lab_shift + gamma_shift)
1041
+ #define LAB_CBRT_TAB_SIZE_B (256 *3 /2 *(1 <<gamma_shift))
1042
+ static ushort LabCbrtTab_b[LAB_CBRT_TAB_SIZE_B];
1043
+
1044
+ enum
1045
+ {
1046
+ lab_base_shift = 14 ,
1047
+ LAB_BASE = (1 << lab_base_shift),
1048
+ };
1049
+
1050
+ #define CV_DESCALE (x,n ) (((x) + (1 << ((n)-1 ))) >> (n))
1051
+
1052
+ static ushort LabToYF_b[256 *2 ];
1053
+ static const int minABvalue = -8145 ;
1054
+ static int abToXZ_b[LAB_BASE*9 /4 ];
1055
+
1056
+ // all constants should be presented through integers to keep bit-exactness
1057
+ static const softdouble gammaThreshold = softdouble(809 )/softdouble(20000 ); // 0.04045
1058
+ static const softdouble gammaInvThreshold = softdouble(7827 )/softdouble(2500000 ); // 0.0031308
1059
+ static const softdouble gammaLowScale = softdouble(323 )/softdouble(25 ); // 12.92
1060
+ static const softdouble gammaPower = softdouble(12 )/softdouble(5 ); // 2.4
1061
+ static const softdouble gammaXshift = softdouble(11 )/softdouble(200 ); // 0.055
1062
+
1063
+ static inline softfloat applyGamma (softfloat x)
1064
+ {
1065
+ // return x <= 0.04045f ? x*(1.f/12.92f) : (float)std::pow((double)(x + 0.055)*(1./1.055), 2.4);
1066
+ softdouble xd = x;
1067
+ return (xd <= gammaThreshold ?
1068
+ xd/gammaLowScale :
1069
+ pow ((xd + gammaXshift)/(softdouble::one ()+gammaXshift), gammaPower));
1070
+ }
1071
+
1072
+ static inline softfloat applyInvGamma (softfloat x)
1073
+ {
1074
+ // return x <= 0.0031308 ? x*12.92f : (float)(1.055*std::pow((double)x, 1./2.4) - 0.055);
1075
+ softdouble xd = x;
1076
+ return (xd <= gammaInvThreshold ?
1077
+ xd*gammaLowScale :
1078
+ pow (xd, softdouble::one ()/gammaPower)*(softdouble::one ()+gammaXshift) - gammaXshift);
1079
+ }
1080
+
1030
1081
static inline float applyGamma (float x)
1031
1082
{
1032
1083
return x <= 0 .04045f ? x*(1 .f /12 .92f ) : (float )std::pow ((double )(x + 0.055 )*(1 ./1.055 ), 2.4 );
@@ -1037,6 +1088,90 @@ static inline float applyInvGamma(float x)
1037
1088
return x <= 0.0031308 ? x*12 .92f : (float )(1.055 *std::pow ((double )x, 1 ./2.4 ) - 0.055 );
1038
1089
}
1039
1090
1091
+ static void initLabTabs ()
1092
+ {
1093
+ static bool initialized = false ;
1094
+ if (!initialized)
1095
+ {
1096
+ static const softfloat lthresh = softfloat (216 ) / softfloat (24389 ); // 0.008856f = (6/29)^3
1097
+ static const softfloat lscale = softfloat (841 ) / softfloat (108 ); // 7.787f = (29/3)^3/(29*4)
1098
+ static const softfloat lbias = softfloat (16 ) / softfloat (116 );
1099
+ static const softfloat f255 (255 );
1100
+
1101
+ static const softfloat intScale (255 *(1 << gamma_shift));
1102
+ for (int i = 0 ; i < 256 ; i++)
1103
+ {
1104
+ softfloat x = softfloat (i)/f255;
1105
+ sRGBGammaTab_b [i] = (ushort)(cvRound (intScale*applyGamma (x)));
1106
+ linearGammaTab_b[i] = (ushort)(i*(1 << gamma_shift));
1107
+ }
1108
+ static const softfloat invScale = softfloat::one ()/softfloat ((int )INV_GAMMA_TAB_SIZE);
1109
+ for (int i = 0 ; i < INV_GAMMA_TAB_SIZE; i++)
1110
+ {
1111
+ softfloat x = invScale*softfloat (i);
1112
+ sRGBInvGammaTab_b [i] = (ushort)(cvRound (f255*applyInvGamma (x)));
1113
+ linearInvGammaTab_b[i] = (ushort)(cvTrunc (f255*x));
1114
+ }
1115
+
1116
+ static const softfloat cbTabScale (softfloat::one ()/(f255*(1 << gamma_shift)));
1117
+ static const softfloat lshift2 (1 << lab_shift2);
1118
+ for (int i = 0 ; i < LAB_CBRT_TAB_SIZE_B; i++)
1119
+ {
1120
+ softfloat x = cbTabScale*softfloat (i);
1121
+ LabCbrtTab_b[i] = (ushort)(cvRound (lshift2 * (x < lthresh ? mulAdd (x, lscale, lbias) : cbrt (x))));
1122
+ }
1123
+
1124
+ // Lookup table for L to y and ify calculations
1125
+ static const int BASE = (1 << 14 );
1126
+ for (int i = 0 ; i < 256 ; i++)
1127
+ {
1128
+ int y, ify;
1129
+ // 8 * 255.0 / 100.0 == 20.4
1130
+ if ( i <= 20 )
1131
+ {
1132
+ // yy = li / 903.3f;
1133
+ // y = L*100/903.3f; 903.3f = (29/3)^3, 255 = 17*3*5
1134
+ y = cvRound (softfloat (i*BASE*20 *9 )/softfloat (17 *29 *29 *29 ));
1135
+ // fy = 7.787f * yy + 16.0f / 116.0f; 7.787f = (29/3)^3/(29*4)
1136
+ ify = cvRound (softfloat (BASE)*(softfloat (16 )/softfloat (116 ) + softfloat (i*5 )/softfloat (3 *17 *29 )));
1137
+ }
1138
+ else
1139
+ {
1140
+ // fy = (li + 16.0f) / 116.0f;
1141
+ softfloat fy = (softfloat (i*100 *BASE)/softfloat (255 *116 ) +
1142
+ softfloat (16 *BASE)/softfloat (116 ));
1143
+ ify = cvRound (fy);
1144
+ // yy = fy * fy * fy;
1145
+ y = cvRound (fy*fy*fy/softfloat (BASE*BASE));
1146
+ }
1147
+
1148
+ LabToYF_b[i*2 ] = (ushort)y; // 2260 <= y <= BASE
1149
+ LabToYF_b[i*2 +1 ] = (ushort)ify; // 0 <= ify <= BASE
1150
+ }
1151
+
1152
+ // Lookup table for a,b to x,z conversion
1153
+ for (int i = minABvalue; i < LAB_BASE*9 /4 +minABvalue; i++)
1154
+ {
1155
+ int v;
1156
+ // 6.f/29.f*BASE = 3389.730
1157
+ if (i <= 3390 )
1158
+ {
1159
+ // fxz[k] = (fxz[k] - 16.0f / 116.0f) / 7.787f;
1160
+ // 7.787f = (29/3)^3/(29*4)
1161
+ v = i*108 /841 - BASE*16 /116 *108 /841 ;
1162
+ }
1163
+ else
1164
+ {
1165
+ // fxz[k] = fxz[k] * fxz[k] * fxz[k];
1166
+ v = i*i/BASE*i/BASE;
1167
+ }
1168
+ abToXZ_b[i-minABvalue] = v; // -1335 <= v <= 88231
1169
+ }
1170
+
1171
+ initialized = true ;
1172
+ }
1173
+ }
1174
+
1040
1175
class CV_ColorLabTest : public CV_ColorCvtBaseTest
1041
1176
{
1042
1177
public:
@@ -1046,11 +1181,14 @@ class CV_ColorLabTest : public CV_ColorCvtBaseTest
1046
1181
double get_success_error_level ( int test_case_idx, int i, int j );
1047
1182
void convert_row_bgr2abc_32f_c3 ( const float * src_row, float * dst_row, int n );
1048
1183
void convert_row_abc2bgr_32f_c3 ( const float * src_row, float * dst_row, int n );
1184
+ int convert_row_bgr2abc_8u_c3 ( const uchar *src_row, uchar *dst_row, int n, int cn );
1185
+ int convert_row_abc2bgr_8u_c3 ( const uchar *src_row, uchar *dst_row, int n, int cn );
1049
1186
};
1050
1187
1051
1188
1052
1189
CV_ColorLabTest::CV_ColorLabTest () : CV_ColorCvtBaseTest( true , true , false )
1053
1190
{
1191
+ initLabTabs ();
1054
1192
INIT_FWD_INV_CODES ( BGR2Lab, Lab2BGR );
1055
1193
}
1056
1194
@@ -1079,7 +1217,50 @@ void CV_ColorLabTest::get_test_array_types_and_sizes( int test_case_idx, vector<
1079
1217
double CV_ColorLabTest::get_success_error_level ( int /* test_case_idx*/ , int i, int j )
1080
1218
{
1081
1219
int depth = test_mat[i][j].depth ();
1082
- return depth == CV_8U ? 16 : depth == CV_16U ? 32 : 1e-3 ;
1220
+ // j == 0 is for forward code, j == 1 is for inverse code
1221
+ return (depth == CV_8U) ? 0 :
1222
+ // 16u is forbidden
1223
+ // (depth == CV_16U) ? 32 :
1224
+ srgb ? ((j == 0 ) ? 0.4 : 0.0055 ) : 1e-3 ;
1225
+ }
1226
+
1227
+
1228
+ int CV_ColorLabTest::convert_row_bgr2abc_8u_c3 (const uchar* src_row, uchar *dst_row, int n, int cn)
1229
+ {
1230
+ int coeffs[9 ];
1231
+ softdouble whitept[3 ] = {Xn, softdouble::one (), Zn};
1232
+
1233
+ static const softdouble lshift (1 << lab_shift);
1234
+ for (int i = 0 ; i < 3 ; i++)
1235
+ {
1236
+ coeffs[i*3 + (blue_idx^2 )] = cvRound (lshift*RGB2XYZ[i*3 ]/whitept[i]);
1237
+ coeffs[i*3 + 1 ] = cvRound (lshift*RGB2XYZ[i*3 +1 ]/whitept[i]);
1238
+ coeffs[i*3 + (blue_idx )] = cvRound (lshift*RGB2XYZ[i*3 +2 ]/whitept[i]);
1239
+ }
1240
+
1241
+ const int Lscale = (116 *255 +50 )/100 ;
1242
+ const int Lshift = -((16 *255 *(1 << lab_shift2) + 50 )/100 );
1243
+ const ushort* tab = srgb ? sRGBGammaTab_b : linearGammaTab_b;
1244
+ for (int x = 0 ; x < n; x++)
1245
+ {
1246
+ int R = src_row[x*cn + 0 ],
1247
+ G = src_row[x*cn + 1 ],
1248
+ B = src_row[x*cn + 2 ];
1249
+ R = tab[R], G = tab[G], B = tab[B];
1250
+ int fX = LabCbrtTab_b[CV_DESCALE (R*coeffs[0 ] + G*coeffs[1 ] + B*coeffs[2 ], lab_shift)];
1251
+ int fY = LabCbrtTab_b[CV_DESCALE (R*coeffs[3 ] + G*coeffs[4 ] + B*coeffs[5 ], lab_shift)];
1252
+ int fZ = LabCbrtTab_b[CV_DESCALE (R*coeffs[6 ] + G*coeffs[7 ] + B*coeffs[8 ], lab_shift)];
1253
+
1254
+ int L = CV_DESCALE ( Lscale*fY + Lshift, lab_shift2 );
1255
+ int a = CV_DESCALE ( 500 *(fX - fY ) + 128 *(1 << lab_shift2), lab_shift2 );
1256
+ int b = CV_DESCALE ( 200 *(fY - fZ ) + 128 *(1 << lab_shift2), lab_shift2 );
1257
+
1258
+ dst_row[x*3 ] = saturate_cast<uchar>(L);
1259
+ dst_row[x*3 + 1 ] = saturate_cast<uchar>(a);
1260
+ dst_row[x*3 + 2 ] = saturate_cast<uchar>(b);
1261
+ }
1262
+
1263
+ return n;
1083
1264
}
1084
1265
1085
1266
@@ -1137,6 +1318,71 @@ void CV_ColorLabTest::convert_row_bgr2abc_32f_c3(const float* src_row, float* ds
1137
1318
}
1138
1319
}
1139
1320
1321
+ int CV_ColorLabTest::convert_row_abc2bgr_8u_c3 (const uchar* src_row, uchar *dst_row, int n, int cn)
1322
+ {
1323
+ static const int base_shift = 14 ;
1324
+ static const int BASE = (1 << base_shift);
1325
+ static const int shift = lab_shift+(base_shift-inv_gamma_shift);
1326
+
1327
+ int coeffs[9 ];
1328
+ softdouble whitept[3 ] = {Xn, softdouble::one (), Zn};
1329
+
1330
+ static const softdouble lshift (1 << lab_shift);
1331
+ for (int i = 0 ; i < 3 ; i++)
1332
+ {
1333
+ coeffs[i+(blue_idx )*3 ] = cvRound (lshift*XYZ2RGB[i ]*whitept[i]);
1334
+ coeffs[i+ 1 *3 ] = cvRound (lshift*XYZ2RGB[i+3 ]*whitept[i]);
1335
+ coeffs[i+(blue_idx^2 )*3 ] = cvRound (lshift*XYZ2RGB[i+6 ]*whitept[i]);
1336
+ }
1337
+ ushort* tab = srgb ? sRGBInvGammaTab_b : linearInvGammaTab_b;
1338
+
1339
+ for (int x = 0 ; x < n; x++)
1340
+ {
1341
+ uchar LL = src_row[x*3 ];
1342
+ uchar aa = src_row[x*3 + 1 ];
1343
+ uchar bb = src_row[x*3 + 2 ];
1344
+
1345
+ int ro, go, bo, xx, yy, zz, ify;
1346
+
1347
+ yy = LabToYF_b[LL*2 ];
1348
+ ify = LabToYF_b[LL*2 +1 ];
1349
+
1350
+ int adiv, bdiv;
1351
+ // adiv = aa*BASE/500 - 128*BASE/500, bdiv = bb*BASE/200 - 128*BASE/200;
1352
+ // approximations with reasonable precision
1353
+ adiv = ((5 *aa*53687 + (1 << 7 )) >> 13 ) - 128 *BASE/500 ;
1354
+ bdiv = (( bb*41943 + (1 << 4 )) >> 9 ) - 128 *BASE/200 +1 ;
1355
+
1356
+ int ifxz[] = {ify + adiv, ify - bdiv};
1357
+
1358
+ for (int k = 0 ; k < 2 ; k++)
1359
+ {
1360
+ int & v = ifxz[k];
1361
+ v = abToXZ_b[v-minABvalue];
1362
+ }
1363
+ xx = ifxz[0 ]; /* yy = yy */ ; zz = ifxz[1 ];
1364
+
1365
+ ro = CV_DESCALE (coeffs[0 ]*xx + coeffs[1 ]*yy + coeffs[2 ]*zz, shift);
1366
+ go = CV_DESCALE (coeffs[3 ]*xx + coeffs[4 ]*yy + coeffs[5 ]*zz, shift);
1367
+ bo = CV_DESCALE (coeffs[6 ]*xx + coeffs[7 ]*yy + coeffs[8 ]*zz, shift);
1368
+
1369
+ ro = max (0 , min ((int )INV_GAMMA_TAB_SIZE-1 , ro));
1370
+ go = max (0 , min ((int )INV_GAMMA_TAB_SIZE-1 , go));
1371
+ bo = max (0 , min ((int )INV_GAMMA_TAB_SIZE-1 , bo));
1372
+
1373
+ ro = tab[ro];
1374
+ go = tab[go];
1375
+ bo = tab[bo];
1376
+
1377
+ dst_row[x*cn ] = saturate_cast<uchar>(bo);
1378
+ dst_row[x*cn + 1 ] = saturate_cast<uchar>(go);
1379
+ dst_row[x*cn + 2 ] = saturate_cast<uchar>(ro);
1380
+ if (cn == 4 ) dst_row[x*cn + 3 ] = 255 ;
1381
+ }
1382
+
1383
+ return n;
1384
+ }
1385
+
1140
1386
void CV_ColorLabTest::convert_row_abc2bgr_32f_c3 ( const float * src_row, float * dst_row, int n )
1141
1387
{
1142
1388
int depth = test_mat[INPUT][0 ].depth ();
@@ -1226,6 +1472,7 @@ class CV_ColorLuvTest : public CV_ColorCvtBaseTest
1226
1472
1227
1473
CV_ColorLuvTest::CV_ColorLuvTest () : CV_ColorCvtBaseTest( true , true , false )
1228
1474
{
1475
+ initLabTabs ();
1229
1476
INIT_FWD_INV_CODES ( BGR2Luv, Luv2BGR );
1230
1477
}
1231
1478
0 commit comments