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