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_DisTransTest : public cvtest::ArrayTest
     48 {
     49 public:
     50     CV_DisTransTest();
     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 get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
     59     int prepare_test_case( int test_case_idx );
     60 
     61     int mask_size;
     62     int dist_type;
     63     int fill_labels;
     64     float mask[3];
     65 };
     66 
     67 
     68 CV_DisTransTest::CV_DisTransTest()
     69 {
     70     test_array[INPUT].push_back(NULL);
     71     test_array[OUTPUT].push_back(NULL);
     72     test_array[OUTPUT].push_back(NULL);
     73     test_array[REF_OUTPUT].push_back(NULL);
     74     test_array[REF_OUTPUT].push_back(NULL);
     75     optional_mask = false;
     76     element_wise_relative_error = true;
     77 }
     78 
     79 
     80 void CV_DisTransTest::get_test_array_types_and_sizes( int test_case_idx,
     81                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
     82 {
     83     RNG& rng = ts->get_rng();
     84     cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
     85 
     86     types[INPUT][0] = CV_8UC1;
     87     types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1;
     88     types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_32SC1;
     89 
     90     if( cvtest::randInt(rng) & 1 )
     91     {
     92         mask_size = 3;
     93     }
     94     else
     95     {
     96         mask_size = 5;
     97     }
     98 
     99     dist_type = cvtest::randInt(rng) % 3;
    100     dist_type = dist_type == 0 ? CV_DIST_C : dist_type == 1 ? CV_DIST_L1 : CV_DIST_L2;
    101 
    102     // for now, check only the "labeled" distance transform mode
    103     fill_labels = 0;
    104 
    105     if( !fill_labels )
    106         sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = cvSize(0,0);
    107 }
    108 
    109 
    110 double CV_DisTransTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
    111 {
    112     Size sz = test_mat[INPUT][0].size();
    113     return dist_type == CV_DIST_C || dist_type == CV_DIST_L1 ? 0 : 0.01*MAX(sz.width, sz.height);
    114 }
    115 
    116 
    117 void CV_DisTransTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
    118 {
    119     cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
    120     if( i == INPUT && CV_MAT_DEPTH(type) == CV_8U )
    121     {
    122         low = Scalar::all(0);
    123         high = Scalar::all(10);
    124     }
    125 }
    126 
    127 int CV_DisTransTest::prepare_test_case( int test_case_idx )
    128 {
    129     int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
    130     if( code > 0 )
    131     {
    132         // the function's response to an "all-nonzeros" image is not determined,
    133         // so put at least one zero point
    134         Mat& mat = test_mat[INPUT][0];
    135         RNG& rng = ts->get_rng();
    136         int i = cvtest::randInt(rng) % mat.rows;
    137         int j = cvtest::randInt(rng) % mat.cols;
    138         mat.at<uchar>(i,j) = 0;
    139     }
    140 
    141     return code;
    142 }
    143 
    144 
    145 void CV_DisTransTest::run_func()
    146 {
    147     cvDistTransform( test_array[INPUT][0], test_array[OUTPUT][0], dist_type, mask_size,
    148                      dist_type == CV_DIST_USER ? mask : 0, test_array[OUTPUT][1] );
    149 }
    150 
    151 
    152 static void
    153 cvTsDistTransform( const CvMat* _src, CvMat* _dst, int dist_type,
    154                    int mask_size, float* _mask, CvMat* /*_labels*/ )
    155 {
    156     int i, j, k;
    157     int width = _src->cols, height = _src->rows;
    158     const float init_val = 1e6;
    159     float mask[3];
    160     CvMat* temp;
    161     int ofs[16];
    162     float delta[16];
    163     int tstep, count;
    164 
    165     assert( mask_size == 3 || mask_size == 5 );
    166 
    167     if( dist_type == CV_DIST_USER )
    168         memcpy( mask, _mask, sizeof(mask) );
    169     else if( dist_type == CV_DIST_C )
    170     {
    171         mask_size = 3;
    172         mask[0] = mask[1] = 1.f;
    173     }
    174     else if( dist_type == CV_DIST_L1 )
    175     {
    176         mask_size = 3;
    177         mask[0] = 1.f;
    178         mask[1] = 2.f;
    179     }
    180     else if( mask_size == 3 )
    181     {
    182         mask[0] = 0.955f;
    183         mask[1] = 1.3693f;
    184     }
    185     else
    186     {
    187         mask[0] = 1.0f;
    188         mask[1] = 1.4f;
    189         mask[2] = 2.1969f;
    190     }
    191 
    192     temp = cvCreateMat( height + mask_size-1, width + mask_size-1, CV_32F );
    193     tstep = temp->step / sizeof(float);
    194 
    195     if( mask_size == 3 )
    196     {
    197         count = 4;
    198         ofs[0] = -1; delta[0] = mask[0];
    199         ofs[1] = -tstep-1; delta[1] = mask[1];
    200         ofs[2] = -tstep; delta[2] = mask[0];
    201         ofs[3] = -tstep+1; delta[3] = mask[1];
    202     }
    203     else
    204     {
    205         count = 8;
    206         ofs[0] = -1; delta[0] = mask[0];
    207         ofs[1] = -tstep-2; delta[1] = mask[2];
    208         ofs[2] = -tstep-1; delta[2] = mask[1];
    209         ofs[3] = -tstep; delta[3] = mask[0];
    210         ofs[4] = -tstep+1; delta[4] = mask[1];
    211         ofs[5] = -tstep+2; delta[5] = mask[2];
    212         ofs[6] = -tstep*2-1; delta[6] = mask[2];
    213         ofs[7] = -tstep*2+1; delta[7] = mask[2];
    214     }
    215 
    216     for( i = 0; i < mask_size/2; i++ )
    217     {
    218         float* t0 = (float*)(temp->data.ptr + i*temp->step);
    219         float* t1 = (float*)(temp->data.ptr + (temp->rows - i - 1)*temp->step);
    220 
    221         for( j = 0; j < width + mask_size - 1; j++ )
    222             t0[j] = t1[j] = init_val;
    223     }
    224 
    225     for( i = 0; i < height; i++ )
    226     {
    227         uchar* s = _src->data.ptr + i*_src->step;
    228         float* tmp = (float*)(temp->data.ptr + temp->step*(i + (mask_size/2))) + (mask_size/2);
    229 
    230         for( j = 0; j < mask_size/2; j++ )
    231             tmp[-j-1] = tmp[j + width] = init_val;
    232 
    233         for( j = 0; j < width; j++ )
    234         {
    235             if( s[j] == 0 )
    236                 tmp[j] = 0;
    237             else
    238             {
    239                 float min_dist = init_val;
    240                 for( k = 0; k < count; k++ )
    241                 {
    242                     float t = tmp[j+ofs[k]] + delta[k];
    243                     if( min_dist > t )
    244                         min_dist = t;
    245                 }
    246                 tmp[j] = min_dist;
    247             }
    248         }
    249     }
    250 
    251     for( i = height - 1; i >= 0; i-- )
    252     {
    253         float* d = (float*)(_dst->data.ptr + i*_dst->step);
    254         float* tmp = (float*)(temp->data.ptr + temp->step*(i + (mask_size/2))) + (mask_size/2);
    255 
    256         for( j = width - 1; j >= 0; j-- )
    257         {
    258             float min_dist = tmp[j];
    259             if( min_dist > mask[0] )
    260             {
    261                 for( k = 0; k < count; k++ )
    262                 {
    263                     float t = tmp[j-ofs[k]] + delta[k];
    264                     if( min_dist > t )
    265                         min_dist = t;
    266                 }
    267                 tmp[j] = min_dist;
    268             }
    269             d[j] = min_dist;
    270         }
    271     }
    272 
    273     cvReleaseMat( &temp );
    274 }
    275 
    276 
    277 void CV_DisTransTest::prepare_to_validation( int /*test_case_idx*/ )
    278 {
    279     CvMat _input = test_mat[INPUT][0], _output = test_mat[REF_OUTPUT][0];
    280 
    281     cvTsDistTransform( &_input, &_output, dist_type, mask_size, mask, 0 );
    282 }
    283 
    284 
    285 TEST(Imgproc_DistanceTransform, accuracy) { CV_DisTransTest test; test.safe_run(); }
    286