1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 5 // By downloading, copying, installing or using the software you agree to this license. 6 // If you do not agree to this license, do not download, install, 7 // copy or use the software. 8 // 9 // 10 // Intel License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000, Intel Corporation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 22 // * Redistribution's in binary form must reproduce the above copyright notice, 23 // this list of conditions and the following disclaimer in the documentation 24 // and/or other materials provided with the distribution. 25 // 26 // * The name of Intel Corporation may not be used to endorse or promote products 27 // derived from this software without specific prior written permission. 28 // 29 // This software is provided by the copyright holders and contributors "as is" and 30 // any express or implied warranties, including, but not limited to, the implied 31 // warranties of merchantability and fitness for a particular purpose are disclaimed. 32 // In no event shall the Intel Corporation or contributors be liable for any direct, 33 // indirect, incidental, special, exemplary, or consequential damages 34 // (including, but not limited to, procurement of substitute goods or services; 35 // loss of use, data, or profits; or business interruption) however caused 36 // and on any theory of liability, whether in contract, strict liability, 37 // or tort (including negligence or otherwise) arising in any way out of 38 // the use of this software, even if advised of the possibility of such damage. 39 // 40 //M*/ 41 42 #include "test_precomp.hpp" 43 44 using namespace cv; 45 using namespace std; 46 47 /////////////////////////// base test class for color transformations ///////////////////////// 48 49 class CV_ColorCvtBaseTest : public cvtest::ArrayTest 50 { 51 public: 52 CV_ColorCvtBaseTest( bool custom_inv_transform, bool allow_32f, bool allow_16u ); 53 54 protected: 55 int prepare_test_case( int test_case_idx ); 56 void prepare_to_validation( int /*test_case_idx*/ ); 57 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 58 void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ); 59 60 // input --- fwd_transform -> ref_output[0] 61 virtual void convert_forward( const Mat& src, Mat& dst ); 62 // ref_output[0] --- inv_transform ---> ref_output[1] (or input -- copy --> ref_output[1]) 63 virtual void convert_backward( const Mat& src, const Mat& dst, Mat& dst2 ); 64 65 // called from default implementation of convert_forward 66 virtual void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); 67 68 // called from default implementation of convert_backward 69 virtual void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); 70 71 const char* fwd_code_str; 72 const char* inv_code_str; 73 74 void run_func(); 75 bool allow_16u, allow_32f; 76 int blue_idx; 77 bool inplace; 78 bool custom_inv_transform; 79 int fwd_code, inv_code; 80 bool test_cpp; 81 int hue_range; 82 }; 83 84 85 CV_ColorCvtBaseTest::CV_ColorCvtBaseTest( bool _custom_inv_transform, bool _allow_32f, bool _allow_16u ) 86 { 87 test_array[INPUT].push_back(NULL); 88 test_array[OUTPUT].push_back(NULL); 89 test_array[OUTPUT].push_back(NULL); 90 test_array[REF_OUTPUT].push_back(NULL); 91 test_array[REF_OUTPUT].push_back(NULL); 92 allow_16u = _allow_16u; 93 allow_32f = _allow_32f; 94 custom_inv_transform = _custom_inv_transform; 95 fwd_code = inv_code = -1; 96 element_wise_relative_error = false; 97 98 fwd_code_str = inv_code_str = 0; 99 100 test_cpp = false; 101 hue_range = 0; 102 blue_idx = 0; 103 inplace = false; 104 } 105 106 107 void CV_ColorCvtBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high ) 108 { 109 cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high ); 110 if( i == INPUT ) 111 { 112 int depth = CV_MAT_DEPTH(type); 113 low = Scalar::all(0.); 114 high = Scalar::all( depth == CV_8U ? 256 : depth == CV_16U ? 65536 : 1. ); 115 } 116 } 117 118 119 void CV_ColorCvtBaseTest::get_test_array_types_and_sizes( int test_case_idx, 120 vector<vector<Size> >& sizes, vector<vector<int> >& types ) 121 { 122 RNG& rng = ts->get_rng(); 123 int depth, cn; 124 cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 125 126 if( allow_16u && allow_32f ) 127 { 128 depth = cvtest::randInt(rng) % 3; 129 depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F; 130 } 131 else if( allow_16u || allow_32f ) 132 { 133 depth = cvtest::randInt(rng) % 2; 134 depth = depth == 0 ? CV_8U : allow_16u ? CV_16U : CV_32F; 135 } 136 else 137 depth = CV_8U; 138 139 cn = (cvtest::randInt(rng) & 1) + 3; 140 blue_idx = cvtest::randInt(rng) & 1 ? 2 : 0; 141 142 types[INPUT][0] = CV_MAKETYPE(depth, cn); 143 types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, 3); 144 if( test_array[OUTPUT].size() > 1 ) 145 types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(depth, cn); 146 147 inplace = cn == 3 && cvtest::randInt(rng) % 2 != 0; 148 test_cpp = (cvtest::randInt(rng) & 256) == 0; 149 } 150 151 152 int CV_ColorCvtBaseTest::prepare_test_case( int test_case_idx ) 153 { 154 int code = cvtest::ArrayTest::prepare_test_case( test_case_idx ); 155 if( code > 0 && inplace ) 156 cvtest::copy( test_mat[INPUT][0], test_mat[OUTPUT][0] ); 157 return code; 158 } 159 160 void CV_ColorCvtBaseTest::run_func() 161 { 162 CvArr* out0 = test_array[OUTPUT][0]; 163 cv::Mat _out0 = cv::cvarrToMat(out0), _out1 = cv::cvarrToMat(test_array[OUTPUT][1]); 164 165 if(!test_cpp) 166 cvCvtColor( inplace ? out0 : test_array[INPUT][0], out0, fwd_code ); 167 else 168 cv::cvtColor( cv::cvarrToMat(inplace ? out0 : test_array[INPUT][0]), _out0, fwd_code, _out0.channels()); 169 170 if( inplace ) 171 { 172 cvCopy( out0, test_array[OUTPUT][1] ); 173 out0 = test_array[OUTPUT][1]; 174 } 175 if(!test_cpp) 176 cvCvtColor( out0, test_array[OUTPUT][1], inv_code ); 177 else 178 cv::cvtColor(cv::cvarrToMat(out0), _out1, inv_code, _out1.channels()); 179 } 180 181 182 void CV_ColorCvtBaseTest::prepare_to_validation( int /*test_case_idx*/ ) 183 { 184 convert_forward( test_mat[INPUT][0], test_mat[REF_OUTPUT][0] ); 185 convert_backward( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], 186 test_mat[REF_OUTPUT][1] ); 187 int depth = test_mat[REF_OUTPUT][0].depth(); 188 if( depth == CV_8U && hue_range ) 189 { 190 for( int y = 0; y < test_mat[REF_OUTPUT][0].rows; y++ ) 191 { 192 uchar* h0 = test_mat[REF_OUTPUT][0].ptr(y); 193 uchar* h = test_mat[OUTPUT][0].ptr(y); 194 195 for( int x = 0; x < test_mat[REF_OUTPUT][0].cols; x++, h0 += 3, h += 3 ) 196 { 197 if( abs(*h - *h0) >= hue_range-1 && (*h <= 1 || *h0 <= 1) ) 198 *h = *h0 = 0; 199 } 200 } 201 } 202 } 203 204 205 void CV_ColorCvtBaseTest::convert_forward( const Mat& src, Mat& dst ) 206 { 207 const float c8u = 0.0039215686274509803f; // 1./255 208 const float c16u = 1.5259021896696422e-005f; // 1./65535 209 int depth = src.depth(); 210 int cn = src.channels(), dst_cn = dst.channels(); 211 int cols = src.cols, dst_cols_n = dst.cols*dst_cn; 212 vector<float> _src_buf(src.cols*3); 213 vector<float> _dst_buf(dst.cols*3); 214 float* src_buf = &_src_buf[0]; 215 float* dst_buf = &_dst_buf[0]; 216 int i, j; 217 218 assert( (cn == 3 || cn == 4) && (dst_cn == 3 || dst_cn == 1) ); 219 220 for( i = 0; i < src.rows; i++ ) 221 { 222 switch( depth ) 223 { 224 case CV_8U: 225 { 226 const uchar* src_row = src.ptr(i); 227 uchar* dst_row = dst.ptr(i); 228 229 for( j = 0; j < cols; j++ ) 230 { 231 src_buf[j*3] = src_row[j*cn + blue_idx]*c8u; 232 src_buf[j*3+1] = src_row[j*cn + 1]*c8u; 233 src_buf[j*3+2] = src_row[j*cn + (blue_idx^2)]*c8u; 234 } 235 236 convert_row_bgr2abc_32f_c3( src_buf, dst_buf, cols ); 237 238 for( j = 0; j < dst_cols_n; j++ ) 239 { 240 int t = cvRound( dst_buf[j] ); 241 dst_row[j] = saturate_cast<uchar>(t); 242 } 243 } 244 break; 245 case CV_16U: 246 { 247 const ushort* src_row = src.ptr<ushort>(i); 248 ushort* dst_row = dst.ptr<ushort>(i); 249 250 for( j = 0; j < cols; j++ ) 251 { 252 src_buf[j*3] = src_row[j*cn + blue_idx]*c16u; 253 src_buf[j*3+1] = src_row[j*cn + 1]*c16u; 254 src_buf[j*3+2] = src_row[j*cn + (blue_idx^2)]*c16u; 255 } 256 257 convert_row_bgr2abc_32f_c3( src_buf, dst_buf, cols ); 258 259 for( j = 0; j < dst_cols_n; j++ ) 260 { 261 int t = cvRound( dst_buf[j] ); 262 dst_row[j] = saturate_cast<ushort>(t); 263 } 264 } 265 break; 266 case CV_32F: 267 { 268 const float* src_row = src.ptr<float>(i); 269 float* dst_row = dst.ptr<float>(i); 270 271 for( j = 0; j < cols; j++ ) 272 { 273 src_buf[j*3] = src_row[j*cn + blue_idx]; 274 src_buf[j*3+1] = src_row[j*cn + 1]; 275 src_buf[j*3+2] = src_row[j*cn + (blue_idx^2)]; 276 } 277 278 convert_row_bgr2abc_32f_c3( src_buf, dst_row, cols ); 279 } 280 break; 281 default: 282 assert(0); 283 } 284 } 285 } 286 287 288 void CV_ColorCvtBaseTest::convert_row_bgr2abc_32f_c3( const float* /*src_row*/, 289 float* /*dst_row*/, int /*n*/ ) 290 { 291 } 292 293 294 void CV_ColorCvtBaseTest::convert_row_abc2bgr_32f_c3( const float* /*src_row*/, 295 float* /*dst_row*/, int /*n*/ ) 296 { 297 } 298 299 300 void CV_ColorCvtBaseTest::convert_backward( const Mat& src, const Mat& dst, Mat& dst2 ) 301 { 302 if( custom_inv_transform ) 303 { 304 int depth = src.depth(); 305 int src_cn = dst.channels(), cn = dst2.channels(); 306 int cols_n = src.cols*src_cn, dst_cols = dst.cols; 307 vector<float> _src_buf(src.cols*3); 308 vector<float> _dst_buf(dst.cols*3); 309 float* src_buf = &_src_buf[0]; 310 float* dst_buf = &_dst_buf[0]; 311 int i, j; 312 313 assert( cn == 3 || cn == 4 ); 314 315 for( i = 0; i < src.rows; i++ ) 316 { 317 switch( depth ) 318 { 319 case CV_8U: 320 { 321 const uchar* src_row = dst.ptr(i); 322 uchar* dst_row = dst2.ptr(i); 323 324 for( j = 0; j < cols_n; j++ ) 325 src_buf[j] = src_row[j]; 326 327 convert_row_abc2bgr_32f_c3( src_buf, dst_buf, dst_cols ); 328 329 for( j = 0; j < dst_cols; j++ ) 330 { 331 int b = cvRound( dst_buf[j*3]*255. ); 332 int g = cvRound( dst_buf[j*3+1]*255. ); 333 int r = cvRound( dst_buf[j*3+2]*255. ); 334 dst_row[j*cn + blue_idx] = saturate_cast<uchar>(b); 335 dst_row[j*cn + 1] = saturate_cast<uchar>(g); 336 dst_row[j*cn + (blue_idx^2)] = saturate_cast<uchar>(r); 337 if( cn == 4 ) 338 dst_row[j*cn + 3] = 255; 339 } 340 } 341 break; 342 case CV_16U: 343 { 344 const ushort* src_row = dst.ptr<ushort>(i); 345 ushort* dst_row = dst2.ptr<ushort>(i); 346 347 for( j = 0; j < cols_n; j++ ) 348 src_buf[j] = src_row[j]; 349 350 convert_row_abc2bgr_32f_c3( src_buf, dst_buf, dst_cols ); 351 352 for( j = 0; j < dst_cols; j++ ) 353 { 354 int b = cvRound( dst_buf[j*3]*65535. ); 355 int g = cvRound( dst_buf[j*3+1]*65535. ); 356 int r = cvRound( dst_buf[j*3+2]*65535. ); 357 dst_row[j*cn + blue_idx] = saturate_cast<ushort>(b); 358 dst_row[j*cn + 1] = saturate_cast<ushort>(g); 359 dst_row[j*cn + (blue_idx^2)] = saturate_cast<ushort>(r); 360 if( cn == 4 ) 361 dst_row[j*cn + 3] = 65535; 362 } 363 } 364 break; 365 case CV_32F: 366 { 367 const float* src_row = dst.ptr<float>(i); 368 float* dst_row = dst2.ptr<float>(i); 369 370 convert_row_abc2bgr_32f_c3( src_row, dst_buf, dst_cols ); 371 372 for( j = 0; j < dst_cols; j++ ) 373 { 374 float b = dst_buf[j*3]; 375 float g = dst_buf[j*3+1]; 376 float r = dst_buf[j*3+2]; 377 dst_row[j*cn + blue_idx] = b; 378 dst_row[j*cn + 1] = g; 379 dst_row[j*cn + (blue_idx^2)] = r; 380 if( cn == 4 ) 381 dst_row[j*cn + 3] = 1.f; 382 } 383 } 384 break; 385 default: 386 assert(0); 387 } 388 } 389 } 390 else 391 { 392 int i, j, k; 393 int elem_size = (int)src.elemSize(), elem_size1 = (int)src.elemSize1(); 394 int width_n = src.cols*elem_size; 395 396 for( i = 0; i < src.rows; i++ ) 397 { 398 memcpy( dst2.ptr(i), src.ptr(i), width_n ); 399 if( src.channels() == 4 ) 400 { 401 // clear the alpha channel 402 uchar* ptr = dst2.ptr(i) + elem_size1*3; 403 for( j = 0; j < width_n; j += elem_size ) 404 { 405 for( k = 0; k < elem_size1; k++ ) 406 ptr[j + k] = 0; 407 } 408 } 409 } 410 } 411 } 412 413 414 #undef INIT_FWD_INV_CODES 415 #define INIT_FWD_INV_CODES( fwd, inv ) \ 416 fwd_code = CV_##fwd; inv_code = CV_##inv; \ 417 fwd_code_str = #fwd; inv_code_str = #inv 418 419 //// rgb <=> gray 420 class CV_ColorGrayTest : public CV_ColorCvtBaseTest 421 { 422 public: 423 CV_ColorGrayTest(); 424 protected: 425 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 426 void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); 427 void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); 428 double get_success_error_level( int test_case_idx, int i, int j ); 429 }; 430 431 432 CV_ColorGrayTest::CV_ColorGrayTest() : CV_ColorCvtBaseTest( true, true, true ) 433 { 434 INIT_FWD_INV_CODES( BGR2GRAY, GRAY2BGR ); 435 } 436 437 438 void CV_ColorGrayTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ) 439 { 440 CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 441 int cn = CV_MAT_CN(types[INPUT][0]); 442 types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0] & CV_MAT_DEPTH_MASK; 443 inplace = false; 444 445 if( cn == 3 ) 446 { 447 if( blue_idx == 0 ) 448 fwd_code = CV_BGR2GRAY, inv_code = CV_GRAY2BGR; 449 else 450 fwd_code = CV_RGB2GRAY, inv_code = CV_GRAY2RGB; 451 } 452 else 453 { 454 if( blue_idx == 0 ) 455 fwd_code = CV_BGRA2GRAY, inv_code = CV_GRAY2BGRA; 456 else 457 fwd_code = CV_RGBA2GRAY, inv_code = CV_GRAY2RGBA; 458 } 459 } 460 461 462 double CV_ColorGrayTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) 463 { 464 int depth = test_mat[i][j].depth(); 465 return depth == CV_8U ? 2 : depth == CV_16U ? 16 : 1e-5; 466 } 467 468 469 void CV_ColorGrayTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) 470 { 471 int depth = test_mat[INPUT][0].depth(); 472 double scale = depth == CV_8U ? 255 : depth == CV_16U ? 65535 : 1; 473 double cr = 0.299*scale; 474 double cg = 0.587*scale; 475 double cb = 0.114*scale; 476 int j; 477 478 for( j = 0; j < n; j++ ) 479 dst_row[j] = (float)(src_row[j*3]*cb + src_row[j*3+1]*cg + src_row[j*3+2]*cr); 480 } 481 482 483 void CV_ColorGrayTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) 484 { 485 int j, depth = test_mat[INPUT][0].depth(); 486 float scale = depth == CV_8U ? (1.f/255) : depth == CV_16U ? 1.f/65535 : 1.f; 487 for( j = 0; j < n; j++ ) 488 dst_row[j*3] = dst_row[j*3+1] = dst_row[j*3+2] = src_row[j]*scale; 489 } 490 491 492 //// rgb <=> ycrcb 493 class CV_ColorYCrCbTest : public CV_ColorCvtBaseTest 494 { 495 public: 496 CV_ColorYCrCbTest(); 497 protected: 498 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 499 double get_success_error_level( int test_case_idx, int i, int j ); 500 void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); 501 void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); 502 }; 503 504 505 CV_ColorYCrCbTest::CV_ColorYCrCbTest() : CV_ColorCvtBaseTest( true, true, true ) 506 { 507 INIT_FWD_INV_CODES( BGR2YCrCb, YCrCb2BGR ); 508 } 509 510 511 void CV_ColorYCrCbTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ) 512 { 513 CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 514 515 if( blue_idx == 0 ) 516 fwd_code = CV_BGR2YCrCb, inv_code = CV_YCrCb2BGR; 517 else 518 fwd_code = CV_RGB2YCrCb, inv_code = CV_YCrCb2RGB; 519 } 520 521 522 double CV_ColorYCrCbTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) 523 { 524 int depth = test_mat[i][j].depth(); 525 return depth == CV_8U ? 2 : depth == CV_16U ? 32 : 1e-3; 526 } 527 528 529 void CV_ColorYCrCbTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) 530 { 531 int depth = test_mat[INPUT][0].depth(); 532 double scale = depth == CV_8U ? 255 : depth == CV_16U ? 65535 : 1; 533 double bias = depth == CV_8U ? 128 : depth == CV_16U ? 32768 : 0.5; 534 535 double M[] = { 0.299, 0.587, 0.114, 536 0.49981, -0.41853, -0.08128, 537 -0.16864, -0.33107, 0.49970 }; 538 int j; 539 for( j = 0; j < 9; j++ ) 540 M[j] *= scale; 541 542 for( j = 0; j < n*3; j += 3 ) 543 { 544 double r = src_row[j+2]; 545 double g = src_row[j+1]; 546 double b = src_row[j]; 547 double y = M[0]*r + M[1]*g + M[2]*b; 548 double cr = M[3]*r + M[4]*g + M[5]*b + bias; 549 double cb = M[6]*r + M[7]*g + M[8]*b + bias; 550 dst_row[j] = (float)y; 551 dst_row[j+1] = (float)cr; 552 dst_row[j+2] = (float)cb; 553 } 554 } 555 556 557 void CV_ColorYCrCbTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) 558 { 559 int depth = test_mat[INPUT][0].depth(); 560 double bias = depth == CV_8U ? 128 : depth == CV_16U ? 32768 : 0.5; 561 double scale = depth == CV_8U ? 1./255 : depth == CV_16U ? 1./65535 : 1; 562 double M[] = { 1, 1.40252, 0, 563 1, -0.71440, -0.34434, 564 1, 0, 1.77305 }; 565 int j; 566 for( j = 0; j < 9; j++ ) 567 M[j] *= scale; 568 569 for( j = 0; j < n*3; j += 3 ) 570 { 571 double y = src_row[j]; 572 double cr = src_row[j+1] - bias; 573 double cb = src_row[j+2] - bias; 574 double r = M[0]*y + M[1]*cr + M[2]*cb; 575 double g = M[3]*y + M[4]*cr + M[5]*cb; 576 double b = M[6]*y + M[7]*cr + M[8]*cb; 577 dst_row[j] = (float)b; 578 dst_row[j+1] = (float)g; 579 dst_row[j+2] = (float)r; 580 } 581 } 582 583 584 //// rgb <=> hsv 585 class CV_ColorHSVTest : public CV_ColorCvtBaseTest 586 { 587 public: 588 CV_ColorHSVTest(); 589 protected: 590 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 591 double get_success_error_level( int test_case_idx, int i, int j ); 592 void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); 593 void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); 594 }; 595 596 597 CV_ColorHSVTest::CV_ColorHSVTest() : CV_ColorCvtBaseTest( true, true, false ) 598 { 599 INIT_FWD_INV_CODES( BGR2HSV, HSV2BGR ); 600 hue_range = 180; 601 } 602 603 604 void CV_ColorHSVTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ) 605 { 606 CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 607 RNG& rng = ts->get_rng(); 608 609 bool full_hrange = (rng.next() & 256) != 0; 610 if( full_hrange ) 611 { 612 if( blue_idx == 0 ) 613 fwd_code = CV_BGR2HSV_FULL, inv_code = CV_HSV2BGR_FULL; 614 else 615 fwd_code = CV_RGB2HSV_FULL, inv_code = CV_HSV2RGB_FULL; 616 hue_range = 256; 617 } 618 else 619 { 620 if( blue_idx == 0 ) 621 fwd_code = CV_BGR2HSV, inv_code = CV_HSV2BGR; 622 else 623 fwd_code = CV_RGB2HSV, inv_code = CV_HSV2RGB; 624 hue_range = 180; 625 } 626 } 627 628 629 double CV_ColorHSVTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) 630 { 631 int depth = test_mat[i][j].depth(); 632 return depth == CV_8U ? (j == 0 ? 4 : 16) : depth == CV_16U ? 32 : 1e-3; 633 } 634 635 636 void CV_ColorHSVTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) 637 { 638 int depth = test_mat[INPUT][0].depth(); 639 float h_scale = depth == CV_8U ? hue_range*30.f/180 : 60.f; 640 float scale = depth == CV_8U ? 255.f : depth == CV_16U ? 65535.f : 1.f; 641 int j; 642 643 for( j = 0; j < n*3; j += 3 ) 644 { 645 float r = src_row[j+2]; 646 float g = src_row[j+1]; 647 float b = src_row[j]; 648 float vmin = MIN(r,g); 649 float v = MAX(r,g); 650 float s, h, diff; 651 vmin = MIN(vmin,b); 652 v = MAX(v,b); 653 diff = v - vmin; 654 if( diff == 0 ) 655 s = h = 0; 656 else 657 { 658 s = diff/(v + FLT_EPSILON); 659 diff = 1.f/diff; 660 661 h = r == v ? (g - b)*diff : 662 g == v ? 2 + (b - r)*diff : 4 + (r - g)*diff; 663 664 if( h < 0 ) 665 h += 6; 666 } 667 668 dst_row[j] = h*h_scale; 669 dst_row[j+1] = s*scale; 670 dst_row[j+2] = v*scale; 671 } 672 } 673 674 // taken from http://www.cs.rit.edu/~ncs/color/t_convert.html 675 void CV_ColorHSVTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) 676 { 677 int depth = test_mat[INPUT][0].depth(); 678 float h_scale = depth == CV_8U ? 180/(hue_range*30.f) : 1.f/60; 679 float scale = depth == CV_8U ? 1.f/255 : depth == CV_16U ? 1.f/65535 : 1; 680 int j; 681 682 for( j = 0; j < n*3; j += 3 ) 683 { 684 float h = src_row[j]*h_scale; 685 float s = src_row[j+1]*scale; 686 float v = src_row[j+2]*scale; 687 float r = v, g = v, b = v; 688 689 if( h < 0 ) 690 h += 6; 691 else if( h >= 6 ) 692 h -= 6; 693 694 if( s != 0 ) 695 { 696 int i = cvFloor(h); 697 float f = h - i; 698 float p = v*(1 - s); 699 float q = v*(1 - s*f); 700 float t = v*(1 - s*(1 - f)); 701 702 if( i == 0 ) 703 r = v, g = t, b = p; 704 else if( i == 1 ) 705 r = q, g = v, b = p; 706 else if( i == 2 ) 707 r = p, g = v, b = t; 708 else if( i == 3 ) 709 r = p, g = q, b = v; 710 else if( i == 4 ) 711 r = t, g = p, b = v; 712 else 713 r = v, g = p, b = q; 714 } 715 716 dst_row[j] = b; 717 dst_row[j+1] = g; 718 dst_row[j+2] = r; 719 } 720 } 721 722 723 //// rgb <=> hls 724 class CV_ColorHLSTest : public CV_ColorCvtBaseTest 725 { 726 public: 727 CV_ColorHLSTest(); 728 protected: 729 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 730 double get_success_error_level( int test_case_idx, int i, int j ); 731 void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); 732 void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); 733 }; 734 735 736 CV_ColorHLSTest::CV_ColorHLSTest() : CV_ColorCvtBaseTest( true, true, false ) 737 { 738 INIT_FWD_INV_CODES( BGR2HLS, HLS2BGR ); 739 hue_range = 180; 740 } 741 742 743 void CV_ColorHLSTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ) 744 { 745 CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 746 747 if( blue_idx == 0 ) 748 fwd_code = CV_BGR2HLS, inv_code = CV_HLS2BGR; 749 else 750 fwd_code = CV_RGB2HLS, inv_code = CV_HLS2RGB; 751 } 752 753 754 double CV_ColorHLSTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) 755 { 756 int depth = test_mat[i][j].depth(); 757 return depth == CV_8U ? (j == 0 ? 4 : 16) : depth == CV_16U ? 32 : 1e-4; 758 } 759 760 761 void CV_ColorHLSTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) 762 { 763 int depth = test_mat[INPUT][0].depth(); 764 float h_scale = depth == CV_8U ? 30.f : 60.f; 765 float scale = depth == CV_8U ? 255.f : depth == CV_16U ? 65535.f : 1.f; 766 int j; 767 768 for( j = 0; j < n*3; j += 3 ) 769 { 770 float r = src_row[j+2]; 771 float g = src_row[j+1]; 772 float b = src_row[j]; 773 float vmin = MIN(r,g); 774 float v = MAX(r,g); 775 float s, h, l, diff; 776 vmin = MIN(vmin,b); 777 v = MAX(v,b); 778 diff = v - vmin; 779 780 if( diff == 0 ) 781 s = h = 0, l = v; 782 else 783 { 784 l = (v + vmin)*0.5f; 785 s = l <= 0.5f ? diff / (v + vmin) : diff / (2 - v - vmin); 786 diff = 1.f/diff; 787 788 h = r == v ? (g - b)*diff : 789 g == v ? 2 + (b - r)*diff : 4 + (r - g)*diff; 790 791 if( h < 0 ) 792 h += 6; 793 } 794 795 dst_row[j] = h*h_scale; 796 dst_row[j+1] = l*scale; 797 dst_row[j+2] = s*scale; 798 } 799 } 800 801 802 void CV_ColorHLSTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) 803 { 804 int depth = test_mat[INPUT][0].depth(); 805 float h_scale = depth == CV_8U ? 1.f/30 : 1.f/60; 806 float scale = depth == CV_8U ? 1.f/255 : depth == CV_16U ? 1.f/65535 : 1; 807 int j; 808 809 for( j = 0; j < n*3; j += 3 ) 810 { 811 float h = src_row[j]*h_scale; 812 float l = src_row[j+1]*scale; 813 float s = src_row[j+2]*scale; 814 float r = l, g = l, b = l; 815 816 if( h < 0 ) 817 h += 6; 818 else if( h >= 6 ) 819 h -= 6; 820 821 if( s != 0 ) 822 { 823 float m2 = l <= 0.5f ? l*(1.f + s) : l + s - l*s; 824 float m1 = 2*l - m2; 825 float h1 = h + 2; 826 827 if( h1 >= 6 ) 828 h1 -= 6; 829 if( h1 < 1 ) 830 r = m1 + (m2 - m1)*h1; 831 else if( h1 < 3 ) 832 r = m2; 833 else if( h1 < 4 ) 834 r = m1 + (m2 - m1)*(4 - h1); 835 else 836 r = m1; 837 838 h1 = h; 839 840 if( h1 < 1 ) 841 g = m1 + (m2 - m1)*h1; 842 else if( h1 < 3 ) 843 g = m2; 844 else if( h1 < 4 ) 845 g = m1 + (m2 - m1)*(4 - h1); 846 else 847 g = m1; 848 849 h1 = h - 2; 850 if( h1 < 0 ) 851 h1 += 6; 852 853 if( h1 < 1 ) 854 b = m1 + (m2 - m1)*h1; 855 else if( h1 < 3 ) 856 b = m2; 857 else if( h1 < 4 ) 858 b = m1 + (m2 - m1)*(4 - h1); 859 else 860 b = m1; 861 } 862 863 dst_row[j] = b; 864 dst_row[j+1] = g; 865 dst_row[j+2] = r; 866 } 867 } 868 869 870 static const double RGB2XYZ[] = 871 { 872 0.412453, 0.357580, 0.180423, 873 0.212671, 0.715160, 0.072169, 874 0.019334, 0.119193, 0.950227 875 }; 876 877 878 static const double XYZ2RGB[] = 879 { 880 3.240479, -1.53715, -0.498535, 881 -0.969256, 1.875991, 0.041556, 882 0.055648, -0.204043, 1.057311 883 }; 884 885 static const float Xn = 0.950456f; 886 static const float Zn = 1.088754f; 887 888 889 //// rgb <=> xyz 890 class CV_ColorXYZTest : public CV_ColorCvtBaseTest 891 { 892 public: 893 CV_ColorXYZTest(); 894 protected: 895 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 896 double get_success_error_level( int test_case_idx, int i, int j ); 897 void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); 898 void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); 899 }; 900 901 902 CV_ColorXYZTest::CV_ColorXYZTest() : CV_ColorCvtBaseTest( true, true, true ) 903 { 904 INIT_FWD_INV_CODES( BGR2XYZ, XYZ2BGR ); 905 } 906 907 908 void CV_ColorXYZTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ) 909 { 910 CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 911 912 if( blue_idx == 0 ) 913 fwd_code = CV_BGR2XYZ, inv_code = CV_XYZ2BGR; 914 else 915 fwd_code = CV_RGB2XYZ, inv_code = CV_XYZ2RGB; 916 } 917 918 919 double CV_ColorXYZTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) 920 { 921 int depth = test_mat[i][j].depth(); 922 return depth == CV_8U ? (j == 0 ? 2 : 8) : depth == CV_16U ? (j == 0 ? 64 : 128) : 1e-1; 923 } 924 925 926 void CV_ColorXYZTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) 927 { 928 int depth = test_mat[INPUT][0].depth(); 929 double scale = depth == CV_8U ? 255 : depth == CV_16U ? 65535 : 1; 930 931 double M[9]; 932 int j; 933 for( j = 0; j < 9; j++ ) 934 M[j] = RGB2XYZ[j]*scale; 935 936 for( j = 0; j < n*3; j += 3 ) 937 { 938 double r = src_row[j+2]; 939 double g = src_row[j+1]; 940 double b = src_row[j]; 941 double x = M[0]*r + M[1]*g + M[2]*b; 942 double y = M[3]*r + M[4]*g + M[5]*b; 943 double z = M[6]*r + M[7]*g + M[8]*b; 944 dst_row[j] = (float)x; 945 dst_row[j+1] = (float)y; 946 dst_row[j+2] = (float)z; 947 } 948 } 949 950 951 void CV_ColorXYZTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) 952 { 953 int depth = test_mat[INPUT][0].depth(); 954 double scale = depth == CV_8U ? 1./255 : depth == CV_16U ? 1./65535 : 1; 955 956 double M[9]; 957 int j; 958 for( j = 0; j < 9; j++ ) 959 M[j] = XYZ2RGB[j]*scale; 960 961 for( j = 0; j < n*3; j += 3 ) 962 { 963 double x = src_row[j]; 964 double y = src_row[j+1]; 965 double z = src_row[j+2]; 966 double r = M[0]*x + M[1]*y + M[2]*z; 967 double g = M[3]*x + M[4]*y + M[5]*z; 968 double b = M[6]*x + M[7]*y + M[8]*z; 969 dst_row[j] = (float)b; 970 dst_row[j+1] = (float)g; 971 dst_row[j+2] = (float)r; 972 } 973 } 974 975 976 //// rgb <=> L*a*b* 977 class CV_ColorLabTest : public CV_ColorCvtBaseTest 978 { 979 public: 980 CV_ColorLabTest(); 981 protected: 982 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 983 double get_success_error_level( int test_case_idx, int i, int j ); 984 void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); 985 void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); 986 }; 987 988 989 CV_ColorLabTest::CV_ColorLabTest() : CV_ColorCvtBaseTest( true, true, false ) 990 { 991 INIT_FWD_INV_CODES( BGR2Lab, Lab2BGR ); 992 } 993 994 995 void CV_ColorLabTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ) 996 { 997 CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 998 999 if( blue_idx == 0 ) 1000 fwd_code = CV_LBGR2Lab, inv_code = CV_Lab2LBGR; 1001 else 1002 fwd_code = CV_LRGB2Lab, inv_code = CV_Lab2LRGB; 1003 } 1004 1005 1006 double CV_ColorLabTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) 1007 { 1008 int depth = test_mat[i][j].depth(); 1009 return depth == CV_8U ? 16 : depth == CV_16U ? 32 : 1e-3; 1010 } 1011 1012 1013 static const double _1_3 = 0.333333333333; 1014 const static float _1_3f = static_cast<float>(_1_3); 1015 1016 1017 void CV_ColorLabTest::convert_row_bgr2abc_32f_c3(const float* src_row, float* dst_row, int n) 1018 { 1019 int depth = test_mat[INPUT][0].depth(); 1020 float Lscale = depth == CV_8U ? 255.f/100.f : depth == CV_16U ? 65535.f/100.f : 1.f; 1021 float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f; 1022 float M[9]; 1023 1024 for (int j = 0; j < 9; j++ ) 1025 M[j] = (float)RGB2XYZ[j]; 1026 1027 for (int x = 0; x < n*3; x += 3) 1028 { 1029 float R = src_row[x + 2]; 1030 float G = src_row[x + 1]; 1031 float B = src_row[x]; 1032 1033 float X = (R * M[0] + G * M[1] + B * M[2]) / Xn; 1034 float Y = R * M[3] + G * M[4] + B * M[5]; 1035 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); 1040 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 } 1052 1053 float a = 500.f * (fX - fY); 1054 float b = 200.f * (fY - fZ); 1055 1056 dst_row[x] = L * Lscale; 1057 dst_row[x + 1] = a + ab_bias; 1058 dst_row[x + 2] = b + ab_bias; 1059 } 1060 } 1061 1062 void CV_ColorLabTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) 1063 { 1064 int depth = test_mat[INPUT][0].depth(); 1065 float Lscale = depth == CV_8U ? 100.f/255.f : depth == CV_16U ? 100.f/65535.f : 1.f; 1066 float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f; 1067 float M[9]; 1068 1069 for(int j = 0; j < 9; j++ ) 1070 M[j] = (float)XYZ2RGB[j]; 1071 1072 static const float lthresh = 903.3f * 0.008856f; 1073 static const float thresh = 7.787f * 0.008856f + 16.0f / 116.0f; 1074 for (int x = 0, end = n * 3; x < end; x += 3) 1075 { 1076 float L = src_row[x] * Lscale; 1077 float a = src_row[x + 1] - ab_bias; 1078 float b = src_row[x + 2] - ab_bias; 1079 1080 float FY = 0.0f, Y = 0.0f; 1081 if (L <= lthresh) 1082 { 1083 Y = L / 903.3f; 1084 FY = 7.787f * Y + 16.0f / 116.0f; 1085 } 1086 else 1087 { 1088 FY = (L + 16.0f) / 116.0f; 1089 Y = FY * FY * FY; 1090 } 1091 1092 float FX = a / 500.0f + FY; 1093 float FZ = FY - b / 200.0f; 1094 1095 float FXZ[] = { FX, FZ }; 1096 for (int k = 0; k < 2; ++k) 1097 { 1098 if (FXZ[k] <= thresh) 1099 FXZ[k] = (FXZ[k] - 16.0f / 116.0f) / 7.787f; 1100 else 1101 FXZ[k] = FXZ[k] * FXZ[k] * FXZ[k]; 1102 } 1103 float X = FXZ[0] * Xn; 1104 float Z = FXZ[1] * Zn; 1105 1106 float R = M[0] * X + M[1] * Y + M[2] * Z; 1107 float G = M[3] * X + M[4] * Y + M[5] * Z; 1108 float B = M[6] * X + M[7] * Y + M[8] * Z; 1109 1110 dst_row[x] = B; 1111 dst_row[x + 1] = G; 1112 dst_row[x + 2] = R; 1113 } 1114 } 1115 1116 1117 //// rgb <=> L*u*v* 1118 class CV_ColorLuvTest : public CV_ColorCvtBaseTest 1119 { 1120 public: 1121 CV_ColorLuvTest(); 1122 protected: 1123 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 1124 double get_success_error_level( int test_case_idx, int i, int j ); 1125 void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ); 1126 void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ); 1127 }; 1128 1129 1130 CV_ColorLuvTest::CV_ColorLuvTest() : CV_ColorCvtBaseTest( true, true, false ) 1131 { 1132 INIT_FWD_INV_CODES( BGR2Luv, Luv2BGR ); 1133 } 1134 1135 1136 void CV_ColorLuvTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ) 1137 { 1138 CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 1139 1140 if( blue_idx == 0 ) 1141 fwd_code = CV_LBGR2Luv, inv_code = CV_Luv2LBGR; 1142 else 1143 fwd_code = CV_LRGB2Luv, inv_code = CV_Luv2LRGB; 1144 } 1145 1146 1147 double CV_ColorLuvTest::get_success_error_level( int /*test_case_idx*/, int i, int j ) 1148 { 1149 int depth = test_mat[i][j].depth(); 1150 return depth == CV_8U ? 48 : depth == CV_16U ? 32 : 5e-2; 1151 } 1152 1153 1154 void CV_ColorLuvTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n ) 1155 { 1156 int depth = test_mat[INPUT][0].depth(); 1157 float Lscale = depth == CV_8U ? 255.f/100.f : depth == CV_16U ? 65535.f/100.f : 1.f; 1158 int j; 1159 1160 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); 1163 float u_scale = 1.f, u_bias = 0.f; 1164 float v_scale = 1.f, v_bias = 0.f; 1165 1166 for( j = 0; j < 9; j++ ) 1167 M[j] = (float)RGB2XYZ[j]; 1168 1169 if( depth == CV_8U ) 1170 { 1171 u_scale = 0.720338983f; 1172 u_bias = 96.5254237f; 1173 v_scale = 0.973282442f; 1174 v_bias = 136.2595419f; 1175 } 1176 1177 for( j = 0; j < n*3; j += 3 ) 1178 { 1179 float r = src_row[j+2]; 1180 float g = src_row[j+1]; 1181 float b = src_row[j]; 1182 1183 float X = r*M[0] + g*M[1] + b*M[2]; 1184 float Y = r*M[3] + g*M[4] + b*M[5]; 1185 float Z = r*M[6] + g*M[7] + b*M[8]; 1186 float d = X + 15*Y + 3*Z, L, u, v; 1187 1188 if( d == 0 ) 1189 L = u = v = 0; 1190 else 1191 { 1192 if( Y > 0.008856f ) 1193 L = (float)(116.*pow((double)Y,_1_3) - 16.); 1194 else 1195 L = 903.3f * Y; 1196 1197 d = 1.f/d; 1198 u = 13*L*(4*X*d - un); 1199 v = 13*L*(9*Y*d - vn); 1200 } 1201 dst_row[j] = L*Lscale; 1202 dst_row[j+1] = u*u_scale + u_bias; 1203 dst_row[j+2] = v*v_scale + v_bias; 1204 } 1205 } 1206 1207 1208 void CV_ColorLuvTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n ) 1209 { 1210 int depth = test_mat[INPUT][0].depth(); 1211 float Lscale = depth == CV_8U ? 100.f/255.f : depth == CV_16U ? 100.f/65535.f : 1.f; 1212 int j; 1213 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); 1216 float u_scale = 1.f, u_bias = 0.f; 1217 float v_scale = 1.f, v_bias = 0.f; 1218 1219 for( j = 0; j < 9; j++ ) 1220 M[j] = (float)XYZ2RGB[j]; 1221 1222 if( depth == CV_8U ) 1223 { 1224 u_scale = 1.f/0.720338983f; 1225 u_bias = 96.5254237f; 1226 v_scale = 1.f/0.973282442f; 1227 v_bias = 136.2595419f; 1228 } 1229 1230 for( j = 0; j < n*3; j += 3 ) 1231 { 1232 float L = src_row[j]*Lscale; 1233 float u = (src_row[j+1] - u_bias)*u_scale; 1234 float v = (src_row[j+2] - v_bias)*v_scale; 1235 float X, Y, Z; 1236 1237 if( L >= 8 ) 1238 { 1239 Y = (L + 16.f)*(1.f/116.f); 1240 Y = Y*Y*Y; 1241 } 1242 else 1243 { 1244 Y = L * (1.f/903.3f); 1245 if( L == 0 ) 1246 L = 0.001f; 1247 } 1248 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); 1254 1255 float r = M[0]*X + M[1]*Y + M[2]*Z; 1256 float g = M[3]*X + M[4]*Y + M[5]*Z; 1257 float b = M[6]*X + M[7]*Y + M[8]*Z; 1258 1259 dst_row[j] = b; 1260 dst_row[j+1] = g; 1261 dst_row[j+2] = r; 1262 } 1263 } 1264 1265 1266 //// rgb <=> another rgb 1267 class CV_ColorRGBTest : public CV_ColorCvtBaseTest 1268 { 1269 public: 1270 CV_ColorRGBTest(); 1271 protected: 1272 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 1273 double get_success_error_level( int test_case_idx, int i, int j ); 1274 void convert_forward( const Mat& src, Mat& dst ); 1275 void convert_backward( const Mat& src, const Mat& dst, Mat& dst2 ); 1276 int dst_bits; 1277 }; 1278 1279 1280 CV_ColorRGBTest::CV_ColorRGBTest() : CV_ColorCvtBaseTest( true, true, true ) 1281 { 1282 dst_bits = 0; 1283 } 1284 1285 1286 void CV_ColorRGBTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ) 1287 { 1288 RNG& rng = ts->get_rng(); 1289 CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 1290 int cn = CV_MAT_CN(types[INPUT][0]); 1291 1292 dst_bits = 24; 1293 1294 if( cvtest::randInt(rng) % 3 == 0 ) 1295 { 1296 types[INPUT][0] = types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(CV_8U,cn); 1297 types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(CV_8U,2); 1298 if( cvtest::randInt(rng) & 1 ) 1299 { 1300 if( blue_idx == 0 ) 1301 fwd_code = CV_BGR2BGR565, inv_code = CV_BGR5652BGR; 1302 else 1303 fwd_code = CV_RGB2BGR565, inv_code = CV_BGR5652RGB; 1304 dst_bits = 16; 1305 } 1306 else 1307 { 1308 if( blue_idx == 0 ) 1309 fwd_code = CV_BGR2BGR555, inv_code = CV_BGR5552BGR; 1310 else 1311 fwd_code = CV_RGB2BGR555, inv_code = CV_BGR5552RGB; 1312 dst_bits = 15; 1313 } 1314 } 1315 else 1316 { 1317 if( cn == 3 ) 1318 { 1319 fwd_code = CV_RGB2BGR, inv_code = CV_BGR2RGB; 1320 blue_idx = 2; 1321 } 1322 else if( blue_idx == 0 ) 1323 fwd_code = CV_BGRA2BGR, inv_code = CV_BGR2BGRA; 1324 else 1325 fwd_code = CV_RGBA2BGR, inv_code = CV_BGR2RGBA; 1326 } 1327 1328 if( CV_MAT_CN(types[INPUT][0]) != CV_MAT_CN(types[OUTPUT][0]) ) 1329 inplace = false; 1330 } 1331 1332 1333 double CV_ColorRGBTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) 1334 { 1335 return 0; 1336 } 1337 1338 1339 void CV_ColorRGBTest::convert_forward( const Mat& src, Mat& dst ) 1340 { 1341 int depth = src.depth(), cn = src.channels(); 1342 /*#if defined _DEBUG || defined DEBUG 1343 int dst_cn = CV_MAT_CN(dst->type); 1344 #endif*/ 1345 int i, j, cols = src.cols; 1346 int g_rshift = dst_bits == 16 ? 2 : 3; 1347 int r_lshift = dst_bits == 16 ? 11 : 10; 1348 1349 //assert( (cn == 3 || cn == 4) && (dst_cn == 3 || (dst_cn == 2 && depth == CV_8U)) ); 1350 1351 for( i = 0; i < src.rows; i++ ) 1352 { 1353 switch( depth ) 1354 { 1355 case CV_8U: 1356 { 1357 const uchar* src_row = src.ptr(i); 1358 uchar* dst_row = dst.ptr(i); 1359 1360 if( dst_bits == 24 ) 1361 { 1362 for( j = 0; j < cols; j++ ) 1363 { 1364 uchar b = src_row[j*cn + blue_idx]; 1365 uchar g = src_row[j*cn + 1]; 1366 uchar r = src_row[j*cn + (blue_idx^2)]; 1367 dst_row[j*3] = b; 1368 dst_row[j*3+1] = g; 1369 dst_row[j*3+2] = r; 1370 } 1371 } 1372 else 1373 { 1374 for( j = 0; j < cols; j++ ) 1375 { 1376 int b = src_row[j*cn + blue_idx] >> 3; 1377 int g = src_row[j*cn + 1] >> g_rshift; 1378 int r = src_row[j*cn + (blue_idx^2)] >> 3; 1379 ((ushort*)dst_row)[j] = (ushort)(b | (g << 5) | (r << r_lshift)); 1380 if( cn == 4 && src_row[j*4+3] ) 1381 ((ushort*)dst_row)[j] |= 1 << (r_lshift+5); 1382 } 1383 } 1384 } 1385 break; 1386 case CV_16U: 1387 { 1388 const ushort* src_row = src.ptr<ushort>(i); 1389 ushort* dst_row = dst.ptr<ushort>(i); 1390 1391 for( j = 0; j < cols; j++ ) 1392 { 1393 ushort b = src_row[j*cn + blue_idx]; 1394 ushort g = src_row[j*cn + 1]; 1395 ushort r = src_row[j*cn + (blue_idx^2)]; 1396 dst_row[j*3] = b; 1397 dst_row[j*3+1] = g; 1398 dst_row[j*3+2] = r; 1399 } 1400 } 1401 break; 1402 case CV_32F: 1403 { 1404 const float* src_row = src.ptr<float>(i); 1405 float* dst_row = dst.ptr<float>(i); 1406 1407 for( j = 0; j < cols; j++ ) 1408 { 1409 float b = src_row[j*cn + blue_idx]; 1410 float g = src_row[j*cn + 1]; 1411 float r = src_row[j*cn + (blue_idx^2)]; 1412 dst_row[j*3] = b; 1413 dst_row[j*3+1] = g; 1414 dst_row[j*3+2] = r; 1415 } 1416 } 1417 break; 1418 default: 1419 assert(0); 1420 } 1421 } 1422 } 1423 1424 1425 void CV_ColorRGBTest::convert_backward( const Mat& /*src*/, const Mat& src, Mat& dst ) 1426 { 1427 int depth = src.depth(), cn = dst.channels(); 1428 /*#if defined _DEBUG || defined DEBUG 1429 int src_cn = CV_MAT_CN(src->type); 1430 #endif*/ 1431 int i, j, cols = src.cols; 1432 int g_lshift = dst_bits == 16 ? 2 : 3; 1433 int r_rshift = dst_bits == 16 ? 11 : 10; 1434 1435 //assert( (cn == 3 || cn == 4) && (src_cn == 3 || (src_cn == 2 && depth == CV_8U)) ); 1436 1437 for( i = 0; i < src.rows; i++ ) 1438 { 1439 switch( depth ) 1440 { 1441 case CV_8U: 1442 { 1443 const uchar* src_row = src.ptr(i); 1444 uchar* dst_row = dst.ptr(i); 1445 1446 if( dst_bits == 24 ) 1447 { 1448 for( j = 0; j < cols; j++ ) 1449 { 1450 uchar b = src_row[j*3]; 1451 uchar g = src_row[j*3 + 1]; 1452 uchar r = src_row[j*3 + 2]; 1453 1454 dst_row[j*cn + blue_idx] = b; 1455 dst_row[j*cn + 1] = g; 1456 dst_row[j*cn + (blue_idx^2)] = r; 1457 1458 if( cn == 4 ) 1459 dst_row[j*cn + 3] = 255; 1460 } 1461 } 1462 else 1463 { 1464 for( j = 0; j < cols; j++ ) 1465 { 1466 ushort val = ((ushort*)src_row)[j]; 1467 uchar b = (uchar)(val << 3); 1468 uchar g = (uchar)((val >> 5) << g_lshift); 1469 uchar r = (uchar)((val >> r_rshift) << 3); 1470 1471 dst_row[j*cn + blue_idx] = b; 1472 dst_row[j*cn + 1] = g; 1473 dst_row[j*cn + (blue_idx^2)] = r; 1474 1475 if( cn == 4 ) 1476 { 1477 uchar alpha = r_rshift == 11 || (val & 0x8000) != 0 ? 255 : 0; 1478 dst_row[j*cn + 3] = alpha; 1479 } 1480 } 1481 } 1482 } 1483 break; 1484 case CV_16U: 1485 { 1486 const ushort* src_row = src.ptr<ushort>(i); 1487 ushort* dst_row = dst.ptr<ushort>(i); 1488 1489 for( j = 0; j < cols; j++ ) 1490 { 1491 ushort b = src_row[j*3]; 1492 ushort g = src_row[j*3 + 1]; 1493 ushort r = src_row[j*3 + 2]; 1494 1495 dst_row[j*cn + blue_idx] = b; 1496 dst_row[j*cn + 1] = g; 1497 dst_row[j*cn + (blue_idx^2)] = r; 1498 1499 if( cn == 4 ) 1500 dst_row[j*cn + 3] = 65535; 1501 } 1502 } 1503 break; 1504 case CV_32F: 1505 { 1506 const float* src_row = src.ptr<float>(i); 1507 float* dst_row = dst.ptr<float>(i); 1508 1509 for( j = 0; j < cols; j++ ) 1510 { 1511 float b = src_row[j*3]; 1512 float g = src_row[j*3 + 1]; 1513 float r = src_row[j*3 + 2]; 1514 1515 dst_row[j*cn + blue_idx] = b; 1516 dst_row[j*cn + 1] = g; 1517 dst_row[j*cn + (blue_idx^2)] = r; 1518 1519 if( cn == 4 ) 1520 dst_row[j*cn + 3] = 1.f; 1521 } 1522 } 1523 break; 1524 default: 1525 assert(0); 1526 } 1527 } 1528 } 1529 1530 1531 //// rgb <=> bayer 1532 1533 class CV_ColorBayerTest : public CV_ColorCvtBaseTest 1534 { 1535 public: 1536 CV_ColorBayerTest(); 1537 protected: 1538 void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ); 1539 double get_success_error_level( int test_case_idx, int i, int j ); 1540 void run_func(); 1541 void prepare_to_validation( int test_case_idx ); 1542 }; 1543 1544 1545 CV_ColorBayerTest::CV_ColorBayerTest() : CV_ColorCvtBaseTest( false, false, true ) 1546 { 1547 test_array[OUTPUT].pop_back(); 1548 test_array[REF_OUTPUT].pop_back(); 1549 1550 fwd_code_str = "BayerBG2BGR"; 1551 inv_code_str = ""; 1552 fwd_code = CV_BayerBG2BGR; 1553 inv_code = -1; 1554 } 1555 1556 1557 void CV_ColorBayerTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types ) 1558 { 1559 RNG& rng = ts->get_rng(); 1560 CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); 1561 1562 types[INPUT][0] = CV_MAT_DEPTH(types[INPUT][0]); 1563 types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(CV_MAT_DEPTH(types[INPUT][0]), 3); 1564 inplace = false; 1565 1566 fwd_code = cvtest::randInt(rng)%4 + CV_BayerBG2BGR; 1567 } 1568 1569 1570 double CV_ColorBayerTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ ) 1571 { 1572 return 1; 1573 } 1574 1575 1576 void CV_ColorBayerTest::run_func() 1577 { 1578 if(!test_cpp) 1579 cvCvtColor( test_array[INPUT][0], test_array[OUTPUT][0], fwd_code ); 1580 else 1581 { 1582 cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]); 1583 cv::cvtColor(cv::cvarrToMat(test_array[INPUT][0]), _out, fwd_code, _out.channels()); 1584 } 1585 } 1586 1587 1588 template<typename T> 1589 static void bayer2BGR_(const Mat& src, Mat& dst, int code) 1590 { 1591 int i, j, cols = src.cols - 2; 1592 int bi = 0; 1593 int step = (int)(src.step/sizeof(T)); 1594 1595 if( code == CV_BayerRG2BGR || code == CV_BayerGR2BGR ) 1596 bi ^= 2; 1597 1598 for( i = 1; i < src.rows - 1; i++ ) 1599 { 1600 const T* ptr = src.ptr<T>(i) + 1; 1601 T* dst_row = dst.ptr<T>(i) + 3; 1602 int save_code = code; 1603 if( cols <= 0 ) 1604 { 1605 dst_row[-3] = dst_row[-2] = dst_row[-1] = 0; 1606 dst_row[cols*3] = dst_row[cols*3+1] = dst_row[cols*3+2] = 0; 1607 continue; 1608 } 1609 1610 for( j = 0; j < cols; j++ ) 1611 { 1612 int b, g, r; 1613 if( !(code & 1) ) 1614 { 1615 b = ptr[j]; 1616 g = (ptr[j-1] + ptr[j+1] + ptr[j-step] + ptr[j+step])>>2; 1617 r = (ptr[j-step-1] + ptr[j-step+1] + ptr[j+step-1] + ptr[j+step+1]) >> 2; 1618 } 1619 else 1620 { 1621 b = (ptr[j-1] + ptr[j+1]) >> 1; 1622 g = ptr[j]; 1623 r = (ptr[j-step] + ptr[j+step]) >> 1; 1624 } 1625 code ^= 1; 1626 dst_row[j*3 + bi] = (T)b; 1627 dst_row[j*3 + 1] = (T)g; 1628 dst_row[j*3 + (bi^2)] = (T)r; 1629 } 1630 1631 dst_row[-3] = dst_row[0]; 1632 dst_row[-2] = dst_row[1]; 1633 dst_row[-1] = dst_row[2]; 1634 dst_row[cols*3] = dst_row[cols*3-3]; 1635 dst_row[cols*3+1] = dst_row[cols*3-2]; 1636 dst_row[cols*3+2] = dst_row[cols*3-1]; 1637 1638 code = save_code ^ 1; 1639 bi ^= 2; 1640 } 1641 1642 if( src.rows <= 2 ) 1643 { 1644 memset( dst.ptr(), 0, (cols+2)*3*sizeof(T) ); 1645 memset( dst.ptr(dst.rows-1), 0, (cols+2)*3*sizeof(T) ); 1646 } 1647 else 1648 { 1649 T* top_row = dst.ptr<T>(); 1650 T* bottom_row = dst.ptr<T>(dst.rows-1); 1651 int dstep = (int)(dst.step/sizeof(T)); 1652 1653 for( j = 0; j < (cols+2)*3; j++ ) 1654 { 1655 top_row[j] = top_row[j + dstep]; 1656 bottom_row[j] = bottom_row[j - dstep]; 1657 } 1658 } 1659 } 1660 1661 1662 void CV_ColorBayerTest::prepare_to_validation( int /*test_case_idx*/ ) 1663 { 1664 const Mat& src = test_mat[INPUT][0]; 1665 Mat& dst = test_mat[REF_OUTPUT][0]; 1666 int depth = src.depth(); 1667 if( depth == CV_8U ) 1668 bayer2BGR_<uchar>(src, dst, fwd_code); 1669 else if( depth == CV_16U ) 1670 bayer2BGR_<ushort>(src, dst, fwd_code); 1671 else 1672 CV_Error(CV_StsUnsupportedFormat, ""); 1673 } 1674 1675 1676 ///////////////////////////////////////////////////////////////////////////////////////////////// 1677 1678 TEST(Imgproc_ColorGray, accuracy) { CV_ColorGrayTest test; test.safe_run(); } 1679 TEST(Imgproc_ColorYCrCb, accuracy) { CV_ColorYCrCbTest test; test.safe_run(); } 1680 TEST(Imgproc_ColorHSV, accuracy) { CV_ColorHSVTest test; test.safe_run(); } 1681 TEST(Imgproc_ColorHLS, accuracy) { CV_ColorHLSTest test; test.safe_run(); } 1682 TEST(Imgproc_ColorXYZ, accuracy) { CV_ColorXYZTest test; test.safe_run(); } 1683 TEST(Imgproc_ColorLab, accuracy) { CV_ColorLabTest test; test.safe_run(); } 1684 TEST(Imgproc_ColorLuv, accuracy) { CV_ColorLuvTest test; test.safe_run(); } 1685 TEST(Imgproc_ColorRGB, accuracy) { CV_ColorRGBTest test; test.safe_run(); } 1686 TEST(Imgproc_ColorBayer, accuracy) { CV_ColorBayerTest test; test.safe_run(); } 1687 1688 TEST(Imgproc_ColorBayer, regression) 1689 { 1690 cvtest::TS* ts = cvtest::TS::ptr(); 1691 1692 Mat given = imread(string(ts->get_data_path()) + "/cvtcolor/bayer_input.png", IMREAD_GRAYSCALE); 1693 Mat gold = imread(string(ts->get_data_path()) + "/cvtcolor/bayer_gold.png", IMREAD_UNCHANGED); 1694 Mat result; 1695 1696 CV_Assert( !given.empty() && !gold.empty() ); 1697 1698 cvtColor(given, result, CV_BayerBG2GRAY); 1699 1700 EXPECT_EQ(gold.type(), result.type()); 1701 EXPECT_EQ(gold.cols, result.cols); 1702 EXPECT_EQ(gold.rows, result.rows); 1703 1704 Mat diff; 1705 absdiff(gold, result, diff); 1706 1707 EXPECT_EQ(0, countNonZero(diff.reshape(1) > 1)); 1708 } 1709 1710 TEST(Imgproc_ColorBayerVNG, regression) 1711 { 1712 cvtest::TS* ts = cvtest::TS::ptr(); 1713 1714 Mat given = imread(string(ts->get_data_path()) + "/cvtcolor/bayer_input.png", IMREAD_GRAYSCALE); 1715 string goldfname = string(ts->get_data_path()) + "/cvtcolor/bayerVNG_gold.png"; 1716 Mat gold = imread(goldfname, IMREAD_UNCHANGED); 1717 Mat result; 1718 1719 CV_Assert( !given.empty() ); 1720 1721 cvtColor(given, result, CV_BayerBG2BGR_VNG, 3); 1722 1723 if (gold.empty()) 1724 imwrite(goldfname, result); 1725 else 1726 { 1727 EXPECT_EQ(gold.type(), result.type()); 1728 EXPECT_EQ(gold.cols, result.cols); 1729 EXPECT_EQ(gold.rows, result.rows); 1730 1731 Mat diff; 1732 absdiff(gold, result, diff); 1733 1734 EXPECT_EQ(0, countNonZero(diff.reshape(1) > 1)); 1735 } 1736 } 1737 1738 // creating Bayer pattern 1739 template <typename T, int depth> 1740 static void calculateBayerPattern(const Mat& src, Mat& bayer, const char* pattern) 1741 { 1742 Size ssize = src.size(); 1743 const int scn = 1; 1744 bayer.create(ssize, CV_MAKETYPE(depth, scn)); 1745 1746 if (!strcmp(pattern, "bg")) 1747 { 1748 for (int y = 0; y < ssize.height; ++y) 1749 for (int x = 0; x < ssize.width; ++x) 1750 { 1751 if ((x + y) % 2) 1752 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[1]); 1753 else if (x % 2) 1754 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[0]); 1755 else 1756 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[2]); 1757 } 1758 } 1759 else if (!strcmp(pattern, "gb")) 1760 { 1761 for (int y = 0; y < ssize.height; ++y) 1762 for (int x = 0; x < ssize.width; ++x) 1763 { 1764 if ((x + y) % 2 == 0) 1765 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[1]); 1766 else if (x % 2 == 0) 1767 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[0]); 1768 else 1769 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[2]); 1770 } 1771 } 1772 else if (!strcmp(pattern, "rg")) 1773 { 1774 for (int y = 0; y < ssize.height; ++y) 1775 for (int x = 0; x < ssize.width; ++x) 1776 { 1777 if ((x + y) % 2) 1778 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[1]); 1779 else if (x % 2 == 0) 1780 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[0]); 1781 else 1782 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[2]); 1783 } 1784 } 1785 else 1786 { 1787 for (int y = 0; y < ssize.height; ++y) 1788 for (int x = 0; x < ssize.width; ++x) 1789 { 1790 if ((x + y) % 2 == 0) 1791 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[1]); 1792 else if (x % 2) 1793 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[0]); 1794 else 1795 bayer.at<T>(y, x) = static_cast<T>(src.at<Vec3b>(y, x)[2]); 1796 } 1797 } 1798 } 1799 1800 TEST(Imgproc_ColorBayerVNG_Strict, regression) 1801 { 1802 cvtest::TS* ts = cvtest::TS::ptr(); 1803 const char pattern[][3] = { "bg", "gb", "rg", "gr" }; 1804 const std::string image_name = "lena.png"; 1805 const std::string parent_path = string(ts->get_data_path()) + "/cvtcolor_strict/"; 1806 1807 Mat src, dst, bayer, reference; 1808 std::string full_path = parent_path + image_name; 1809 src = imread(full_path, IMREAD_UNCHANGED); 1810 1811 if ( src.empty() ) 1812 { 1813 ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA); 1814 ts->printf(cvtest::TS::SUMMARY, "No input image\n"); 1815 ts->set_gtest_status(); 1816 return; 1817 } 1818 1819 for (int i = 0; i < 4; ++i) 1820 { 1821 calculateBayerPattern<uchar, CV_8U>(src, bayer, pattern[i]); 1822 CV_Assert(!bayer.empty() && bayer.type() == CV_8UC1); 1823 1824 // calculating a dst image 1825 cvtColor(bayer, dst, CV_BayerBG2BGR_VNG + i); 1826 1827 // reading a reference image 1828 full_path = parent_path + pattern[i] + image_name; 1829 reference = imread(full_path, IMREAD_UNCHANGED); 1830 if ( reference.empty() ) 1831 { 1832 imwrite(full_path, dst); 1833 continue; 1834 } 1835 1836 if (reference.depth() != dst.depth() || reference.channels() != dst.channels() || 1837 reference.size() != dst.size()) 1838 { 1839 std::cout << reference(Rect(0, 0, 5, 5)) << std::endl << std::endl << std::endl; 1840 ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH); 1841 ts->printf(cvtest::TS::SUMMARY, "\nReference channels: %d\n" 1842 "Actual channels: %d\n", reference.channels(), dst.channels()); 1843 ts->printf(cvtest::TS::SUMMARY, "\nReference depth: %d\n" 1844 "Actual depth: %d\n", reference.depth(), dst.depth()); 1845 ts->printf(cvtest::TS::SUMMARY, "\nReference rows: %d\n" 1846 "Actual rows: %d\n", reference.rows, dst.rows); 1847 ts->printf(cvtest::TS::SUMMARY, "\nReference cols: %d\n" 1848 "Actual cols: %d\n", reference.cols, dst.cols); 1849 ts->set_gtest_status(); 1850 1851 return; 1852 } 1853 1854 Mat diff; 1855 absdiff(reference, dst, diff); 1856 1857 int nonZero = countNonZero(diff.reshape(1) > 1); 1858 if (nonZero != 0) 1859 { 1860 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 1861 ts->printf(cvtest::TS::SUMMARY, "\nCount non zero in absdiff: %d\n", nonZero); 1862 ts->set_gtest_status(); 1863 return; 1864 } 1865 } 1866 } 1867 1868 static void getTestMatrix(Mat& src) 1869 { 1870 Size ssize(1000, 1000); 1871 src.create(ssize, CV_32FC3); 1872 int szm = ssize.width - 1; 1873 float pi2 = 2 * 3.1415f; 1874 // Generate a pretty test image 1875 for (int i = 0; i < ssize.height; i++) 1876 { 1877 for (int j = 0; j < ssize.width; j++) 1878 { 1879 float b = (1 + cos((szm - i) * (szm - j) * pi2 / (10 * float(szm)))) / 2; 1880 float g = (1 + cos((szm - i) * j * pi2 / (10 * float(szm)))) / 2; 1881 float r = (1 + sin(i * j * pi2 / (10 * float(szm)))) / 2; 1882 1883 // The following lines aren't necessary, but just to prove that 1884 // the BGR values all lie in [0,1]... 1885 if (b < 0) b = 0; else if (b > 1) b = 1; 1886 if (g < 0) g = 0; else if (g > 1) g = 1; 1887 if (r < 0) r = 0; else if (r > 1) r = 1; 1888 src.at<cv::Vec3f>(i, j) = cv::Vec3f(b, g, r); 1889 } 1890 } 1891 } 1892 1893 static void validateResult(const Mat& reference, const Mat& actual, const Mat& src = Mat(), int mode = -1) 1894 { 1895 cvtest::TS* ts = cvtest::TS::ptr(); 1896 Size ssize = reference.size(); 1897 1898 int cn = reference.channels(); 1899 ssize.width *= cn; 1900 bool next = true; 1901 1902 for (int y = 0; y < ssize.height && next; ++y) 1903 { 1904 const float* rD = reference.ptr<float>(y); 1905 const float* D = actual.ptr<float>(y); 1906 for (int x = 0; x < ssize.width && next; ++x) 1907 if (fabs(rD[x] - D[x]) > 0.0001f) 1908 { 1909 next = false; 1910 ts->printf(cvtest::TS::SUMMARY, "Error in: (%d, %d)\n", x / cn, y); 1911 ts->printf(cvtest::TS::SUMMARY, "Reference value: %f\n", rD[x]); 1912 ts->printf(cvtest::TS::SUMMARY, "Actual value: %f\n", D[x]); 1913 if (!src.empty()) 1914 ts->printf(cvtest::TS::SUMMARY, "Src value: %f\n", src.ptr<float>(y)[x]); 1915 ts->printf(cvtest::TS::SUMMARY, "Size: (%d, %d)\n", reference.rows, reference.cols); 1916 1917 if (mode >= 0) 1918 { 1919 cv::Mat lab; 1920 cv::cvtColor(src, lab, mode); 1921 std::cout << "lab: " << lab(cv::Rect(y, x / cn, 1, 1)) << std::endl; 1922 } 1923 std::cout << "src: " << src(cv::Rect(y, x / cn, 1, 1)) << std::endl; 1924 1925 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 1926 ts->set_gtest_status(); 1927 } 1928 } 1929 } 1930 1931 TEST(Imgproc_ColorLab_Full, accuracy) 1932 { 1933 Mat src; 1934 getTestMatrix(src); 1935 Size ssize = src.size(); 1936 CV_Assert(ssize.width == ssize.height); 1937 1938 RNG& rng = cvtest::TS::ptr()->get_rng(); 1939 int blueInd = rng.uniform(0., 1.) > 0.5 ? 0 : 2; 1940 bool srgb = rng.uniform(0., 1.) > 0.5; 1941 1942 // Convert test image to LAB 1943 cv::Mat lab; 1944 int forward_code = blueInd ? srgb ? CV_BGR2Lab : CV_LBGR2Lab : srgb ? CV_RGB2Lab : CV_LRGB2Lab; 1945 int inverse_code = blueInd ? srgb ? CV_Lab2BGR : CV_Lab2LBGR : srgb ? CV_Lab2RGB : CV_Lab2LRGB; 1946 cv::cvtColor(src, lab, forward_code); 1947 // Convert LAB image back to BGR(RGB) 1948 cv::Mat recons; 1949 cv::cvtColor(lab, recons, inverse_code); 1950 1951 validateResult(src, recons, src, forward_code); 1952 } 1953 1954 static void test_Bayer2RGB_EdgeAware_8u(const Mat& src, Mat& dst, int code) 1955 { 1956 if (dst.empty()) 1957 dst.create(src.size(), CV_MAKETYPE(src.depth(), 3)); 1958 Size size = src.size(); 1959 size.width -= 1; 1960 size.height -= 1; 1961 1962 int dcn = dst.channels(); 1963 CV_Assert(dcn == 3); 1964 1965 int step = (int)src.step; 1966 const uchar* S = src.ptr<uchar>(1) + 1; 1967 uchar* D = dst.ptr<uchar>(1) + dcn; 1968 1969 int start_with_green = code == CV_BayerGB2BGR_EA || code == CV_BayerGR2BGR_EA ? 1 : 0; 1970 int blue = code == CV_BayerGB2BGR_EA || code == CV_BayerBG2BGR_EA ? 1 : 0; 1971 1972 for (int y = 1; y < size.height; ++y) 1973 { 1974 S = src.ptr<uchar>(y) + 1; 1975 D = dst.ptr<uchar>(y) + dcn; 1976 1977 if (start_with_green) 1978 { 1979 for (int x = 1; x < size.width; x += 2, S += 2, D += 2*dcn) 1980 { 1981 // red 1982 D[0] = (S[-1] + S[1]) / 2; 1983 D[1] = S[0]; 1984 D[2] = (S[-step] + S[step]) / 2; 1985 if (!blue) 1986 std::swap(D[0], D[2]); 1987 } 1988 1989 S = src.ptr<uchar>(y) + 2; 1990 D = dst.ptr<uchar>(y) + 2*dcn; 1991 1992 for (int x = 2; x < size.width; x += 2, S += 2, D += 2*dcn) 1993 { 1994 // red 1995 D[0] = S[0]; 1996 D[1] = (std::abs(S[-1] - S[1]) > std::abs(S[step] - S[-step]) ? (S[step] + S[-step] + 1) : (S[-1] + S[1] + 1)) / 2; 1997 D[2] = ((S[-step-1] + S[-step+1] + S[step-1] + S[step+1] + 2) / 4); 1998 if (!blue) 1999 std::swap(D[0], D[2]); 2000 } 2001 } 2002 else 2003 { 2004 for (int x = 1; x < size.width; x += 2, S += 2, D += 2*dcn) 2005 { 2006 D[0] = S[0]; 2007 D[1] = (std::abs(S[-1] - S[1]) > std::abs(S[step] - S[-step]) ? (S[step] + S[-step] + 1) : (S[-1] + S[1] + 1)) / 2; 2008 D[2] = ((S[-step-1] + S[-step+1] + S[step-1] + S[step+1] + 2) / 4); 2009 if (!blue) 2010 std::swap(D[0], D[2]); 2011 } 2012 2013 S = src.ptr<uchar>(y) + 2; 2014 D = dst.ptr<uchar>(y) + 2*dcn; 2015 2016 for (int x = 2; x < size.width; x += 2, S += 2, D += 2*dcn) 2017 { 2018 D[0] = (S[-1] + S[1] + 1) / 2; 2019 D[1] = S[0]; 2020 D[2] = (S[-step] + S[step] + 1) / 2; 2021 if (!blue) 2022 std::swap(D[0], D[2]); 2023 } 2024 } 2025 2026 D = dst.ptr<uchar>(y + 1) - dcn; 2027 for (int i = 0; i < dcn; ++i) 2028 { 2029 D[i] = D[-dcn + i]; 2030 D[-static_cast<int>(dst.step)+dcn+i] = D[-static_cast<int>(dst.step)+(dcn<<1)+i]; 2031 } 2032 2033 start_with_green ^= 1; 2034 blue ^= 1; 2035 } 2036 2037 ++size.width; 2038 uchar* firstRow = dst.ptr(), *lastRow = dst.ptr(size.height); 2039 size.width *= dcn; 2040 for (int x = 0; x < size.width; ++x) 2041 { 2042 firstRow[x] = firstRow[dst.step + x]; 2043 lastRow[x] = lastRow[-static_cast<int>(dst.step)+x]; 2044 } 2045 } 2046 2047 template <typename T> 2048 static void checkData(const Mat& actual, const Mat& reference, cvtest::TS* ts, const char* type, 2049 bool& next, const char* bayer_type) 2050 { 2051 EXPECT_EQ(actual.size(), reference.size()); 2052 EXPECT_EQ(actual.channels(), reference.channels()); 2053 EXPECT_EQ(actual.depth(), reference.depth()); 2054 2055 Size size = reference.size(); 2056 int dcn = reference.channels(); 2057 size.width *= dcn; 2058 2059 for (int y = 0; y < size.height && next; ++y) 2060 { 2061 const T* A = actual.ptr<T>(y); 2062 const T* R = reference.ptr<T>(y); 2063 2064 for (int x = 0; x < size.width && next; ++x) 2065 if (std::abs(A[x] - R[x]) > 1) 2066 { 2067 #define SUM cvtest::TS::SUMMARY 2068 ts->printf(SUM, "\nReference value: %d\n", static_cast<int>(R[x])); 2069 ts->printf(SUM, "Actual value: %d\n", static_cast<int>(A[x])); 2070 ts->printf(SUM, "(y, x): (%d, %d)\n", y, x / reference.channels()); 2071 ts->printf(SUM, "Channel pos: %d\n", x % reference.channels()); 2072 ts->printf(SUM, "Pattern: %s\n", type); 2073 ts->printf(SUM, "Bayer image type: %s", bayer_type); 2074 #undef SUM 2075 2076 Mat diff; 2077 absdiff(actual, reference, diff); 2078 EXPECT_EQ(countNonZero(diff.reshape(1) > 1), 0); 2079 2080 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 2081 ts->set_gtest_status(); 2082 2083 next = false; 2084 } 2085 } 2086 } 2087 2088 TEST(ImgProc_BayerEdgeAwareDemosaicing, accuracy) 2089 { 2090 cvtest::TS* ts = cvtest::TS::ptr(); 2091 const std::string image_name = "lena.png"; 2092 const std::string parent_path = string(ts->get_data_path()) + "/cvtcolor_strict/"; 2093 2094 Mat src, bayer; 2095 std::string full_path = parent_path + image_name; 2096 src = imread(full_path, IMREAD_UNCHANGED); 2097 2098 if (src.empty()) 2099 { 2100 ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA); 2101 ts->printf(cvtest::TS::SUMMARY, "No input image\n"); 2102 ts->set_gtest_status(); 2103 return; 2104 } 2105 2106 /* 2107 COLOR_BayerBG2BGR_EA = 127, 2108 COLOR_BayerGB2BGR_EA = 128, 2109 COLOR_BayerRG2BGR_EA = 129, 2110 COLOR_BayerGR2BGR_EA = 130, 2111 */ 2112 2113 bool next = true; 2114 const char* types[] = { "bg", "gb", "rg", "gr" }; 2115 for (int i = 0; i < 4 && next; ++i) 2116 { 2117 calculateBayerPattern<uchar, CV_8U>(src, bayer, types[i]); 2118 Mat reference; 2119 test_Bayer2RGB_EdgeAware_8u(bayer, reference, CV_BayerBG2BGR_EA + i); 2120 2121 for (int t = 0; t <= 1; ++t) 2122 { 2123 if (t == 1) 2124 calculateBayerPattern<unsigned short int, CV_16U>(src, bayer, types[i]); 2125 2126 CV_Assert(!bayer.empty() && (bayer.type() == CV_8UC1 || bayer.type() == CV_16UC1)); 2127 2128 Mat actual; 2129 cv::demosaicing(bayer, actual, CV_BayerBG2BGR_EA + i); 2130 2131 if (t == 0) 2132 checkData<unsigned char>(actual, reference, ts, types[i], next, "CV_8U"); 2133 else 2134 { 2135 Mat tmp; 2136 reference.convertTo(tmp, CV_16U); 2137 checkData<unsigned short int>(actual, tmp, ts, types[i], next, "CV_16U"); 2138 } 2139 } 2140 } 2141 } 2142 2143 TEST(ImgProc_Bayer2RGBA, accuracy) 2144 { 2145 cvtest::TS* ts = cvtest::TS::ptr(); 2146 Mat raw = imread(string(ts->get_data_path()) + "/cvtcolor/bayer_input.png", IMREAD_GRAYSCALE); 2147 Mat rgb, reference; 2148 2149 CV_Assert(raw.channels() == 1); 2150 CV_Assert(raw.depth() == CV_8U); 2151 CV_Assert(!raw.empty()); 2152 2153 for (int code = CV_BayerBG2BGR; code <= CV_BayerGR2BGR; ++code) 2154 { 2155 cvtColor(raw, rgb, code); 2156 cvtColor(rgb, reference, CV_BGR2BGRA); 2157 2158 Mat actual; 2159 cvtColor(raw, actual, code, 4); 2160 2161 EXPECT_EQ(reference.size(), actual.size()); 2162 EXPECT_EQ(reference.depth(), actual.depth()); 2163 EXPECT_EQ(reference.channels(), actual.channels()); 2164 2165 Size ssize = raw.size(); 2166 int cn = reference.channels(); 2167 ssize.width *= cn; 2168 bool next = true; 2169 for (int y = 0; y < ssize.height && next; ++y) 2170 { 2171 const uchar* rD = reference.ptr<uchar>(y); 2172 const uchar* D = actual.ptr<uchar>(y); 2173 for (int x = 0; x < ssize.width && next; ++x) 2174 if (abs(rD[x] - D[x]) >= 1) 2175 { 2176 next = false; 2177 ts->printf(cvtest::TS::SUMMARY, "Error in: (%d, %d)\n", x / cn, y); 2178 ts->printf(cvtest::TS::SUMMARY, "Reference value: %d\n", rD[x]); 2179 ts->printf(cvtest::TS::SUMMARY, "Actual value: %d\n", D[x]); 2180 ts->printf(cvtest::TS::SUMMARY, "Src value: %d\n", raw.ptr<uchar>(y)[x]); 2181 ts->printf(cvtest::TS::SUMMARY, "Size: (%d, %d)\n", reference.rows, reference.cols); 2182 2183 Mat diff; 2184 absdiff(actual, reference, diff); 2185 EXPECT_EQ(countNonZero(diff.reshape(1) > 1), 0); 2186 2187 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 2188 ts->set_gtest_status(); 2189 } 2190 } 2191 } 2192 } 2193