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 class CV_FloodFillTest : public cvtest::ArrayTest
     48 {
     49 public:
     50     CV_FloodFillTest();
     51 
     52 protected:
     53     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
     54     double get_success_error_level( int test_case_idx, int i, int j );
     55     void run_func();
     56     void prepare_to_validation( int );
     57 
     58     void fill_array( int test_case_idx, int i, int j, Mat& arr );
     59 
     60     /*int write_default_params(CvFileStorage* fs);
     61     void get_timing_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types
     62                                                 CvSize** whole_sizes, bool *are_images );
     63     void print_timing_params( int test_case_idx, char* ptr, int params_left );*/
     64     CvPoint seed_pt;
     65     CvScalar new_val;
     66     CvScalar l_diff, u_diff;
     67     int connectivity;
     68     bool use_mask, mask_only;
     69     int range_type;
     70     int new_mask_val;
     71     bool test_cpp;
     72 };
     73 
     74 
     75 CV_FloodFillTest::CV_FloodFillTest()
     76 {
     77     test_array[INPUT_OUTPUT].push_back(NULL);
     78     test_array[INPUT_OUTPUT].push_back(NULL);
     79     test_array[REF_INPUT_OUTPUT].push_back(NULL);
     80     test_array[REF_INPUT_OUTPUT].push_back(NULL);
     81     test_array[OUTPUT].push_back(NULL);
     82     test_array[REF_OUTPUT].push_back(NULL);
     83     optional_mask = false;
     84     element_wise_relative_error = true;
     85 
     86     test_cpp = false;
     87 }
     88 
     89 
     90 void CV_FloodFillTest::get_test_array_types_and_sizes( int test_case_idx,
     91                                                        vector<vector<Size> >& sizes,
     92                                                        vector<vector<int> >& types )
     93 {
     94     RNG& rng = ts->get_rng();
     95     int depth, cn;
     96     int i;
     97     double buff[8];
     98     cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
     99 
    100     depth = cvtest::randInt(rng) % 3;
    101     depth = depth == 0 ? CV_8U : depth == 1 ? CV_32S : CV_32F;
    102     cn = cvtest::randInt(rng) & 1 ? 3 : 1;
    103 
    104     use_mask = (cvtest::randInt(rng) & 1) != 0;
    105     connectivity = (cvtest::randInt(rng) & 1) ? 4 : 8;
    106     mask_only = use_mask && (cvtest::randInt(rng) & 1) != 0;
    107     new_mask_val = cvtest::randInt(rng) & 255;
    108     range_type = cvtest::randInt(rng) % 3;
    109 
    110     types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn);
    111     types[INPUT_OUTPUT][1] = types[REF_INPUT_OUTPUT][1] = CV_8UC1;
    112     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
    113     sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(9,1);
    114 
    115     if( !use_mask )
    116         sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = cvSize(0,0);
    117     else
    118     {
    119         CvSize sz = sizes[INPUT_OUTPUT][0];
    120         sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = cvSize(sz.width+2,sz.height+2);
    121     }
    122 
    123     seed_pt.x = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].width;
    124     seed_pt.y = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].height;
    125 
    126     if( range_type == 0 )
    127         l_diff = u_diff = Scalar::all(0.);
    128     else
    129     {
    130         Mat m( 1, 8, CV_16S, buff );
    131         rng.fill( m, RNG::NORMAL, Scalar::all(0), Scalar::all(32) );
    132         for( i = 0; i < 4; i++ )
    133         {
    134             l_diff.val[i] = fabs(m.at<short>(i)/16.);
    135             u_diff.val[i] = fabs(m.at<short>(i+4)/16.);
    136         }
    137     }
    138 
    139     new_val = Scalar::all(0.);
    140     for( i = 0; i < cn; i++ )
    141         new_val.val[i] = cvtest::randReal(rng)*255;
    142 
    143     test_cpp = (cvtest::randInt(rng) & 256) == 0;
    144 }
    145 
    146 
    147 double CV_FloodFillTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
    148 {
    149     return i == OUTPUT ? FLT_EPSILON : j == 0 ? FLT_EPSILON : 0;
    150 }
    151 
    152 
    153 void CV_FloodFillTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
    154 {
    155     RNG& rng = ts->get_rng();
    156 
    157     if( i != INPUT && i != INPUT_OUTPUT )
    158     {
    159         cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
    160         return;
    161     }
    162 
    163     if( j == 0 )
    164     {
    165         Mat tmp = arr;
    166         Scalar m = Scalar::all(128);
    167         Scalar s = Scalar::all(10);
    168 
    169         if( arr.depth() == CV_32FC1 )
    170             tmp.create(arr.size(), CV_MAKETYPE(CV_8U, arr.channels()));
    171 
    172         if( range_type == 0 )
    173             s = Scalar::all(2);
    174 
    175         rng.fill(tmp, RNG::NORMAL, m, s );
    176         if( arr.data != tmp.data )
    177             cvtest::convert(tmp, arr, arr.type());
    178     }
    179     else
    180     {
    181         Scalar l = Scalar::all(-2);
    182         Scalar u = Scalar::all(2);
    183         cvtest::randUni(rng, arr, l, u );
    184         rectangle( arr, Point(0,0), Point(arr.cols-1,arr.rows-1), Scalar::all(1), 1, 8, 0 );
    185     }
    186 }
    187 
    188 
    189 void CV_FloodFillTest::run_func()
    190 {
    191     int flags = connectivity + (mask_only ? CV_FLOODFILL_MASK_ONLY : 0) +
    192         (range_type == 1 ? CV_FLOODFILL_FIXED_RANGE : 0) + (new_mask_val << 8);
    193     double* odata = test_mat[OUTPUT][0].ptr<double>();
    194 
    195     if(!test_cpp)
    196     {
    197         CvConnectedComp comp;
    198         cvFloodFill( test_array[INPUT_OUTPUT][0], seed_pt, new_val, l_diff, u_diff, &comp,
    199                      flags, test_array[INPUT_OUTPUT][1] );
    200         odata[0] = comp.area;
    201         odata[1] = comp.rect.x;
    202         odata[2] = comp.rect.y;
    203         odata[3] = comp.rect.width;
    204         odata[4] = comp.rect.height;
    205         odata[5] = comp.value.val[0];
    206         odata[6] = comp.value.val[1];
    207         odata[7] = comp.value.val[2];
    208         odata[8] = comp.value.val[3];
    209     }
    210     else
    211     {
    212         cv::Mat img = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]),
    213             mask = test_array[INPUT_OUTPUT][1] ? cv::cvarrToMat(test_array[INPUT_OUTPUT][1]) : cv::Mat();
    214         cv::Rect rect;
    215         int area;
    216         if( mask.empty() )
    217             area = cv::floodFill( img, seed_pt, new_val, &rect, l_diff, u_diff, flags );
    218         else
    219             area = cv::floodFill( img, mask, seed_pt, new_val, &rect, l_diff, u_diff, flags );
    220         odata[0] = area;
    221         odata[1] = rect.x;
    222         odata[2] = rect.y;
    223         odata[3] = rect.width;
    224         odata[4] = rect.height;
    225         odata[5] = odata[6] = odata[7] = odata[8] = 0;
    226     }
    227 }
    228 
    229 
    230 typedef struct ff_offset_pair_t
    231 {
    232     int mofs, iofs;
    233 }
    234 ff_offset_pair_t;
    235 
    236 static void
    237 cvTsFloodFill( CvMat* _img, CvPoint seed_pt, CvScalar new_val,
    238                CvScalar l_diff, CvScalar u_diff, CvMat* _mask,
    239                double* comp, int connectivity, int range_type,
    240                int new_mask_val, bool mask_only )
    241 {
    242     CvMemStorage* st = cvCreateMemStorage();
    243     ff_offset_pair_t p0, p;
    244     CvSeq* seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(p0), st );
    245     CvMat* tmp = _img;
    246     CvMat* mask;
    247     CvRect r = cvRect( 0, 0, -1, -1 );
    248     int area = 0;
    249     int i, j;
    250     ushort* m;
    251     float* img;
    252     int mstep, step;
    253     int cn = CV_MAT_CN(_img->type);
    254     int mdelta[8], idelta[8], ncount;
    255     int cols = _img->cols, rows = _img->rows;
    256     int u0 = 0, u1 = 0, u2 = 0;
    257     double s0 = 0, s1 = 0, s2 = 0;
    258 
    259     if( CV_MAT_DEPTH(_img->type) == CV_8U || CV_MAT_DEPTH(_img->type) == CV_32S )
    260     {
    261         tmp = cvCreateMat( rows, cols, CV_MAKETYPE(CV_32F,CV_MAT_CN(_img->type)) );
    262         cvtest::convert(cvarrToMat(_img), cvarrToMat(tmp), -1);
    263     }
    264 
    265     mask = cvCreateMat( rows + 2, cols + 2, CV_16UC1 );
    266 
    267     if( _mask )
    268         cvtest::convert(cvarrToMat(_mask), cvarrToMat(mask), -1);
    269     else
    270     {
    271         Mat m_mask = cvarrToMat(mask);
    272         cvtest::set( m_mask, Scalar::all(0), Mat() );
    273         cvRectangle( mask, cvPoint(0,0), cvPoint(mask->cols-1,mask->rows-1), Scalar::all(1.), 1, 8, 0 );
    274     }
    275 
    276     new_mask_val = (new_mask_val != 0 ? new_mask_val : 1) << 8;
    277 
    278     m = (ushort*)(mask->data.ptr + mask->step) + 1;
    279     mstep = mask->step / sizeof(m[0]);
    280     img = tmp->data.fl;
    281     step = tmp->step / sizeof(img[0]);
    282 
    283     p0.mofs = seed_pt.y*mstep + seed_pt.x;
    284     p0.iofs = seed_pt.y*step + seed_pt.x*cn;
    285 
    286     if( m[p0.mofs] )
    287         goto _exit_;
    288 
    289     cvSeqPush( seq, &p0 );
    290     m[p0.mofs] = (ushort)new_mask_val;
    291 
    292     if( connectivity == 4 )
    293     {
    294         ncount = 4;
    295         mdelta[0] = -mstep; idelta[0] = -step;
    296         mdelta[1] = -1; idelta[1] = -cn;
    297         mdelta[2] = 1; idelta[2] = cn;
    298         mdelta[3] = mstep; idelta[3] = step;
    299     }
    300     else
    301     {
    302         ncount = 8;
    303         mdelta[0] = -mstep-1; mdelta[1] = -mstep; mdelta[2] = -mstep+1;
    304         idelta[0] = -step-cn; idelta[1] = -step; idelta[2] = -step+cn;
    305 
    306         mdelta[3] = -1; mdelta[4] = 1;
    307         idelta[3] = -cn; idelta[4] = cn;
    308 
    309         mdelta[5] = mstep-1; mdelta[6] = mstep; mdelta[7] = mstep+1;
    310         idelta[5] = step-cn; idelta[6] = step; idelta[7] = step+cn;
    311     }
    312 
    313     if( cn == 1 )
    314     {
    315         float a0 = (float)-l_diff.val[0];
    316         float b0 = (float)u_diff.val[0];
    317 
    318         s0 = img[p0.iofs];
    319 
    320         if( range_type < 2 )
    321         {
    322             a0 += (float)s0; b0 += (float)s0;
    323         }
    324 
    325         while( seq->total )
    326         {
    327             cvSeqPop( seq, &p0 );
    328             float a = a0, b = b0;
    329             float* ptr = img + p0.iofs;
    330             ushort* mptr = m + p0.mofs;
    331 
    332             if( range_type == 2 )
    333                 a += ptr[0], b += ptr[0];
    334 
    335             for( i = 0; i < ncount; i++ )
    336             {
    337                 int md = mdelta[i], id = idelta[i];
    338                 float v;
    339                 if( !mptr[md] && a <= (v = ptr[id]) && v <= b )
    340                 {
    341                     mptr[md] = (ushort)new_mask_val;
    342                     p.mofs = p0.mofs + md;
    343                     p.iofs = p0.iofs + id;
    344                     cvSeqPush( seq, &p );
    345                 }
    346             }
    347         }
    348     }
    349     else
    350     {
    351         float a0 = (float)-l_diff.val[0];
    352         float a1 = (float)-l_diff.val[1];
    353         float a2 = (float)-l_diff.val[2];
    354         float b0 = (float)u_diff.val[0];
    355         float b1 = (float)u_diff.val[1];
    356         float b2 = (float)u_diff.val[2];
    357 
    358         s0 = img[p0.iofs];
    359         s1 = img[p0.iofs + 1];
    360         s2 = img[p0.iofs + 2];
    361 
    362         if( range_type < 2 )
    363         {
    364             a0 += (float)s0; b0 += (float)s0;
    365             a1 += (float)s1; b1 += (float)s1;
    366             a2 += (float)s2; b2 += (float)s2;
    367         }
    368 
    369         while( seq->total )
    370         {
    371             cvSeqPop( seq, &p0 );
    372             float _a0 = a0, _a1 = a1, _a2 = a2;
    373             float _b0 = b0, _b1 = b1, _b2 = b2;
    374             float* ptr = img + p0.iofs;
    375             ushort* mptr = m + p0.mofs;
    376 
    377             if( range_type == 2 )
    378             {
    379                 _a0 += ptr[0]; _b0 += ptr[0];
    380                 _a1 += ptr[1]; _b1 += ptr[1];
    381                 _a2 += ptr[2]; _b2 += ptr[2];
    382             }
    383 
    384             for( i = 0; i < ncount; i++ )
    385             {
    386                 int md = mdelta[i], id = idelta[i];
    387                 float v;
    388                 if( !mptr[md] &&
    389                     _a0 <= (v = ptr[id]) && v <= _b0 &&
    390                     _a1 <= (v = ptr[id+1]) && v <= _b1 &&
    391                     _a2 <= (v = ptr[id+2]) && v <= _b2 )
    392                 {
    393                     mptr[md] = (ushort)new_mask_val;
    394                     p.mofs = p0.mofs + md;
    395                     p.iofs = p0.iofs + id;
    396                     cvSeqPush( seq, &p );
    397                 }
    398             }
    399         }
    400     }
    401 
    402     r.x = r.width = seed_pt.x;
    403     r.y = r.height = seed_pt.y;
    404 
    405     if( !mask_only )
    406     {
    407         s0 = new_val.val[0];
    408         s1 = new_val.val[1];
    409         s2 = new_val.val[2];
    410 
    411         if( tmp != _img )
    412         {
    413             u0 = saturate_cast<uchar>(s0);
    414             u1 = saturate_cast<uchar>(s1);
    415             u2 = saturate_cast<uchar>(s2);
    416 
    417             s0 = u0;
    418             s1 = u1;
    419             s2 = u2;
    420         }
    421     }
    422     else
    423         s0 = s1 = s2 = 0;
    424 
    425     new_mask_val >>= 8;
    426 
    427     for( i = 0; i < rows; i++ )
    428     {
    429         float* ptr = img + i*step;
    430         ushort* mptr = m + i*mstep;
    431         uchar* dmptr = _mask ? _mask->data.ptr + (i+1)*_mask->step + 1 : 0;
    432         double area0 = area;
    433 
    434         for( j = 0; j < cols; j++ )
    435         {
    436             if( mptr[j] > 255 )
    437             {
    438                 if( dmptr )
    439                     dmptr[j] = (uchar)new_mask_val;
    440                 if( !mask_only )
    441                 {
    442                     if( cn == 1 )
    443                         ptr[j] = (float)s0;
    444                     else
    445                     {
    446                         ptr[j*3] = (float)s0;
    447                         ptr[j*3+1] = (float)s1;
    448                         ptr[j*3+2] = (float)s2;
    449                     }
    450                 }
    451                 else
    452                 {
    453                     if( cn == 1 )
    454                         s0 += ptr[j];
    455                     else
    456                     {
    457                         s0 += ptr[j*3];
    458                         s1 += ptr[j*3+1];
    459                         s2 += ptr[j*3+2];
    460                     }
    461                 }
    462 
    463                 area++;
    464                 if( r.x > j )
    465                     r.x = j;
    466                 if( r.width < j )
    467                     r.width = j;
    468             }
    469         }
    470 
    471         if( area != area0 )
    472         {
    473             if( r.y > i )
    474                 r.y = i;
    475             if( r.height < i )
    476                 r.height = i;
    477         }
    478     }
    479 
    480 _exit_:
    481     cvReleaseMat( &mask );
    482     if( tmp != _img )
    483     {
    484         if( !mask_only )
    485             cvtest::convert(cvarrToMat(tmp), cvarrToMat(_img), -1);
    486         cvReleaseMat( &tmp );
    487     }
    488 
    489     comp[0] = area;
    490     comp[1] = r.x;
    491     comp[2] = r.y;
    492     comp[3] = r.width - r.x + 1;
    493     comp[4] = r.height - r.y + 1;
    494 #if 0
    495     if( mask_only )
    496     {
    497         double t = area ? 1./area : 0;
    498         s0 *= t;
    499         s1 *= t;
    500         s2 *= t;
    501     }
    502     comp[5] = s0;
    503     comp[6] = s1;
    504     comp[7] = s2;
    505 #else
    506     comp[5] = new_val.val[0];
    507     comp[6] = new_val.val[1];
    508     comp[7] = new_val.val[2];
    509 #endif
    510     comp[8] = 0;
    511 }
    512 
    513 
    514 void CV_FloodFillTest::prepare_to_validation( int /*test_case_idx*/ )
    515 {
    516     double* comp = test_mat[REF_OUTPUT][0].ptr<double>();
    517     CvMat _input = test_mat[REF_INPUT_OUTPUT][0];
    518     CvMat _mask = test_mat[REF_INPUT_OUTPUT][1];
    519     cvTsFloodFill( &_input, seed_pt, new_val, l_diff, u_diff,
    520                    _mask.data.ptr ? &_mask : 0,
    521                    comp, connectivity, range_type,
    522                    new_mask_val, mask_only );
    523     if(test_cpp)
    524         comp[5] = comp[6] = comp[7] = comp[8] = 0;
    525 }
    526 
    527 TEST(Imgproc_FloodFill, accuracy) { CV_FloodFillTest test; test.safe_run(); }
    528 
    529 /* End of file. */
    530