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 #include <limits.h>
     44 
     45 using namespace cv;
     46 using namespace std;
     47 
     48 //
     49 // TODO!!!:
     50 //  check_slice (and/or check) seem(s) to be broken, or this is a bug in function
     51 //  (or its inability to handle possible self-intersections in the generated contours).
     52 //
     53 //  At least, if // return TotalErrors;
     54 //  is uncommented in check_slice, the test fails easily.
     55 //  So, now (and it looks like since 0.9.6)
     56 //  we only check that the set of vertices of the approximated polygon is
     57 //  a subset of vertices of the original contour.
     58 //
     59 
     60 class CV_ApproxPolyTest : public cvtest::BaseTest
     61 {
     62 public:
     63     CV_ApproxPolyTest();
     64     ~CV_ApproxPolyTest();
     65     void clear();
     66     //int write_default_params(CvFileStorage* fs);
     67 
     68 protected:
     69     //int read_params( CvFileStorage* fs );
     70 
     71     int check_slice( CvPoint StartPt, CvPoint EndPt,
     72                      CvSeqReader* SrcReader, float Eps,
     73                      int* j, int Count );
     74     int check( CvSeq* SrcSeq, CvSeq* DstSeq, float Eps );
     75 
     76     bool get_contour( int /*type*/, CvSeq** Seq, int* d,
     77                       CvMemStorage* storage );
     78 
     79     void run(int);
     80 };
     81 
     82 
     83 CV_ApproxPolyTest::CV_ApproxPolyTest()
     84 {
     85 }
     86 
     87 
     88 CV_ApproxPolyTest::~CV_ApproxPolyTest()
     89 {
     90     clear();
     91 }
     92 
     93 
     94 void CV_ApproxPolyTest::clear()
     95 {
     96     cvtest::BaseTest::clear();
     97 }
     98 
     99 
    100 /*int CV_ApproxPolyTest::write_default_params( CvFileStorage* fs )
    101 {
    102     cvtest::BaseTest::write_default_params( fs );
    103     if( ts->get_testing_mode() != cvtest::TS::TIMING_MODE )
    104     {
    105         write_param( fs, "test_case_count", test_case_count );
    106     }
    107     return 0;
    108 }
    109 
    110 
    111 int CV_ApproxPolyTest::read_params( CvFileStorage* fs )
    112 {
    113     int code = cvtest::BaseTest::read_params( fs );
    114     if( code < 0 )
    115         return code;
    116 
    117     test_case_count = cvReadInt( find_param( fs, "test_case_count" ), test_case_count );
    118     min_log_size = cvtest::clipInt( min_log_size, 1, 10 );
    119     return 0;
    120 }*/
    121 
    122 
    123 bool CV_ApproxPolyTest::get_contour( int /*type*/, CvSeq** Seq, int* d,
    124                                      CvMemStorage* storage )
    125 {
    126     RNG& rng = ts->get_rng();
    127     int max_x = INT_MIN, max_y = INT_MIN, min_x = INT_MAX, min_y = INT_MAX;
    128     int i;
    129     CvSeq* seq;
    130     int total = cvtest::randInt(rng) % 1000 + 1;
    131     CvPoint center;
    132     int radius, angle;
    133     double deg_to_rad = CV_PI/180.;
    134     CvPoint pt;
    135 
    136     center.x = cvtest::randInt( rng ) % 1000;
    137     center.y = cvtest::randInt( rng ) % 1000;
    138     radius = cvtest::randInt( rng ) % 1000;
    139     angle = cvtest::randInt( rng ) % 360;
    140 
    141     seq = cvCreateSeq( CV_SEQ_POLYGON, sizeof(CvContour), sizeof(CvPoint), storage );
    142 
    143     for( i = 0; i < total; i++ )
    144     {
    145         int d_radius = cvtest::randInt( rng ) % 10 - 5;
    146         int d_angle = 360/total;//cvtest::randInt( rng ) % 10 - 5;
    147         pt.x = cvRound( center.x + radius*cos(angle*deg_to_rad));
    148         pt.y = cvRound( center.x - radius*sin(angle*deg_to_rad));
    149         radius += d_radius;
    150         angle += d_angle;
    151         cvSeqPush( seq, &pt );
    152 
    153         max_x = MAX( max_x, pt.x );
    154         max_y = MAX( max_y, pt.y );
    155 
    156         min_x = MIN( min_x, pt.x );
    157         min_y = MIN( min_y, pt.y );
    158     }
    159 
    160     *d = (max_x - min_x)*(max_x - min_x) + (max_y - min_y)*(max_y - min_y);
    161     *Seq = seq;
    162     return true;
    163 }
    164 
    165 
    166 int CV_ApproxPolyTest::check_slice( CvPoint StartPt, CvPoint EndPt,
    167                                    CvSeqReader* SrcReader, float Eps,
    168                                    int* _j, int Count )
    169 {
    170     ///////////
    171     CvPoint Pt;
    172     ///////////
    173     bool flag;
    174     double dy,dx;
    175     double A,B,C;
    176     double Sq;
    177     double sin_a = 0;
    178     double cos_a = 0;
    179     double d     = 0;
    180     double dist;
    181     ///////////
    182     int j, TotalErrors = 0;
    183 
    184     ////////////////////////////////
    185     if( SrcReader == NULL )
    186     {
    187         assert( false );
    188         return 0;
    189     }
    190 
    191     ///////// init line ////////////
    192     flag = true;
    193 
    194     dx = (double)StartPt.x - (double)EndPt.x;
    195     dy = (double)StartPt.y - (double)EndPt.y;
    196 
    197     if( ( dx == 0 ) && ( dy == 0 ) ) flag = false;
    198     else
    199     {
    200         A = -dy;
    201         B = dx;
    202         C = dy * (double)StartPt.x - dx * (double)StartPt.y;
    203         Sq = sqrt( A*A + B*B );
    204 
    205         sin_a = B/Sq;
    206         cos_a = A/Sq;
    207         d = C/Sq;
    208     }
    209 
    210     /////// find start point and check distance ////////
    211     for( j = *_j; j < Count; j++ )
    212     {
    213         CV_READ_SEQ_ELEM( Pt, *SrcReader );
    214         if( StartPt.x == Pt.x && StartPt.y == Pt.y ) break;
    215         else
    216         {
    217             if( flag ) dist = sin_a * Pt.y + cos_a * Pt.x - d;
    218             else dist = sqrt( (double)(EndPt.y - Pt.y)*(EndPt.y - Pt.y) + (EndPt.x - Pt.x)*(EndPt.x - Pt.x) );
    219             if( dist > Eps ) TotalErrors++;
    220         }
    221     }
    222 
    223     *_j = j;
    224 
    225     //return TotalErrors;
    226     return 0;
    227 }
    228 
    229 
    230 int CV_ApproxPolyTest::check( CvSeq* SrcSeq, CvSeq* DstSeq, float Eps )
    231 {
    232     //////////
    233     CvSeqReader  DstReader;
    234     CvSeqReader  SrcReader;
    235     CvPoint StartPt, EndPt;
    236     ///////////
    237     int TotalErrors = 0;
    238     ///////////
    239     int Count;
    240     int i,j;
    241 
    242     assert( SrcSeq && DstSeq );
    243 
    244     ////////// init ////////////////////
    245     Count = SrcSeq->total;
    246 
    247     cvStartReadSeq( DstSeq, &DstReader, 0 );
    248     cvStartReadSeq( SrcSeq, &SrcReader, 0 );
    249 
    250     CV_READ_SEQ_ELEM( StartPt, DstReader );
    251     for( i = 0 ; i < Count ;  )
    252     {
    253         CV_READ_SEQ_ELEM( EndPt, SrcReader );
    254         i++;
    255         if( StartPt.x == EndPt.x && StartPt.y == EndPt.y ) break;
    256     }
    257 
    258     ///////// start ////////////////
    259     for( i = 1, j = 0 ; i <= DstSeq->total ;  )
    260     {
    261         ///////// read slice ////////////
    262         EndPt.x = StartPt.x;
    263         EndPt.y = StartPt.y;
    264         CV_READ_SEQ_ELEM( StartPt, DstReader );
    265         i++;
    266 
    267         TotalErrors += check_slice( StartPt, EndPt, &SrcReader, Eps, &j, Count );
    268 
    269         if( j > Count )
    270         {
    271             TotalErrors++;
    272             return TotalErrors;
    273         } //if( !flag )
    274 
    275     } // for( int i = 0 ; i < DstSeq->total ; i++ )
    276 
    277     return TotalErrors;
    278 }
    279 
    280 
    281 //extern CvTestContourGenerator cvTsTestContours[];
    282 
    283 void CV_ApproxPolyTest::run( int /*start_from*/ )
    284 {
    285     int code = cvtest::TS::OK;
    286     CvMemStorage* storage = 0;
    287     ////////////// Variables ////////////////
    288     int IntervalsCount = 10;
    289     ///////////
    290     //CvTestContourGenerator Cont;
    291     CvSeq*  SrcSeq = NULL;
    292     CvSeq*  DstSeq;
    293     int     iDiam;
    294     float   dDiam, Eps, EpsStep;
    295 
    296     for( int i = 0; i < 30; i++ )
    297     {
    298         CvMemStoragePos pos;
    299 
    300         ts->update_context( this, i, false );
    301 
    302         ///////////////////// init contour /////////
    303         dDiam = 0;
    304         while( sqrt(dDiam) / IntervalsCount == 0 )
    305         {
    306             if( storage != 0 )
    307                 cvReleaseMemStorage(&storage);
    308 
    309             storage = cvCreateMemStorage( 0 );
    310             if( get_contour( 0, &SrcSeq, &iDiam, storage ) )
    311                 dDiam = (float)iDiam;
    312         }
    313         dDiam = (float)sqrt( dDiam );
    314 
    315         storage = SrcSeq->storage;
    316 
    317         ////////////////// test /////////////
    318         EpsStep = dDiam / IntervalsCount ;
    319         for( Eps = EpsStep ; Eps < dDiam ; Eps += EpsStep )
    320         {
    321             cvSaveMemStoragePos( storage, &pos );
    322 
    323             ////////// call function ////////////
    324             DstSeq = cvApproxPoly( SrcSeq, SrcSeq->header_size, storage,
    325                 CV_POLY_APPROX_DP, Eps );
    326 
    327             if( DstSeq == NULL )
    328             {
    329                 ts->printf( cvtest::TS::LOG,
    330                     "cvApproxPoly returned NULL for contour #%d, espilon = %g\n", i, Eps );
    331                 code = cvtest::TS::FAIL_INVALID_OUTPUT;
    332                 goto _exit_;
    333             } // if( DstSeq == NULL )
    334 
    335             code = check( SrcSeq, DstSeq, Eps );
    336             if( code != 0 )
    337             {
    338                 ts->printf( cvtest::TS::LOG,
    339                     "Incorrect result for the contour #%d approximated with epsilon=%g\n", i, Eps );
    340                 code = cvtest::TS::FAIL_BAD_ACCURACY;
    341                 goto _exit_;
    342             }
    343 
    344             cvRestoreMemStoragePos( storage, &pos );
    345         } // for( Eps = EpsStep ; Eps <= Diam ; Eps += EpsStep )
    346 
    347         ///////////// free memory  ///////////////////
    348         cvReleaseMemStorage(&storage);
    349     } // for( int i = 0; NULL != ( Cont = Contours[i] ) ; i++ )
    350 
    351 _exit_:
    352     cvReleaseMemStorage(&storage);
    353 
    354     if( code < 0 )
    355         ts->set_failed_test_info( code );
    356 }
    357 
    358 TEST(Imgproc_ApproxPoly, accuracy) { CV_ApproxPolyTest test; test.safe_run(); }
    359