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 47typedef 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. */ 58CvSeq* 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 360copy_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 */ 379CV_IMPL CvSeq* 380cvApproxChains( 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 472namespace cv 473{ 474 475template<typename T> static int 476approxPolyDP_( 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 674void 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 703CV_IMPL CvSeq* 704cvApproxPoly( 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