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 #include "precomp.hpp"
42 
43 /****************************************************************************************\
44 *                                  Chain Approximation                                   *
45 \****************************************************************************************/
46 
47 typedef struct _CvPtInfo
48 {
49     CvPoint pt;
50     int k;                      /* support region */
51     int s;                      /* curvature value */
52     struct _CvPtInfo *next;
53 }
54 _CvPtInfo;
55 
56 
57 /* curvature: 0 - 1-curvature, 1 - k-cosine curvature. */
icvApproximateChainTC89(CvChain * chain,int header_size,CvMemStorage * storage,int method)58 CvSeq* icvApproximateChainTC89( CvChain* chain, int header_size,
59                                 CvMemStorage* storage, int method )
60 {
61     static const int abs_diff[] = { 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1 };
62 
63     cv::AutoBuffer<_CvPtInfo> buf(chain->total + 8);
64 
65     _CvPtInfo       temp;
66     _CvPtInfo       *array = buf, *first = 0, *current = 0, *prev_current = 0;
67     int             i, j, i1, i2, s, len;
68     int             count = chain->total;
69 
70     CvChainPtReader reader;
71     CvSeqWriter     writer;
72     CvPoint         pt = chain->origin;
73 
74     CV_Assert( CV_IS_SEQ_CHAIN_CONTOUR( chain ));
75     CV_Assert( header_size >= (int)sizeof(CvContour) );
76 
77     cvStartWriteSeq( (chain->flags & ~CV_SEQ_ELTYPE_MASK) | CV_SEQ_ELTYPE_POINT,
78                      header_size, sizeof( CvPoint ), storage, &writer );
79 
80     if( chain->total == 0 )
81     {
82         CV_WRITE_SEQ_ELEM( pt, writer );
83         return cvEndWriteSeq( &writer );
84     }
85 
86     cvStartReadChainPoints( chain, &reader );
87 
88     temp.next = 0;
89     current = &temp;
90 
91     /* Pass 0.
92        Restores all the digital curve points from the chain code.
93        Removes the points (from the resultant polygon)
94        that have zero 1-curvature */
95     for( i = 0; i < count; i++ )
96     {
97         int prev_code = *reader.prev_elem;
98 
99         reader.prev_elem = reader.ptr;
100         CV_READ_CHAIN_POINT( pt, reader );
101 
102         /* calc 1-curvature */
103         s = abs_diff[reader.code - prev_code + 7];
104 
105         if( method <= CV_CHAIN_APPROX_SIMPLE )
106         {
107             if( method == CV_CHAIN_APPROX_NONE || s != 0 )
108             {
109                 CV_WRITE_SEQ_ELEM( pt, writer );
110             }
111         }
112         else
113         {
114             if( s != 0 )
115                 current = current->next = array + i;
116             array[i].s = s;
117             array[i].pt = pt;
118         }
119     }
120 
121     //assert( pt.x == chain->origin.x && pt.y == chain->origin.y );
122 
123     if( method <= CV_CHAIN_APPROX_SIMPLE )
124         return cvEndWriteSeq( &writer );
125 
126     current->next = 0;
127 
128     len = i;
129     current = temp.next;
130 
131     assert( current );
132 
133     /* Pass 1.
134        Determines support region for all the remained points */
135     do
136     {
137         CvPoint pt0;
138         int k, l = 0, d_num = 0;
139 
140         i = (int)(current - array);
141         pt0 = array[i].pt;
142 
143         /* determine support region */
144         for( k = 1;; k++ )
145         {
146             int lk, dk_num;
147             int dx, dy;
148             Cv32suf d;
149 
150             assert( k <= len );
151 
152             /* calc indices */
153             i1 = i - k;
154             i1 += i1 < 0 ? len : 0;
155             i2 = i + k;
156             i2 -= i2 >= len ? len : 0;
157 
158             dx = array[i2].pt.x - array[i1].pt.x;
159             dy = array[i2].pt.y - array[i1].pt.y;
160 
161             /* distance between p_(i - k) and p_(i + k) */
162             lk = dx * dx + dy * dy;
163 
164             /* distance between p_i and the line (p_(i-k), p_(i+k)) */
165             dk_num = (pt0.x - array[i1].pt.x) * dy - (pt0.y - array[i1].pt.y) * dx;
166             d.f = (float) (((double) d_num) * lk - ((double) dk_num) * l);
167 
168             if( k > 1 && (l >= lk || ((d_num > 0 && d.i <= 0) || (d_num < 0 && d.i >= 0))))
169                 break;
170 
171             d_num = dk_num;
172             l = lk;
173         }
174 
175         current->k = --k;
176 
177         /* determine cosine curvature if it should be used */
178         if( method == CV_CHAIN_APPROX_TC89_KCOS )
179         {
180             /* calc k-cosine curvature */
181             for( j = k, s = 0; j > 0; j-- )
182             {
183                 double temp_num;
184                 int dx1, dy1, dx2, dy2;
185                 Cv32suf sk;
186 
187                 i1 = i - j;
188                 i1 += i1 < 0 ? len : 0;
189                 i2 = i + j;
190                 i2 -= i2 >= len ? len : 0;
191 
192                 dx1 = array[i1].pt.x - pt0.x;
193                 dy1 = array[i1].pt.y - pt0.y;
194                 dx2 = array[i2].pt.x - pt0.x;
195                 dy2 = array[i2].pt.y - pt0.y;
196 
197                 if( (dx1 | dy1) == 0 || (dx2 | dy2) == 0 )
198                     break;
199 
200                 temp_num = dx1 * dx2 + dy1 * dy2;
201                 temp_num =
202                     (float) (temp_num /
203                              sqrt( ((double)dx1 * dx1 + (double)dy1 * dy1) *
204                                    ((double)dx2 * dx2 + (double)dy2 * dy2) ));
205                 sk.f = (float) (temp_num + 1.1);
206 
207                 assert( 0 <= sk.f && sk.f <= 2.2 );
208                 if( j < k && sk.i <= s )
209                     break;
210 
211                 s = sk.i;
212             }
213             current->s = s;
214         }
215         current = current->next;
216     }
217     while( current != 0 );
218 
219     prev_current = &temp;
220     current = temp.next;
221 
222     /* Pass 2.
223        Performs non-maxima suppression */
224     do
225     {
226         int k2 = current->k >> 1;
227 
228         s = current->s;
229         i = (int)(current - array);
230 
231         for( j = 1; j <= k2; j++ )
232         {
233             i2 = i - j;
234             i2 += i2 < 0 ? len : 0;
235 
236             if( array[i2].s > s )
237                 break;
238 
239             i2 = i + j;
240             i2 -= i2 >= len ? len : 0;
241 
242             if( array[i2].s > s )
243                 break;
244         }
245 
246         if( j <= k2 )           /* exclude point */
247         {
248             prev_current->next = current->next;
249             current->s = 0;     /* "clear" point */
250         }
251         else
252             prev_current = current;
253         current = current->next;
254     }
255     while( current != 0 );
256 
257     /* Pass 3.
258        Removes non-dominant points with 1-length support region */
259     current = temp.next;
260     assert( current );
261     prev_current = &temp;
262 
263     do
264     {
265         if( current->k == 1 )
266         {
267             s = current->s;
268             i = (int)(current - array);
269 
270             i1 = i - 1;
271             i1 += i1 < 0 ? len : 0;
272 
273             i2 = i + 1;
274             i2 -= i2 >= len ? len : 0;
275 
276             if( s <= array[i1].s || s <= array[i2].s )
277             {
278                 prev_current->next = current->next;
279                 current->s = 0;
280             }
281             else
282                 prev_current = current;
283         }
284         else
285             prev_current = current;
286         current = current->next;
287     }
288     while( current != 0 );
289 
290     if( method == CV_CHAIN_APPROX_TC89_KCOS )
291         goto copy_vect;
292 
293     /* Pass 4.
294        Cleans remained couples of points */
295     assert( temp.next );
296 
297     if( array[0].s != 0 && array[len - 1].s != 0 )      /* specific case */
298     {
299         for( i1 = 1; i1 < len && array[i1].s != 0; i1++ )
300         {
301             array[i1 - 1].s = 0;
302         }
303         if( i1 == len )
304             goto copy_vect;     /* all points survived */
305         i1--;
306 
307         for( i2 = len - 2; i2 > 0 && array[i2].s != 0; i2-- )
308         {
309             array[i2].next = 0;
310             array[i2 + 1].s = 0;
311         }
312         i2++;
313 
314         if( i1 == 0 && i2 == len - 1 )  /* only two points */
315         {
316             i1 = (int)(array[0].next - array);
317             array[len] = array[0];      /* move to the end */
318             array[len].next = 0;
319             array[len - 1].next = array + len;
320         }
321         temp.next = array + i1;
322     }
323 
324     current = temp.next;
325     first = prev_current = &temp;
326     count = 1;
327 
328     /* do last pass */
329     do
330     {
331         if( current->next == 0 || current->next - current != 1 )
332         {
333             if( count >= 2 )
334             {
335                 if( count == 2 )
336                 {
337                     int s1 = prev_current->s;
338                     int s2 = current->s;
339 
340                     if( s1 > s2 || (s1 == s2 && prev_current->k <= current->k) )
341                         /* remove second */
342                         prev_current->next = current->next;
343                     else
344                         /* remove first */
345                         first->next = current;
346                 }
347                 else
348                     first->next->next = current;
349             }
350             first = current;
351             count = 1;
352         }
353         else
354             count++;
355         prev_current = current;
356         current = current->next;
357     }
358     while( current != 0 );
359 
360 copy_vect:
361 
362     // gather points
363     current = temp.next;
364     assert( current );
365 
366     do
367     {
368         CV_WRITE_SEQ_ELEM( current->pt, writer );
369         current = current->next;
370     }
371     while( current != 0 );
372 
373     return cvEndWriteSeq( &writer );
374 }
375 
376 
377 /*Applies some approximation algorithm to chain-coded contour(s) and
378   converts it/them to polygonal representation */
379 CV_IMPL CvSeq*
cvApproxChains(CvSeq * src_seq,CvMemStorage * storage,int method,double,int minimal_perimeter,int recursive)380 cvApproxChains( CvSeq*              src_seq,
381                 CvMemStorage*       storage,
382                 int                 method,
383                 double              /*parameter*/,
384                 int                 minimal_perimeter,
385                 int                 recursive )
386 {
387     CvSeq *prev_contour = 0, *parent = 0;
388     CvSeq *dst_seq = 0;
389 
390     if( !src_seq || !storage )
391         CV_Error( CV_StsNullPtr, "" );
392     if( method > CV_CHAIN_APPROX_TC89_KCOS || method <= 0 || minimal_perimeter < 0 )
393         CV_Error( CV_StsOutOfRange, "" );
394 
395     while( src_seq != 0 )
396     {
397         int len = src_seq->total;
398 
399         if( len >= minimal_perimeter )
400         {
401             CvSeq *contour = 0;
402 
403             switch( method )
404             {
405             case CV_CHAIN_APPROX_NONE:
406             case CV_CHAIN_APPROX_SIMPLE:
407             case CV_CHAIN_APPROX_TC89_L1:
408             case CV_CHAIN_APPROX_TC89_KCOS:
409                 contour = icvApproximateChainTC89( (CvChain *) src_seq, sizeof( CvContour ), storage, method );
410                 break;
411             default:
412                 CV_Error( CV_StsOutOfRange, "" );
413             }
414 
415             if( contour->total > 0 )
416             {
417                 cvBoundingRect( contour, 1 );
418 
419                 contour->v_prev = parent;
420                 contour->h_prev = prev_contour;
421 
422                 if( prev_contour )
423                     prev_contour->h_next = contour;
424                 else if( parent )
425                     parent->v_next = contour;
426                 prev_contour = contour;
427                 if( !dst_seq )
428                     dst_seq = prev_contour;
429             }
430             else                /* if resultant contour has zero length, skip it */
431             {
432                 len = -1;
433             }
434         }
435 
436         if( !recursive )
437             break;
438 
439         if( src_seq->v_next && len >= minimal_perimeter )
440         {
441             assert( prev_contour != 0 );
442             parent = prev_contour;
443             prev_contour = 0;
444             src_seq = src_seq->v_next;
445         }
446         else
447         {
448             while( src_seq->h_next == 0 )
449             {
450                 src_seq = src_seq->v_prev;
451                 if( src_seq == 0 )
452                     break;
453                 prev_contour = parent;
454                 if( parent )
455                     parent = parent->v_prev;
456             }
457             if( src_seq )
458                 src_seq = src_seq->h_next;
459         }
460     }
461 
462     return dst_seq;
463 }
464 
465 
466 /****************************************************************************************\
467 *                               Polygonal Approximation                                  *
468 \****************************************************************************************/
469 
470 /* Ramer-Douglas-Peucker algorithm for polygon simplification */
471 
472 namespace cv
473 {
474 
475 template<typename T> static int
approxPolyDP_(const Point_<T> * src_contour,int count0,Point_<T> * dst_contour,bool is_closed0,double eps,AutoBuffer<Range> * _stack)476 approxPolyDP_( const Point_<T>* src_contour, int count0, Point_<T>* dst_contour,
477               bool is_closed0, double eps, AutoBuffer<Range>* _stack )
478 {
479     #define PUSH_SLICE(slice) \
480         if( top >= stacksz ) \
481         { \
482             _stack->resize(stacksz*3/2); \
483             stack = *_stack; \
484             stacksz = _stack->size(); \
485         } \
486         stack[top++] = slice
487 
488     #define READ_PT(pt, pos) \
489         pt = src_contour[pos]; \
490         if( ++pos >= count ) pos = 0
491 
492     #define READ_DST_PT(pt, pos) \
493         pt = dst_contour[pos]; \
494         if( ++pos >= count ) pos = 0
495 
496     #define WRITE_PT(pt) \
497         dst_contour[new_count++] = pt
498 
499     typedef cv::Point_<T> PT;
500     int             init_iters = 3;
501     Range           slice(0, 0), right_slice(0, 0);
502     PT              start_pt((T)-1000000, (T)-1000000), end_pt(0, 0), pt(0,0);
503     int             i = 0, j, pos = 0, wpos, count = count0, new_count=0;
504     int             is_closed = is_closed0;
505     bool            le_eps = false;
506     size_t top = 0, stacksz = _stack->size();
507     Range*          stack = *_stack;
508 
509     if( count == 0  )
510         return 0;
511 
512     eps *= eps;
513 
514     if( !is_closed )
515     {
516         right_slice.start = count;
517         end_pt = src_contour[0];
518         start_pt = src_contour[count-1];
519 
520         if( start_pt.x != end_pt.x || start_pt.y != end_pt.y )
521         {
522             slice.start = 0;
523             slice.end = count - 1;
524             PUSH_SLICE(slice);
525         }
526         else
527         {
528             is_closed = 1;
529             init_iters = 1;
530         }
531     }
532 
533     if( is_closed )
534     {
535         // 1. Find approximately two farthest points of the contour
536         right_slice.start = 0;
537 
538         for( i = 0; i < init_iters; i++ )
539         {
540             double dist, max_dist = 0;
541             pos = (pos + right_slice.start) % count;
542             READ_PT(start_pt, pos);
543 
544             for( j = 1; j < count; j++ )
545             {
546                 double dx, dy;
547 
548                 READ_PT(pt, pos);
549                 dx = pt.x - start_pt.x;
550                 dy = pt.y - start_pt.y;
551 
552                 dist = dx * dx + dy * dy;
553 
554                 if( dist > max_dist )
555                 {
556                     max_dist = dist;
557                     right_slice.start = j;
558                 }
559             }
560 
561             le_eps = max_dist <= eps;
562         }
563 
564         // 2. initialize the stack
565         if( !le_eps )
566         {
567             right_slice.end = slice.start = pos % count;
568             slice.end = right_slice.start = (right_slice.start + slice.start) % count;
569 
570             PUSH_SLICE(right_slice);
571             PUSH_SLICE(slice);
572         }
573         else
574             WRITE_PT(start_pt);
575     }
576 
577     // 3. run recursive process
578     while( top > 0 )
579     {
580         slice = stack[--top];
581         end_pt = src_contour[slice.end];
582         pos = slice.start;
583         READ_PT(start_pt, pos);
584 
585         if( pos != slice.end )
586         {
587             double dx, dy, dist, max_dist = 0;
588 
589             dx = end_pt.x - start_pt.x;
590             dy = end_pt.y - start_pt.y;
591 
592             assert( dx != 0 || dy != 0 );
593 
594             while( pos != slice.end )
595             {
596                 READ_PT(pt, pos);
597                 dist = fabs((pt.y - start_pt.y) * dx - (pt.x - start_pt.x) * dy);
598 
599                 if( dist > max_dist )
600                 {
601                     max_dist = dist;
602                     right_slice.start = (pos+count-1)%count;
603                 }
604             }
605 
606             le_eps = max_dist * max_dist <= eps * (dx * dx + dy * dy);
607         }
608         else
609         {
610             le_eps = true;
611             // read starting point
612             start_pt = src_contour[slice.start];
613         }
614 
615         if( le_eps )
616         {
617             WRITE_PT(start_pt);
618         }
619         else
620         {
621             right_slice.end = slice.end;
622             slice.end = right_slice.start;
623             PUSH_SLICE(right_slice);
624             PUSH_SLICE(slice);
625         }
626     }
627 
628     if( !is_closed )
629         WRITE_PT( src_contour[count-1] );
630 
631     // last stage: do final clean-up of the approximated contour -
632     // remove extra points on the [almost] stright lines.
633     is_closed = is_closed0;
634     count = new_count;
635     pos = is_closed ? count - 1 : 0;
636     READ_DST_PT(start_pt, pos);
637     wpos = pos;
638     READ_DST_PT(pt, pos);
639 
640     for( i = !is_closed; i < count - !is_closed && new_count > 2; i++ )
641     {
642         double dx, dy, dist, successive_inner_product;
643         READ_DST_PT( end_pt, pos );
644 
645         dx = end_pt.x - start_pt.x;
646         dy = end_pt.y - start_pt.y;
647         dist = fabs((pt.x - start_pt.x)*dy - (pt.y - start_pt.y)*dx);
648         successive_inner_product = (pt.x - start_pt.x) * (end_pt.x - pt.x) +
649         (pt.y - start_pt.y) * (end_pt.y - pt.y);
650 
651         if( dist * dist <= 0.5*eps*(dx*dx + dy*dy) && dx != 0 && dy != 0 &&
652            successive_inner_product >= 0 )
653         {
654             new_count--;
655             dst_contour[wpos] = start_pt = end_pt;
656             if(++wpos >= count) wpos = 0;
657             READ_DST_PT(pt, pos);
658             i++;
659             continue;
660         }
661         dst_contour[wpos] = start_pt = pt;
662         if(++wpos >= count) wpos = 0;
663         pt = end_pt;
664     }
665 
666     if( !is_closed )
667         dst_contour[wpos] = pt;
668 
669     return new_count;
670 }
671 
672 }
673 
approxPolyDP(InputArray _curve,OutputArray _approxCurve,double epsilon,bool closed)674 void cv::approxPolyDP( InputArray _curve, OutputArray _approxCurve,
675                       double epsilon, bool closed )
676 {
677     Mat curve = _curve.getMat();
678     int npoints = curve.checkVector(2), depth = curve.depth();
679     CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F));
680 
681     if( npoints == 0 )
682     {
683         _approxCurve.release();
684         return;
685     }
686 
687     AutoBuffer<Point> _buf(npoints);
688     AutoBuffer<Range> _stack(npoints);
689     Point* buf = _buf;
690     int nout = 0;
691 
692     if( depth == CV_32S )
693         nout = approxPolyDP_(curve.ptr<Point>(), npoints, buf, closed, epsilon, &_stack);
694     else if( depth == CV_32F )
695         nout = approxPolyDP_(curve.ptr<Point2f>(), npoints, (Point2f*)buf, closed, epsilon, &_stack);
696     else
697         CV_Error( CV_StsUnsupportedFormat, "" );
698 
699     Mat(nout, 1, CV_MAKETYPE(depth, 2), buf).copyTo(_approxCurve);
700 }
701 
702 
703 CV_IMPL CvSeq*
cvApproxPoly(const void * array,int header_size,CvMemStorage * storage,int method,double parameter,int parameter2)704 cvApproxPoly( const void* array, int header_size,
705              CvMemStorage* storage, int method,
706              double parameter, int parameter2 )
707 {
708     cv::AutoBuffer<cv::Point> _buf;
709     cv::AutoBuffer<cv::Range> stack(100);
710     CvSeq* dst_seq = 0;
711     CvSeq *prev_contour = 0, *parent = 0;
712     CvContour contour_header;
713     CvSeq* src_seq = 0;
714     CvSeqBlock block;
715     int recursive = 0;
716 
717     if( CV_IS_SEQ( array ))
718     {
719         src_seq = (CvSeq*)array;
720         if( !CV_IS_SEQ_POLYLINE( src_seq ))
721             CV_Error( CV_StsBadArg, "Unsupported sequence type" );
722 
723         recursive = parameter2;
724 
725         if( !storage )
726             storage = src_seq->storage;
727     }
728     else
729     {
730         src_seq = cvPointSeqFromMat(
731                                     CV_SEQ_KIND_CURVE | (parameter2 ? CV_SEQ_FLAG_CLOSED : 0),
732                                     array, &contour_header, &block );
733     }
734 
735     if( !storage )
736         CV_Error( CV_StsNullPtr, "NULL storage pointer " );
737 
738     if( header_size < 0 )
739         CV_Error( CV_StsOutOfRange, "header_size is negative. "
740                  "Pass 0 to make the destination header_size == input header_size" );
741 
742     if( header_size == 0 )
743         header_size = src_seq->header_size;
744 
745     if( !CV_IS_SEQ_POLYLINE( src_seq ))
746     {
747         if( CV_IS_SEQ_CHAIN( src_seq ))
748         {
749             CV_Error( CV_StsBadArg, "Input curves are not polygonal. "
750                      "Use cvApproxChains first" );
751         }
752         else
753         {
754             CV_Error( CV_StsBadArg, "Input curves have uknown type" );
755         }
756     }
757 
758     if( header_size == 0 )
759         header_size = src_seq->header_size;
760 
761     if( header_size < (int)sizeof(CvContour) )
762         CV_Error( CV_StsBadSize, "New header size must be non-less than sizeof(CvContour)" );
763 
764     if( method != CV_POLY_APPROX_DP )
765         CV_Error( CV_StsOutOfRange, "Unknown approximation method" );
766 
767     while( src_seq != 0 )
768     {
769         CvSeq *contour = 0;
770 
771         switch (method)
772         {
773         case CV_POLY_APPROX_DP:
774             if( parameter < 0 )
775                 CV_Error( CV_StsOutOfRange, "Accuracy must be non-negative" );
776 
777             CV_Assert( CV_SEQ_ELTYPE(src_seq) == CV_32SC2 ||
778                       CV_SEQ_ELTYPE(src_seq) == CV_32FC2 );
779 
780             {
781             int npoints = src_seq->total, nout = 0;
782             _buf.allocate(npoints*2);
783             cv::Point *src = _buf, *dst = src + npoints;
784             bool closed = CV_IS_SEQ_CLOSED(src_seq);
785 
786             if( src_seq->first->next == src_seq->first )
787                 src = (cv::Point*)src_seq->first->data;
788             else
789                 cvCvtSeqToArray(src_seq, src);
790 
791             if( CV_SEQ_ELTYPE(src_seq) == CV_32SC2 )
792                 nout = cv::approxPolyDP_(src, npoints, dst, closed, parameter, &stack);
793             else if( CV_SEQ_ELTYPE(src_seq) == CV_32FC2 )
794                 nout = cv::approxPolyDP_((cv::Point2f*)src, npoints,
795                                          (cv::Point2f*)dst, closed, parameter, &stack);
796             else
797                 CV_Error( CV_StsUnsupportedFormat, "" );
798 
799             contour = cvCreateSeq( src_seq->flags, header_size,
800                                   src_seq->elem_size, storage );
801             cvSeqPushMulti(contour, dst, nout);
802             }
803             break;
804         default:
805             CV_Error( CV_StsBadArg, "Invalid approximation method" );
806         }
807 
808         assert( contour );
809 
810         if( header_size >= (int)sizeof(CvContour))
811             cvBoundingRect( contour, 1 );
812 
813         contour->v_prev = parent;
814         contour->h_prev = prev_contour;
815 
816         if( prev_contour )
817             prev_contour->h_next = contour;
818         else if( parent )
819             parent->v_next = contour;
820         prev_contour = contour;
821         if( !dst_seq )
822             dst_seq = prev_contour;
823 
824         if( !recursive )
825             break;
826 
827         if( src_seq->v_next )
828         {
829             assert( prev_contour != 0 );
830             parent = prev_contour;
831             prev_contour = 0;
832             src_seq = src_seq->v_next;
833         }
834         else
835         {
836             while( src_seq->h_next == 0 )
837             {
838                 src_seq = src_seq->v_prev;
839                 if( src_seq == 0 )
840                     break;
841                 prev_contour = parent;
842                 if( parent )
843                     parent = parent->v_prev;
844             }
845             if( src_seq )
846                 src_seq = src_seq->h_next;
847         }
848     }
849 
850     return dst_seq;
851 }
852 
853 /* End of file. */
854