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