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