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