Home | History | Annotate | Download | only in test
      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