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
CV_ApproxPolyTest()83 CV_ApproxPolyTest::CV_ApproxPolyTest()
84 {
85 }
86
87
~CV_ApproxPolyTest()88 CV_ApproxPolyTest::~CV_ApproxPolyTest()
89 {
90 clear();
91 }
92
93
clear()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
get_contour(int,CvSeq ** Seq,int * d,CvMemStorage * storage)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
check_slice(CvPoint StartPt,CvPoint EndPt,CvSeqReader * SrcReader,float Eps,int * _j,int Count)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
check(CvSeq * SrcSeq,CvSeq * DstSeq,float Eps)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
run(int)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
TEST(Imgproc_ApproxPoly,accuracy)358 TEST(Imgproc_ApproxPoly, accuracy) { CV_ApproxPolyTest test; test.safe_run(); }
359