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