5b504f95478cf74ca7139150eeb895fab5243d9d
[opencv] / src / cv / cvcontours.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 #include "_cv.h"
42
43 /* initializes 8-element array for fast access to 3x3 neighborhood of a pixel */
44 #define  CV_INIT_3X3_DELTAS( deltas, step, nch )            \
45     ((deltas)[0] =  (nch),  (deltas)[1] = -(step) + (nch),  \
46      (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch),  \
47      (deltas)[4] = -(nch),  (deltas)[5] =  (step) - (nch),  \
48      (deltas)[6] =  (step), (deltas)[7] =  (step) + (nch))
49
50 static const CvPoint icvCodeDeltas[8] =
51     { {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1} };
52
53 CV_IMPL void
54 cvStartReadChainPoints( CvChain * chain, CvChainPtReader * reader )
55 {
56     int i;
57
58     CV_FUNCNAME( "cvStartReadChainPoints" );
59
60     __BEGIN__;
61
62     if( !chain || !reader )
63         CV_ERROR( CV_StsNullPtr, "" );
64
65     if( chain->elem_size != 1 || chain->header_size < (int)sizeof(CvChain))
66         CV_ERROR( CV_StsBadSize, "" );
67
68     cvStartReadSeq( (CvSeq *) chain, (CvSeqReader *) reader, 0 );
69     CV_CHECK();
70
71     reader->pt = chain->origin;
72
73     for( i = 0; i < 8; i++ )
74     {
75         reader->deltas[i][0] = (schar) icvCodeDeltas[i].x;
76         reader->deltas[i][1] = (schar) icvCodeDeltas[i].y;
77     }
78
79     __END__;
80 }
81
82
83 /* retrieves next point of the chain curve and updates reader */
84 CV_IMPL CvPoint
85 cvReadChainPoint( CvChainPtReader * reader )
86 {
87     schar *ptr;
88     int code;
89     CvPoint pt = { 0, 0 };
90
91     CV_FUNCNAME( "cvReadChainPoint" );
92
93     __BEGIN__;
94
95     if( !reader )
96         CV_ERROR( CV_StsNullPtr, "" );
97
98     pt = reader->pt;
99
100     ptr = reader->ptr;
101     if( ptr )
102     {
103         code = *ptr++;
104
105         if( ptr >= reader->block_max )
106         {
107             cvChangeSeqBlock( (CvSeqReader *) reader, 1 );
108             ptr = reader->ptr;
109         }
110
111         reader->ptr = ptr;
112         reader->code = (schar)code;
113         assert( (code & ~7) == 0 );
114         reader->pt.x = pt.x + icvCodeDeltas[code].x;
115         reader->pt.y = pt.y + icvCodeDeltas[code].y;
116     }
117
118     __END__;
119
120     return pt;
121 }
122
123
124 /****************************************************************************************\
125 *                         Raster->Chain Tree (Suzuki algorithms)                         *
126 \****************************************************************************************/
127
128 typedef struct _CvContourInfo
129 {
130     int flags;
131     struct _CvContourInfo *next;        /* next contour with the same mark value */
132     struct _CvContourInfo *parent;      /* information about parent contour */
133     CvSeq *contour;             /* corresponding contour (may be 0, if rejected) */
134     CvRect rect;                /* bounding rectangle */
135     CvPoint origin;             /* origin point (where the contour was traced from) */
136     int is_hole;                /* hole flag */
137 }
138 _CvContourInfo;
139
140
141 /*
142   Structure that is used for sequental retrieving contours from the image.
143   It supports both hierarchical and plane variants of Suzuki algorithm.
144 */
145 typedef struct _CvContourScanner
146 {
147     CvMemStorage *storage1;     /* contains fetched contours */
148     CvMemStorage *storage2;     /* contains approximated contours
149                                    (!=storage1 if approx_method2 != approx_method1) */
150     CvMemStorage *cinfo_storage;        /* contains _CvContourInfo nodes */
151     CvSet *cinfo_set;           /* set of _CvContourInfo nodes */
152     CvMemStoragePos initial_pos;        /* starting storage pos */
153     CvMemStoragePos backup_pos; /* beginning of the latest approx. contour */
154     CvMemStoragePos backup_pos2;        /* ending of the latest approx. contour */
155     schar *img0;                /* image origin */
156     schar *img;                 /* current image row */
157     int img_step;               /* image step */
158     CvSize img_size;            /* ROI size */
159     CvPoint offset;             /* ROI offset: coordinates, added to each contour point */
160     CvPoint pt;                 /* current scanner position */
161     CvPoint lnbd;               /* position of the last met contour */
162     int nbd;                    /* current mark val */
163     _CvContourInfo *l_cinfo;    /* information about latest approx. contour */
164     _CvContourInfo cinfo_temp;  /* temporary var which is used in simple modes */
165     _CvContourInfo frame_info;  /* information about frame */
166     CvSeq frame;                /* frame itself */
167     int approx_method1;         /* approx method when tracing */
168     int approx_method2;         /* final approx method */
169     int mode;                   /* contour scanning mode:
170                                    0 - external only
171                                    1 - all the contours w/o any hierarchy
172                                    2 - connected components (i.e. two-level structure -
173                                    external contours and holes) */
174     int subst_flag;
175     int seq_type1;              /* type of fetched contours */
176     int header_size1;           /* hdr size of fetched contours */
177     int elem_size1;             /* elem size of fetched contours */
178     int seq_type2;              /*                                       */
179     int header_size2;           /*        the same for approx. contours  */
180     int elem_size2;             /*                                       */
181     _CvContourInfo *cinfo_table[126];
182 }
183 _CvContourScanner;
184
185 #define _CV_FIND_CONTOURS_FLAGS_EXTERNAL_ONLY    1
186 #define _CV_FIND_CONTOURS_FLAGS_HIERARCHIC       2
187
188 /*
189    Initializes scanner structure.
190    Prepare image for scanning ( clear borders and convert all pixels to 0-1.
191 */
192 CV_IMPL CvContourScanner
193 cvStartFindContours( void* _img, CvMemStorage* storage,
194                      int  header_size, int mode,
195                      int  method, CvPoint offset )
196 {
197     int y;
198     int step;
199     CvSize size;
200     uchar *img = 0;
201     CvContourScanner scanner = 0;
202     CvMat stub, *mat = (CvMat*)_img;
203
204     CV_FUNCNAME( "cvStartFindContours" );
205
206     __BEGIN__;
207
208     if( !storage )
209         CV_ERROR( CV_StsNullPtr, "" );
210
211     CV_CALL( mat = cvGetMat( mat, &stub ));
212
213     if( !CV_IS_MASK_ARR( mat ))
214         CV_ERROR( CV_StsUnsupportedFormat, "[Start]FindContours support only 8uC1 images" );
215
216     size = cvSize( mat->width, mat->height );
217     step = mat->step;
218     img = (uchar*)(mat->data.ptr);
219
220     if( method < 0 || method > CV_CHAIN_APPROX_TC89_KCOS )
221         CV_ERROR( CV_StsOutOfRange, "" );
222
223     if( header_size < (int) (method == CV_CHAIN_CODE ? sizeof( CvChain ) : sizeof( CvContour )))
224         CV_ERROR( CV_StsBadSize, "" );
225
226     scanner = (CvContourScanner)cvAlloc( sizeof( *scanner ));
227     memset( scanner, 0, sizeof( *scanner ));
228
229     scanner->storage1 = scanner->storage2 = storage;
230     scanner->img0 = (schar *) img;
231     scanner->img = (schar *) (img + step);
232     scanner->img_step = step;
233     scanner->img_size.width = size.width - 1;   /* exclude rightest column */
234     scanner->img_size.height = size.height - 1; /* exclude bottomost row */
235     scanner->mode = mode;
236     scanner->offset = offset;
237     scanner->pt.x = scanner->pt.y = 1;
238     scanner->lnbd.x = 0;
239     scanner->lnbd.y = 1;
240     scanner->nbd = 2;
241     scanner->mode = (int) mode;
242     scanner->frame_info.contour = &(scanner->frame);
243     scanner->frame_info.is_hole = 1;
244     scanner->frame_info.next = 0;
245     scanner->frame_info.parent = 0;
246     scanner->frame_info.rect = cvRect( 0, 0, size.width, size.height );
247     scanner->l_cinfo = 0;
248     scanner->subst_flag = 0;
249
250     scanner->frame.flags = CV_SEQ_FLAG_HOLE;
251
252     scanner->approx_method2 = scanner->approx_method1 = method;
253
254     if( method == CV_CHAIN_APPROX_TC89_L1 || method == CV_CHAIN_APPROX_TC89_KCOS )
255         scanner->approx_method1 = CV_CHAIN_CODE;
256
257     if( scanner->approx_method1 == CV_CHAIN_CODE )
258     {
259         scanner->seq_type1 = CV_SEQ_CHAIN_CONTOUR;
260         scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ?
261             header_size : sizeof( CvChain );
262         scanner->elem_size1 = sizeof( char );
263     }
264     else
265     {
266         scanner->seq_type1 = CV_SEQ_POLYGON;
267         scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ?
268             header_size : sizeof( CvContour );
269         scanner->elem_size1 = sizeof( CvPoint );
270     }
271
272     scanner->header_size2 = header_size;
273
274     if( scanner->approx_method2 == CV_CHAIN_CODE )
275     {
276         scanner->seq_type2 = scanner->seq_type1;
277         scanner->elem_size2 = scanner->elem_size1;
278     }
279     else
280     {
281         scanner->seq_type2 = CV_SEQ_POLYGON;
282         scanner->elem_size2 = sizeof( CvPoint );
283     }
284
285     scanner->seq_type1 = scanner->approx_method1 == CV_CHAIN_CODE ?
286         CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON;
287
288     scanner->seq_type2 = scanner->approx_method2 == CV_CHAIN_CODE ?
289         CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON;
290
291     cvSaveMemStoragePos( storage, &(scanner->initial_pos) );
292
293     if( method > CV_CHAIN_APPROX_SIMPLE )
294     {
295         scanner->storage1 = cvCreateChildMemStorage( scanner->storage2 );
296     }
297
298     if( mode > CV_RETR_LIST )
299     {
300         scanner->cinfo_storage = cvCreateChildMemStorage( scanner->storage2 );
301         scanner->cinfo_set = cvCreateSet( 0, sizeof( CvSet ), sizeof( _CvContourInfo ),
302                                           scanner->cinfo_storage );
303     }
304
305     /* make zero borders */
306     memset( img, 0, size.width );
307     memset( img + step * (size.height - 1), 0, size.width );
308
309     for( y = 1, img += step; y < size.height - 1; y++, img += step )
310     {
311         img[0] = img[size.width - 1] = 0;
312     }
313
314     /* converts all pixels to 0 or 1 */
315     cvThreshold( mat, mat, 0, 1, CV_THRESH_BINARY );
316     CV_CHECK();
317
318     __END__;
319
320     if( cvGetErrStatus() < 0 )
321         cvFree( &scanner );
322
323     return scanner;
324 }
325
326 /*
327    Final stage of contour processing.
328    Three variants possible:
329       1. Contour, which was retrieved using border following, is added to
330          the contour tree. It is the case when the icvSubstituteContour function
331          was not called after retrieving the contour.
332
333       2. New contour, assigned by icvSubstituteContour function, is added to the
334          tree. The retrieved contour itself is removed from the storage.
335          Here two cases are possible:
336             2a. If one deals with plane variant of algorithm
337                 (hierarchical strucutre is not reconstructed),
338                 the contour is removed completely.
339             2b. In hierarchical case, the header of the contour is not removed.
340                 It's marked as "link to contour" and h_next pointer of it is set to
341                 new, substituting contour.
342
343       3. The similar to 2, but when NULL pointer was assigned by
344          icvSubstituteContour function. In this case, the function removes
345          retrieved contour completely if plane case and
346          leaves header if hierarchical (but doesn't mark header as "link").
347       ------------------------------------------------------------------------
348       The 1st variant can be used to retrieve and store all the contours from the image
349       (with optional convertion from chains to contours using some approximation from
350       restriced set of methods). Some characteristics of contour can be computed in the
351       same pass.
352
353       The usage scheme can look like:
354
355       icvContourScanner scanner;
356       CvMemStorage*  contour_storage;
357       CvSeq*  first_contour;
358       CvStatus  result;
359
360       ...
361
362       icvCreateMemStorage( &contour_storage, block_size/0 );
363
364       ...
365
366       cvStartFindContours
367               ( img, contour_storage,
368                 header_size, approx_method,
369                 [external_only,]
370                 &scanner );
371
372       for(;;)
373       {
374           [CvSeq* contour;]
375           result = icvFindNextContour( &scanner, &contour/0 );
376
377           if( result != CV_OK ) break;
378
379           // calculate some characteristics
380           ...
381       }
382
383       if( result < 0 ) goto error_processing;
384
385       cvEndFindContours( &scanner, &first_contour );
386       ...
387
388       -----------------------------------------------------------------
389
390       Second variant is more complex and can be used when someone wants store not
391       the retrieved contours but transformed ones. (e.g. approximated with some
392       non-default algorithm ).
393
394       The scheme can be the as following:
395
396       icvContourScanner scanner;
397       CvMemStorage*  contour_storage;
398       CvMemStorage*  temp_storage;
399       CvSeq*  first_contour;
400       CvStatus  result;
401
402       ...
403
404       icvCreateMemStorage( &contour_storage, block_size/0 );
405       icvCreateMemStorage( &temp_storage, block_size/0 );
406
407       ...
408
409       icvStartFindContours8uC1R
410               ( <img_params>, temp_storage,
411                 header_size, approx_method,
412                 [retrival_mode],
413                 &scanner );
414
415       for(;;)
416       {
417           CvSeq* temp_contour;
418           CvSeq* new_contour;
419           result = icvFindNextContour( scanner, &temp_contour );
420
421           if( result != CV_OK ) break;
422
423           <approximation_function>( temp_contour, contour_storage,
424                                     &new_contour, <parameters...> );
425
426           icvSubstituteContour( scanner, new_contour );
427           ...
428       }
429
430       if( result < 0 ) goto error_processing;
431
432       cvEndFindContours( &scanner, &first_contour );
433       ...
434
435       ----------------------------------------------------------------------------
436       Third method to retrieve contours may be applied if contours are irrelevant
437       themselves but some characteristics of them are used only.
438       The usage is similar to second except slightly different internal loop
439
440       for(;;)
441       {
442           CvSeq* temp_contour;
443           result = icvFindNextContour( &scanner, &temp_contour );
444
445           if( result != CV_OK ) break;
446
447           // calculate some characteristics of temp_contour
448
449           icvSubstituteContour( scanner, 0 );
450           ...
451       }
452
453       new_storage variable is not needed here.
454
455       Two notes.
456       1. Second and third method can interleave. I.e. it is possible to
457          remain contours that satisfy with some criteria and reject others.
458          In hierarchic case the resulting tree is the part of original tree with
459          some nodes absent. But in the resulting tree the contour1 is a child
460          (may be indirect) of contour2 iff in the original tree the contour1
461          is a child (may be indirect) of contour2.
462 */
463 static void
464 icvEndProcessContour( CvContourScanner scanner )
465 {
466     _CvContourInfo *l_cinfo = scanner->l_cinfo;
467
468     if( l_cinfo )
469     {
470         if( scanner->subst_flag )
471         {
472             CvMemStoragePos temp;
473
474             cvSaveMemStoragePos( scanner->storage2, &temp );
475
476             if( temp.top == scanner->backup_pos2.top &&
477                 temp.free_space == scanner->backup_pos2.free_space )
478             {
479                 cvRestoreMemStoragePos( scanner->storage2, &scanner->backup_pos );
480             }
481             scanner->subst_flag = 0;
482         }
483
484         if( l_cinfo->contour )
485         {
486             cvInsertNodeIntoTree( l_cinfo->contour, l_cinfo->parent->contour,
487                                   &(scanner->frame) );
488         }
489         scanner->l_cinfo = 0;
490     }
491 }
492
493 /* replaces one contour with another */
494 CV_IMPL void
495 cvSubstituteContour( CvContourScanner scanner, CvSeq * new_contour )
496 {
497     _CvContourInfo *l_cinfo;
498
499     CV_FUNCNAME( "cvSubstituteContour" );
500
501     __BEGIN__;
502
503     if( !scanner )
504         CV_ERROR( CV_StsNullPtr, "" );
505
506     l_cinfo = scanner->l_cinfo;
507     if( l_cinfo && l_cinfo->contour && l_cinfo->contour != new_contour )
508     {
509         l_cinfo->contour = new_contour;
510         scanner->subst_flag = 1;
511     }
512
513     __END__;
514 }
515
516
517 /*
518     marks domain border with +/-<constant> and stores the contour into CvSeq.
519         method:
520             <0  - chain
521             ==0 - direct
522             >0  - simple approximation
523 */
524 static CvStatus
525 icvFetchContour( schar                  *ptr,
526                  int                    step,
527                  CvPoint                pt,
528                  CvSeq*                 contour,
529                  int    _method )
530 {
531     const schar     nbd = 2;
532     int             deltas[16];
533     CvSeqWriter     writer;
534     schar           *i0 = ptr, *i1, *i3, *i4 = 0;
535     int             prev_s = -1, s, s_end;
536     int             method = _method - 1;
537
538     assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
539
540     /* initialize local state */
541     CV_INIT_3X3_DELTAS( deltas, step, 1 );
542     memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
543
544     /* initialize writer */
545     cvStartAppendToSeq( contour, &writer );
546
547     if( method < 0 )
548         ((CvChain *) contour)->origin = pt;
549
550     s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
551
552     do
553     {
554         s = (s - 1) & 7;
555         i1 = i0 + deltas[s];
556         if( *i1 != 0 )
557             break;
558     }
559     while( s != s_end );
560
561     if( s == s_end )            /* single pixel domain */
562     {
563         *i0 = (schar) (nbd | -128);
564         if( method >= 0 )
565         {
566             CV_WRITE_SEQ_ELEM( pt, writer );
567         }
568     }
569     else
570     {
571         i3 = i0;
572         prev_s = s ^ 4;
573
574         /* follow border */
575         for( ;; )
576         {
577             s_end = s;
578
579             for( ;; )
580             {
581                 i4 = i3 + deltas[++s];
582                 if( *i4 != 0 )
583                     break;
584             }
585             s &= 7;
586
587             /* check "right" bound */
588             if( (unsigned) (s - 1) < (unsigned) s_end )
589             {
590                 *i3 = (schar) (nbd | -128);
591             }
592             else if( *i3 == 1 )
593             {
594                 *i3 = nbd;
595             }
596
597             if( method < 0 )
598             {
599                 schar _s = (schar) s;
600
601                 CV_WRITE_SEQ_ELEM( _s, writer );
602             }
603             else
604             {
605                 if( s != prev_s || method == 0 )
606                 {
607                     CV_WRITE_SEQ_ELEM( pt, writer );
608                     prev_s = s;
609                 }
610
611                 pt.x += icvCodeDeltas[s].x;
612                 pt.y += icvCodeDeltas[s].y;
613
614             }
615
616             if( i4 == i0 && i3 == i1 )
617                 break;
618
619             i3 = i4;
620             s = (s + 4) & 7;
621         }                       /* end of border following loop */
622     }
623
624     cvEndWriteSeq( &writer );
625
626     if( _method != CV_CHAIN_CODE )
627         cvBoundingRect( contour, 1 );
628
629     assert( (writer.seq->total == 0 && writer.seq->first == 0) ||
630             writer.seq->total > writer.seq->first->count ||
631             (writer.seq->first->prev == writer.seq->first &&
632              writer.seq->first->next == writer.seq->first) );
633
634     return CV_OK;
635 }
636
637
638
639 /*
640    trace contour until certain point is met.
641    returns 1 if met, 0 else.
642 */
643 static int
644 icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole )
645 {
646     int deltas[16];
647     schar *i0 = ptr, *i1, *i3, *i4;
648     int s, s_end;
649
650     /* initialize local state */
651     CV_INIT_3X3_DELTAS( deltas, step, 1 );
652     memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
653
654     assert( (*i0 & -2) != 0 );
655
656     s_end = s = is_hole ? 0 : 4;
657
658     do
659     {
660         s = (s - 1) & 7;
661         i1 = i0 + deltas[s];
662         if( *i1 != 0 )
663             break;
664     }
665     while( s != s_end );
666
667     i3 = i0;
668
669     /* check single pixel domain */
670     if( s != s_end )
671     {
672         /* follow border */
673         for( ;; )
674         {
675             s_end = s;
676
677             for( ;; )
678             {
679                 i4 = i3 + deltas[++s];
680                 if( *i4 != 0 )
681                     break;
682             }
683
684             if( i3 == stop_ptr || (i4 == i0 && i3 == i1) )
685                 break;
686
687             i3 = i4;
688             s = (s + 4) & 7;
689         }                       /* end of border following loop */
690     }
691     return i3 == stop_ptr;
692 }
693
694
695 static CvStatus
696 icvFetchContourEx( schar*               ptr,
697                    int                  step,
698                    CvPoint              pt,
699                    CvSeq*               contour,
700                    int  _method,
701                    int                  nbd,
702                    CvRect*              _rect )
703 {
704     int         deltas[16];
705     CvSeqWriter writer;
706     schar        *i0 = ptr, *i1, *i3, *i4;
707     CvRect      rect;
708     int         prev_s = -1, s, s_end;
709     int         method = _method - 1;
710
711     assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
712     assert( 1 < nbd && nbd < 128 );
713
714     /* initialize local state */
715     CV_INIT_3X3_DELTAS( deltas, step, 1 );
716     memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
717
718     /* initialize writer */
719     cvStartAppendToSeq( contour, &writer );
720
721     if( method < 0 )
722         ((CvChain *)contour)->origin = pt;
723
724     rect.x = rect.width = pt.x;
725     rect.y = rect.height = pt.y;
726
727     s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
728
729     do
730     {
731         s = (s - 1) & 7;
732         i1 = i0 + deltas[s];
733         if( *i1 != 0 )
734             break;
735     }
736     while( s != s_end );
737
738     if( s == s_end )            /* single pixel domain */
739     {
740         *i0 = (schar) (nbd | 0x80);
741         if( method >= 0 )
742         {
743             CV_WRITE_SEQ_ELEM( pt, writer );
744         }
745     }
746     else
747     {
748         i3 = i0;
749
750         prev_s = s ^ 4;
751
752         /* follow border */
753         for( ;; )
754         {
755             s_end = s;
756
757             for( ;; )
758             {
759                 i4 = i3 + deltas[++s];
760                 if( *i4 != 0 )
761                     break;
762             }
763             s &= 7;
764
765             /* check "right" bound */
766             if( (unsigned) (s - 1) < (unsigned) s_end )
767             {
768                 *i3 = (schar) (nbd | 0x80);
769             }
770             else if( *i3 == 1 )
771             {
772                 *i3 = (schar) nbd;
773             }
774
775             if( method < 0 )
776             {
777                 schar _s = (schar) s;
778                 CV_WRITE_SEQ_ELEM( _s, writer );
779             }
780             else if( s != prev_s || method == 0 )
781             {
782                 CV_WRITE_SEQ_ELEM( pt, writer );
783             }
784
785             if( s != prev_s )
786             {
787                 /* update bounds */
788                 if( pt.x < rect.x )
789                     rect.x = pt.x;
790                 else if( pt.x > rect.width )
791                     rect.width = pt.x;
792
793                 if( pt.y < rect.y )
794                     rect.y = pt.y;
795                 else if( pt.y > rect.height )
796                     rect.height = pt.y;
797             }
798
799             prev_s = s;
800             pt.x += icvCodeDeltas[s].x;
801             pt.y += icvCodeDeltas[s].y;
802
803             if( i4 == i0 && i3 == i1 )  break;
804
805             i3 = i4;
806             s = (s + 4) & 7;
807         }                       /* end of border following loop */
808     }
809
810     rect.width -= rect.x - 1;
811     rect.height -= rect.y - 1;
812
813     cvEndWriteSeq( &writer );
814
815     if( _method != CV_CHAIN_CODE )
816         ((CvContour*)contour)->rect = rect;
817
818     assert( (writer.seq->total == 0 && writer.seq->first == 0) ||
819             writer.seq->total > writer.seq->first->count ||
820             (writer.seq->first->prev == writer.seq->first &&
821              writer.seq->first->next == writer.seq->first) );
822
823     if( _rect )  *_rect = rect;
824
825     return CV_OK;
826 }
827
828
829 CvSeq *
830 cvFindNextContour( CvContourScanner scanner )
831 {
832     schar *img0;
833     schar *img;
834     int step;
835     int width, height;
836     int x, y;
837     int prev;
838     CvPoint lnbd;
839     CvSeq *contour = 0;
840     int nbd;
841     int mode;
842     CvStatus result = (CvStatus) 1;
843
844     CV_FUNCNAME( "cvFindNextContour" );
845
846     __BEGIN__;
847
848     if( !scanner )
849         CV_ERROR( CV_StsNullPtr, "" );
850     icvEndProcessContour( scanner );
851
852     /* initialize local state */
853     img0 = scanner->img0;
854     img = scanner->img;
855     step = scanner->img_step;
856     x = scanner->pt.x;
857     y = scanner->pt.y;
858     width = scanner->img_size.width;
859     height = scanner->img_size.height;
860     mode = scanner->mode;
861     lnbd = scanner->lnbd;
862     nbd = scanner->nbd;
863
864     prev = img[x - 1];
865
866     for( ; y < height; y++, img += step )
867     {
868         for( ; x < width; x++ )
869         {
870             int p = img[x];
871
872             if( p != prev )
873             {
874                 _CvContourInfo *par_info = 0;
875                 _CvContourInfo *l_cinfo = 0;
876                 CvSeq *seq = 0;
877                 int is_hole = 0;
878                 CvPoint origin;
879
880                 if( !(prev == 0 && p == 1) )    /* if not external contour */
881                 {
882                     /* check hole */
883                     if( p != 0 || prev < 1 )
884                         goto resume_scan;
885
886                     if( prev & -2 )
887                     {
888                         lnbd.x = x - 1;
889                     }
890                     is_hole = 1;
891                 }
892
893                 if( mode == 0 && (is_hole || img0[lnbd.y * step + lnbd.x] > 0) )
894                     goto resume_scan;
895
896                 origin.y = y;
897                 origin.x = x - is_hole;
898
899                 /* find contour parent */
900                 if( mode <= 1 || (!is_hole && mode == 2) || lnbd.x <= 0 )
901                 {
902                     par_info = &(scanner->frame_info);
903                 }
904                 else
905                 {
906                     int lval = img0[lnbd.y * step + lnbd.x] & 0x7f;
907                     _CvContourInfo *cur = scanner->cinfo_table[lval - 2];
908
909                     assert( lval >= 2 );
910
911                     /* find the first bounding contour */
912                     while( cur )
913                     {
914                         if( (unsigned) (lnbd.x - cur->rect.x) < (unsigned) cur->rect.width &&
915                             (unsigned) (lnbd.y - cur->rect.y) < (unsigned) cur->rect.height )
916                         {
917                             if( par_info )
918                             {
919                                 if( icvTraceContour( scanner->img0 +
920                                                      par_info->origin.y * step +
921                                                      par_info->origin.x, step, img + lnbd.x,
922                                                      par_info->is_hole ) > 0 )
923                                     break;
924                             }
925                             par_info = cur;
926                         }
927                         cur = cur->next;
928                     }
929
930                     assert( par_info != 0 );
931
932                     /* if current contour is a hole and previous contour is a hole or
933                        current contour is external and previous contour is external then
934                        the parent of the contour is the parent of the previous contour else
935                        the parent is the previous contour itself. */
936                     if( par_info->is_hole == is_hole )
937                     {
938                         par_info = par_info->parent;
939                         /* every contour must have a parent
940                            (at least, the frame of the image) */
941                         if( !par_info )
942                             par_info = &(scanner->frame_info);
943                     }
944
945                     /* hole flag of the parent must differ from the flag of the contour */
946                     assert( par_info->is_hole != is_hole );
947                     if( par_info->contour == 0 )        /* removed contour */
948                         goto resume_scan;
949                 }
950
951                 lnbd.x = x - is_hole;
952
953                 cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos) );
954
955                 seq = cvCreateSeq( scanner->seq_type1, scanner->header_size1,
956                                    scanner->elem_size1, scanner->storage1 );
957                 seq->flags |= is_hole ? CV_SEQ_FLAG_HOLE : 0;
958
959                 /* initialize header */
960                 if( mode <= 1 )
961                 {
962                     l_cinfo = &(scanner->cinfo_temp);
963                     result = icvFetchContour( img + x - is_hole, step,
964                                               cvPoint( origin.x + scanner->offset.x,
965                                                        origin.y + scanner->offset.y),
966                                               seq, scanner->approx_method1 );
967                     if( result < 0 )
968                         goto exit_func;
969                 }
970                 else
971                 {
972                     union { _CvContourInfo* ci; CvSetElem* se; } v;
973                     v.ci = l_cinfo;
974                     cvSetAdd( scanner->cinfo_set, 0, &v.se );
975                     l_cinfo = v.ci;
976
977                     result = icvFetchContourEx( img + x - is_hole, step,
978                                                 cvPoint( origin.x + scanner->offset.x,
979                                                          origin.y + scanner->offset.y),
980                                                 seq, scanner->approx_method1,
981                                                 nbd, &(l_cinfo->rect) );
982                     if( result < 0 )
983                         goto exit_func;
984                     l_cinfo->rect.x -= scanner->offset.x;
985                     l_cinfo->rect.y -= scanner->offset.y;
986
987                     l_cinfo->next = scanner->cinfo_table[nbd - 2];
988                     scanner->cinfo_table[nbd - 2] = l_cinfo;
989
990                     /* change nbd */
991                     nbd = (nbd + 1) & 127;
992                     nbd += nbd == 0 ? 3 : 0;
993                 }
994
995                 l_cinfo->is_hole = is_hole;
996                 l_cinfo->contour = seq;
997                 l_cinfo->origin = origin;
998                 l_cinfo->parent = par_info;
999
1000                 if( scanner->approx_method1 != scanner->approx_method2 )
1001                 {
1002                     result = icvApproximateChainTC89( (CvChain *) seq,
1003                                                       scanner->header_size2,
1004                                                       scanner->storage2,
1005                                                       &(l_cinfo->contour),
1006                                                       scanner->approx_method2 );
1007                     if( result < 0 )
1008                         goto exit_func;
1009                     cvClearMemStorage( scanner->storage1 );
1010                 }
1011
1012                 l_cinfo->contour->v_prev = l_cinfo->parent->contour;
1013
1014                 if( par_info->contour == 0 )
1015                 {
1016                     l_cinfo->contour = 0;
1017                     if( scanner->storage1 == scanner->storage2 )
1018                     {
1019                         cvRestoreMemStoragePos( scanner->storage1, &(scanner->backup_pos) );
1020                     }
1021                     else
1022                     {
1023                         cvClearMemStorage( scanner->storage1 );
1024                     }
1025                     p = img[x];
1026                     goto resume_scan;
1027                 }
1028
1029                 cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos2) );
1030                 scanner->l_cinfo = l_cinfo;
1031                 scanner->pt.x = x + 1;
1032                 scanner->pt.y = y;
1033                 scanner->lnbd = lnbd;
1034                 scanner->img = (schar *) img;
1035                 scanner->nbd = nbd;
1036                 contour = l_cinfo->contour;
1037
1038                 result = CV_OK;
1039                 goto exit_func;
1040               resume_scan:
1041                 prev = p;
1042                 /* update lnbd */
1043                 if( prev & -2 )
1044                 {
1045                     lnbd.x = x;
1046                 }
1047             }                   /* end of prev != p */
1048         }                       /* end of loop on x */
1049
1050         lnbd.x = 0;
1051         lnbd.y = y + 1;
1052         x = 1;
1053         prev = 0;
1054
1055     }                           /* end of loop on y */
1056
1057   exit_func:
1058
1059     if( result != 0 )
1060         contour = 0;
1061     if( result < 0 )
1062         CV_ERROR( result, "" );
1063
1064     __END__;
1065
1066     return contour;
1067 }
1068
1069
1070 /*
1071    The function add to tree the last retrieved/substituted contour,
1072    releases temp_storage, restores state of dst_storage (if needed), and
1073    returns pointer to root of the contour tree */
1074 CV_IMPL CvSeq *
1075 cvEndFindContours( CvContourScanner * _scanner )
1076 {
1077     CvContourScanner scanner;
1078     CvSeq *first = 0;
1079
1080     CV_FUNCNAME( "cvFindNextContour" );
1081
1082     __BEGIN__;
1083
1084     if( !_scanner )
1085         CV_ERROR( CV_StsNullPtr, "" );
1086     scanner = *_scanner;
1087
1088     if( scanner )
1089     {
1090         icvEndProcessContour( scanner );
1091
1092         if( scanner->storage1 != scanner->storage2 )
1093             cvReleaseMemStorage( &(scanner->storage1) );
1094
1095         if( scanner->cinfo_storage )
1096             cvReleaseMemStorage( &(scanner->cinfo_storage) );
1097
1098         first = scanner->frame.v_next;
1099         cvFree( _scanner );
1100     }
1101
1102     __END__;
1103
1104     return first;
1105 }
1106
1107
1108 #define ICV_SINGLE                  0
1109 #define ICV_CONNECTING_ABOVE        1
1110 #define ICV_CONNECTING_BELOW        -1
1111 #define ICV_IS_COMPONENT_POINT(val) ((val) != 0)
1112
1113 #define CV_GET_WRITTEN_ELEM( writer ) ((writer).ptr - (writer).seq->elem_size)
1114
1115 typedef  struct CvLinkedRunPoint
1116 {
1117     struct CvLinkedRunPoint* link;
1118     struct CvLinkedRunPoint* next;
1119     CvPoint pt;
1120 }
1121 CvLinkedRunPoint;
1122
1123
1124 static int
1125 icvFindContoursInInterval( const CvArr* src,
1126                            /*int minValue, int maxValue,*/
1127                            CvMemStorage* storage,
1128                            CvSeq** result,
1129                            int contourHeaderSize )
1130 {
1131     int count = 0;
1132     CvMemStorage* storage00 = 0;
1133     CvMemStorage* storage01 = 0;
1134     CvSeq* first = 0;
1135
1136     CV_FUNCNAME( "icvFindContoursInInterval" );
1137
1138     __BEGIN__;
1139
1140     int i, j, k, n;
1141
1142     uchar*  src_data = 0;
1143     int  img_step = 0;
1144     CvSize  img_size;
1145
1146     int  connect_flag;
1147     int  lower_total;
1148     int  upper_total;
1149     int  all_total;
1150
1151     CvSeq*  runs;
1152     CvLinkedRunPoint  tmp;
1153     CvLinkedRunPoint*  tmp_prev;
1154     CvLinkedRunPoint*  upper_line = 0;
1155     CvLinkedRunPoint*  lower_line = 0;
1156     CvLinkedRunPoint*  last_elem;
1157
1158     CvLinkedRunPoint*  upper_run = 0;
1159     CvLinkedRunPoint*  lower_run = 0;
1160     CvLinkedRunPoint*  prev_point = 0;
1161
1162     CvSeqWriter  writer_ext;
1163     CvSeqWriter  writer_int;
1164     CvSeqWriter  writer;
1165     CvSeqReader  reader;
1166
1167     CvSeq* external_contours;
1168     CvSeq* internal_contours;
1169     CvSeq* prev = 0;
1170
1171     if( !storage )
1172         CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
1173
1174     if( !result )
1175         CV_ERROR( CV_StsNullPtr, "NULL double CvSeq pointer" );
1176
1177     if( contourHeaderSize < (int)sizeof(CvContour))
1178         CV_ERROR( CV_StsBadSize, "Contour header size must be >= sizeof(CvContour)" );
1179
1180     CV_CALL( storage00 = cvCreateChildMemStorage(storage));
1181     CV_CALL( storage01 = cvCreateChildMemStorage(storage));
1182
1183     {
1184         CvMat stub, *mat;
1185
1186         CV_CALL( mat = cvGetMat( src, &stub ));
1187         if( !CV_IS_MASK_ARR(mat))
1188             CV_ERROR( CV_StsBadArg, "Input array must be 8uC1 or 8sC1" );
1189         src_data = mat->data.ptr;
1190         img_step = mat->step;
1191         img_size = cvGetMatSize( mat );
1192     }
1193
1194     // Create temporary sequences
1195     runs = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvLinkedRunPoint), storage00 );
1196     cvStartAppendToSeq( runs, &writer );
1197
1198     cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_ext );
1199     cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_int );
1200
1201     tmp_prev = &(tmp);
1202     tmp_prev->next = 0;
1203     tmp_prev->link = 0;
1204
1205     // First line. None of runs is binded
1206     tmp.pt.y = 0;
1207     i = 0;
1208     CV_WRITE_SEQ_ELEM( tmp, writer );
1209     upper_line = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1210
1211     tmp_prev = upper_line;
1212     for( j = 0; j < img_size.width; )
1213     {
1214         for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1215             ;
1216         if( j == img_size.width )
1217             break;
1218
1219         tmp.pt.x = j;
1220         CV_WRITE_SEQ_ELEM( tmp, writer );
1221         tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1222         tmp_prev = tmp_prev->next;
1223
1224         for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1225             ;
1226
1227         tmp.pt.x = j-1;
1228         CV_WRITE_SEQ_ELEM( tmp, writer );
1229         tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1230         tmp_prev->link = tmp_prev->next;
1231         // First point of contour
1232         CV_WRITE_SEQ_ELEM( tmp_prev, writer_ext );
1233         tmp_prev = tmp_prev->next;
1234     }
1235     cvFlushSeqWriter( &writer );
1236     upper_line = upper_line->next;
1237     upper_total = runs->total - 1;
1238     last_elem = tmp_prev;
1239     tmp_prev->next = 0;
1240
1241     for( i = 1; i < img_size.height; i++ )
1242     {
1243 //------// Find runs in next line
1244         src_data += img_step;
1245         tmp.pt.y = i;
1246         all_total = runs->total;
1247         for( j = 0; j < img_size.width; )
1248         {
1249             for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1250                 ;
1251             if( j == img_size.width ) break;
1252
1253             tmp.pt.x = j;
1254             CV_WRITE_SEQ_ELEM( tmp, writer );
1255             tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1256             tmp_prev = tmp_prev->next;
1257
1258             for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
1259                 ;
1260
1261             tmp.pt.x = j-1;
1262             CV_WRITE_SEQ_ELEM( tmp, writer );
1263             tmp_prev = tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
1264         }//j
1265         cvFlushSeqWriter( &writer );
1266         lower_line = last_elem->next;
1267         lower_total = runs->total - all_total;
1268         last_elem = tmp_prev;
1269         tmp_prev->next = 0;
1270 //------//
1271 //------// Find links between runs of lower_line and upper_line
1272         upper_run = upper_line;
1273         lower_run = lower_line;
1274         connect_flag = ICV_SINGLE;
1275
1276         for( k = 0, n = 0; k < upper_total/2 && n < lower_total/2; )
1277         {
1278             switch( connect_flag )
1279             {
1280             case ICV_SINGLE:
1281                 if( upper_run->next->pt.x < lower_run->next->pt.x )
1282                 {
1283                     if( upper_run->next->pt.x >= lower_run->pt.x  -1 )
1284                     {
1285                         lower_run->link = upper_run;
1286                         connect_flag = ICV_CONNECTING_ABOVE;
1287                         prev_point = upper_run->next;
1288                     }
1289                     else
1290                         upper_run->next->link = upper_run;
1291                     k++;
1292                     upper_run = upper_run->next->next;
1293                 }
1294                 else
1295                 {
1296                     if( upper_run->pt.x <= lower_run->next->pt.x  +1 )
1297                     {
1298                         lower_run->link = upper_run;
1299                         connect_flag = ICV_CONNECTING_BELOW;
1300                         prev_point = lower_run->next;
1301                     }
1302                     else
1303                     {
1304                         lower_run->link = lower_run->next;
1305                         // First point of contour
1306                         CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
1307                     }
1308                     n++;
1309                     lower_run = lower_run->next->next;
1310                 }
1311                 break;
1312             case ICV_CONNECTING_ABOVE:
1313                 if( upper_run->pt.x > lower_run->next->pt.x +1 )
1314                 {
1315                     prev_point->link = lower_run->next;
1316                     connect_flag = ICV_SINGLE;
1317                     n++;
1318                     lower_run = lower_run->next->next;
1319                 }
1320                 else
1321                 {
1322                     prev_point->link = upper_run;
1323                     if( upper_run->next->pt.x < lower_run->next->pt.x )
1324                     {
1325                         k++;
1326                         prev_point = upper_run->next;
1327                         upper_run = upper_run->next->next;
1328                     }
1329                     else
1330                     {
1331                         connect_flag = ICV_CONNECTING_BELOW;
1332                         prev_point = lower_run->next;
1333                         n++;
1334                         lower_run = lower_run->next->next;
1335                     }
1336                 }
1337                 break;
1338             case ICV_CONNECTING_BELOW:
1339                 if( lower_run->pt.x > upper_run->next->pt.x +1 )
1340                 {
1341                     upper_run->next->link = prev_point;
1342                     connect_flag = ICV_SINGLE;
1343                     k++;
1344                     upper_run = upper_run->next->next;
1345                 }
1346                 else
1347                 {
1348                     // First point of contour
1349                     CV_WRITE_SEQ_ELEM( lower_run, writer_int );
1350
1351                     lower_run->link = prev_point;
1352                     if( lower_run->next->pt.x < upper_run->next->pt.x )
1353                     {
1354                         n++;
1355                         prev_point = lower_run->next;
1356                         lower_run = lower_run->next->next;
1357                     }
1358                     else
1359                     {
1360                         connect_flag = ICV_CONNECTING_ABOVE;
1361                         k++;
1362                         prev_point = upper_run->next;
1363                         upper_run = upper_run->next->next;
1364                     }
1365                 }
1366                 break;
1367             }
1368         }// k, n
1369
1370         for( ; n < lower_total/2; n++ )
1371         {
1372             if( connect_flag != ICV_SINGLE )
1373             {
1374                 prev_point->link = lower_run->next;
1375                 connect_flag = ICV_SINGLE;
1376                 lower_run = lower_run->next->next;
1377                 continue;
1378             }
1379             lower_run->link = lower_run->next;
1380
1381             //First point of contour
1382             CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
1383
1384             lower_run = lower_run->next->next;
1385         }
1386
1387         for( ; k < upper_total/2; k++ )
1388         {
1389             if( connect_flag != ICV_SINGLE )
1390             {
1391                 upper_run->next->link = prev_point;
1392                 connect_flag = ICV_SINGLE;
1393                 upper_run = upper_run->next->next;
1394                 continue;
1395             }
1396             upper_run->next->link = upper_run;
1397             upper_run = upper_run->next->next;
1398         }
1399         upper_line = lower_line;
1400         upper_total = lower_total;
1401     }//i
1402
1403     upper_run = upper_line;
1404
1405     //the last line of image
1406     for( k = 0; k < upper_total/2; k++ )
1407     {
1408         upper_run->next->link = upper_run;
1409         upper_run = upper_run->next->next;
1410     }
1411
1412 //------//
1413 //------//Find end read contours
1414     external_contours = cvEndWriteSeq( &writer_ext );
1415     internal_contours = cvEndWriteSeq( &writer_int );
1416
1417     for( k = 0; k < 2; k++ )
1418     {
1419         CvSeq* contours = k == 0 ? external_contours : internal_contours;
1420
1421         cvStartReadSeq( contours, &reader );
1422
1423         for( j = 0; j < contours->total; j++, count++ )
1424         {
1425             CvLinkedRunPoint* p_temp;
1426             CvLinkedRunPoint* p00;
1427             CvLinkedRunPoint* p01;
1428             CvSeq* contour;
1429
1430             CV_READ_SEQ_ELEM( p00, reader );
1431             p01 = p00;
1432
1433             if( !p00->link )
1434                 continue;
1435
1436             cvStartWriteSeq( CV_SEQ_ELTYPE_POINT | CV_SEQ_POLYLINE | CV_SEQ_FLAG_CLOSED,
1437                              contourHeaderSize, sizeof(CvPoint), storage, &writer );
1438             do
1439             {
1440                 CV_WRITE_SEQ_ELEM( p00->pt, writer );
1441                 p_temp = p00;
1442                 p00 = p00->link;
1443                 p_temp->link = 0;
1444             }
1445             while( p00 != p01 );
1446
1447             contour = cvEndWriteSeq( &writer );
1448             cvBoundingRect( contour, 1 );
1449
1450             if( k != 0 )
1451                 contour->flags |= CV_SEQ_FLAG_HOLE;
1452
1453             if( !first )
1454                 prev = first = contour;
1455             else
1456             {
1457                 contour->h_prev = prev;
1458                 prev = prev->h_next = contour;
1459             }
1460         }
1461     }
1462
1463     __END__;
1464
1465     if( !first )
1466         count = -1;
1467
1468     if( result )
1469         *result = first;
1470
1471     cvReleaseMemStorage(&storage00);
1472     cvReleaseMemStorage(&storage01);
1473
1474     return count;
1475 }
1476
1477
1478
1479 /*F///////////////////////////////////////////////////////////////////////////////////////
1480 //    Name: cvFindContours
1481 //    Purpose:
1482 //      Finds all the contours on the bi-level image.
1483 //    Context:
1484 //    Parameters:
1485 //      img  - source image.
1486 //             Non-zero pixels are considered as 1-pixels
1487 //             and zero pixels as 0-pixels.
1488 //      step - full width of source image in bytes.
1489 //      size - width and height of the image in pixels
1490 //      storage - pointer to storage where will the output contours be placed.
1491 //      header_size - header size of resulting contours
1492 //      mode - mode of contour retrieval.
1493 //      method - method of approximation that is applied to contours
1494 //      first_contour - pointer to first contour pointer
1495 //    Returns:
1496 //      CV_OK or error code
1497 //    Notes:
1498 //F*/
1499 CV_IMPL int
1500 cvFindContours( void*  img,  CvMemStorage*  storage,
1501                 CvSeq**  firstContour, int  cntHeaderSize,
1502                 int  mode,
1503                 int  method, CvPoint offset )
1504 {
1505     CvContourScanner scanner = 0;
1506     CvSeq *contour = 0;
1507     int count = -1;
1508
1509     CV_FUNCNAME( "cvFindContours" );
1510
1511     __BEGIN__;
1512
1513     if( !firstContour )
1514         CV_ERROR( CV_StsNullPtr, "NULL double CvSeq pointer" );
1515
1516     if( method == CV_LINK_RUNS )
1517     {
1518         if( offset.x != 0 || offset.y != 0 )
1519             CV_ERROR( CV_StsOutOfRange,
1520             "Nonzero offset is not supported in CV_LINK_RUNS yet" );
1521
1522         CV_CALL( count = icvFindContoursInInterval( img, storage,
1523                                     firstContour, cntHeaderSize ));
1524     }
1525     else
1526     {
1527         CV_CALL( scanner = cvStartFindContours( img, storage,
1528                         cntHeaderSize, mode, method, offset ));
1529         assert( scanner );
1530
1531         do
1532         {
1533             count++;
1534             contour = cvFindNextContour( scanner );
1535         }
1536         while( contour != 0 );
1537
1538         *firstContour = cvEndFindContours( &scanner );
1539     }
1540
1541     __END__;
1542
1543     return count;
1544 }
1545
1546 namespace cv
1547 {
1548 static void
1549 _findContours( const Mat& image, vector<vector<Point> >& contours,
1550                vector<Vec4i>* hierarchy, int mode, int method, Point offset )
1551 {
1552     MemStorage storage(cvCreateMemStorage());
1553     CvMat _image = image;
1554     CvSeq* _contours = 0;
1555     if( hierarchy )
1556         hierarchy->clear();
1557     cvFindContours(&_image, storage, &_contours, sizeof(CvContour), mode, method, offset);
1558     if( !_contours )
1559     {
1560         contours.clear();
1561         return;
1562     }
1563     Seq<CvSeq*> all_contours(cvTreeToNodeSeq( _contours, sizeof(CvSeq), storage ));
1564     size_t i, total = all_contours.size();
1565     contours.resize(total);
1566     SeqIterator<CvSeq*> it = all_contours.begin();
1567     for( i = 0; i < total; i++, ++it )
1568     {
1569         CvSeq* c = *it;
1570         ((CvContour*)c)->color = (int)i;
1571         Seq<Point>(c).copyTo(contours[i]);
1572     }
1573
1574     if( hierarchy )
1575     {
1576         hierarchy->resize(total);
1577         it = all_contours.begin();
1578         for( i = 0; i < total; i++, ++it )
1579         {
1580             CvSeq* c = *it;
1581             int h_next = c->h_next ? ((CvContour*)c->h_next)->color : -1;
1582             int h_prev = c->h_next ? ((CvContour*)c->h_next)->color : -1;
1583             int v_next = c->h_next ? ((CvContour*)c->h_next)->color : -1;
1584             int v_prev = c->h_next ? ((CvContour*)c->h_next)->color : -1;
1585             (*hierarchy)[i] = Vec4i(h_next, h_prev, v_next, v_prev);
1586         }
1587     }
1588 }
1589 }
1590
1591 void cv::findContours( const Mat& image, vector<vector<Point> >& contours,
1592                    vector<Vec4i>& hierarchy, int mode, int method, Point offset )
1593 {
1594     _findContours(image, contours, &hierarchy, mode, method, offset);
1595 }
1596
1597 void cv::findContours( const Mat& image, vector<vector<Point> >& contours,
1598                    int mode, int method, Point offset)
1599 {
1600     _findContours(image, contours, 0, mode, method, offset);
1601 }
1602
1603 namespace cv
1604 {
1605
1606 static void addChildContour(const vector<vector<Point> >& contours,
1607                             const vector<Vec4i>& hierarchy,
1608                             int i, vector<CvSeq>& seq,
1609                             vector<CvSeqBlock>& block)
1610 {
1611     size_t count = contours.size();
1612     for( ; i >= 0; i = hierarchy[i][0] )
1613     {
1614         const vector<Point>& ci = contours[i];
1615         cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
1616                                 !ci.empty() ? (void*)&ci[0] : 0, (int)ci.size(),
1617                                 &seq[i], &block[i] );
1618         
1619         int h_next = hierarchy[i][0], h_prev = hierarchy[i][1],
1620             v_next = hierarchy[i][2], v_prev = hierarchy[i][3];
1621         seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
1622         seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
1623         seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
1624         seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
1625         
1626         if( v_next >= 0 )
1627             addChildContour(contours, hierarchy, v_next, seq, block);
1628     }
1629 }
1630     
1631 }
1632
1633 void cv::drawContours( Mat& image, const vector<vector<Point> >& contours,
1634                    int contourIdx, const Scalar& color, int thickness,
1635                    int lineType, const vector<Vec4i>& hierarchy,
1636                    int maxLevel, Point offset )
1637 {
1638     CvMat _image = image;
1639
1640     size_t i = 0, first = 0, last = contours.size();
1641     vector<CvSeq> seq;
1642     vector<CvSeqBlock> block;
1643
1644     seq.resize(last);
1645     block.resize(last);
1646     
1647     for( i = first; i < last; i++ )
1648         seq[i].first = 0;
1649                               
1650     if( contourIdx >= 0 )
1651     {
1652         CV_Assert( 0 <= contourIdx && contourIdx < (int)last );
1653         first = contourIdx;
1654         last = contourIdx + 1;
1655     }
1656     
1657     for( i = first; i < last; i++ )
1658     {
1659         const vector<Point>& ci = contours[i];
1660         cvMakeSeqHeaderForArray(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point),
1661             !ci.empty() ? (void*)&ci[0] : 0, (int)ci.size(), &seq[i], &block[i] );
1662     }
1663
1664     if( hierarchy.empty() || maxLevel == 0 || maxLevel == INT_MAX )
1665         for( i = first; i < last; i++ )
1666         {
1667             seq[i].h_next = i < last-1 ? &seq[i+1] : 0;
1668             seq[i].h_prev = i > first ? &seq[i-1] : 0;
1669         }
1670     else
1671     {
1672         size_t count = last - first;
1673         CV_Assert(hierarchy.size() == contours.size());
1674         if( count == contours.size() )
1675         {
1676             for( i = first; i < last; i++ )
1677             {
1678                 int h_next = hierarchy[i][0], h_prev = hierarchy[i][1],
1679                     v_next = hierarchy[i][2], v_prev = hierarchy[i][3];
1680                 seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0;
1681                 seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0;
1682                 seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0;
1683                 seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0;
1684             }
1685         }
1686         else
1687         {
1688             int child = hierarchy[first][2];
1689             if( child >= 0 )
1690             {
1691                 addChildContour(contours, hierarchy, child, seq, block);
1692                 seq[first].v_next = &seq[child];
1693             }
1694         }
1695     }
1696
1697     cvDrawContours( &_image, &seq[first], color, color, contourIdx >= 0 ?
1698                    -maxLevel : maxLevel, thickness, lineType, offset );
1699 }
1700
1701 void cv::approxPolyDP( const Mat& curve, vector<Point>& approxCurve,
1702                        double epsilon, bool closed )
1703 {
1704     CV_Assert(curve.isContinuous() && curve.depth() == CV_32S &&
1705               ((curve.rows == 1 && curve.channels() == 2) ||
1706                curve.cols*curve.channels() == 2));
1707     CvMat _curve = curve;
1708     MemStorage storage(cvCreateMemStorage());
1709     Seq<Point> seq(cvApproxPoly(&_curve, sizeof(CvContour), storage, CV_POLY_APPROX_DP, epsilon, closed));
1710     seq.copyTo(approxCurve);
1711 }
1712
1713 void cv::approxPolyDP( const Mat& curve, vector<Point2f>& approxCurve,
1714                        double epsilon, bool closed )
1715 {
1716     CV_Assert(curve.isContinuous() && curve.depth() == CV_32F &&
1717               ((curve.rows == 1 && curve.channels() == 2) ||
1718                curve.cols*curve.channels() == 2));
1719     CvMat _curve = curve;
1720     MemStorage storage(cvCreateMemStorage());
1721     Seq<Point2f> seq(cvApproxPoly(&_curve, sizeof(CvContour), storage, CV_POLY_APPROX_DP, epsilon, closed));
1722     seq.copyTo(approxCurve);
1723 }
1724
1725 double cv::arcLength( const Mat& curve, bool closed )
1726 {
1727     CV_Assert(curve.isContinuous() &&
1728               (curve.depth() == CV_32S || curve.depth() == CV_32F) &&
1729               ((curve.rows == 1 && curve.channels() == 2) ||
1730                curve.cols*curve.channels() == 2));
1731     CvMat _curve = curve;
1732     return cvArcLength(&_curve, CV_WHOLE_SEQ, closed);
1733 }
1734
1735
1736 cv::Rect cv::boundingRect( const Mat& points )
1737 {
1738     CV_Assert(points.isContinuous() &&
1739               (points.depth() == CV_32S || points.depth() == CV_32F) &&
1740               ((points.rows == 1 && points.channels() == 2) ||
1741                points.cols*points.channels() == 2));
1742     CvMat _points = points;
1743     return cvBoundingRect(&_points, 0);
1744 }
1745
1746
1747 double cv::contourArea( const Mat& contour )
1748 {
1749     CV_Assert(contour.isContinuous() &&
1750               (contour.depth() == CV_32S || contour.depth() == CV_32F) &&
1751               ((contour.rows == 1 && contour.channels() == 2) ||
1752                contour.cols*contour.channels() == 2));
1753     CvMat _contour = contour;
1754     return cvContourArea(&_contour);
1755 }
1756
1757
1758 cv::RotatedRect cv::minAreaRect( const Mat& points )
1759 {
1760     CV_Assert(points.isContinuous() &&
1761               (points.depth() == CV_32S || points.depth() == CV_32F) &&
1762               ((points.rows == 1 && points.channels() == 2) ||
1763                points.cols*points.channels() == 2));
1764     CvMat _points = points;
1765     return cvMinAreaRect2(&_points, 0);
1766 }
1767
1768
1769 void cv::minEnclosingCircle( const Mat& points,
1770                              Point2f& center, float& radius )
1771 {
1772     CV_Assert(points.isContinuous() &&
1773               (points.depth() == CV_32S || points.depth() == CV_32F) &&
1774               ((points.rows == 1 && points.channels() == 2) ||
1775                points.cols*points.channels() == 2));
1776     CvMat _points = points;
1777     cvMinEnclosingCircle( &_points, (CvPoint2D32f*)&center, &radius );
1778 }
1779
1780
1781 double cv::matchShapes( const Mat& contour1,
1782                         const Mat& contour2,
1783                         int method, double parameter )
1784 {
1785     CV_Assert(contour1.isContinuous() && contour2.isContinuous() &&
1786               (contour1.depth() == CV_32S || contour1.depth() == CV_32F) &&
1787               contour1.depth() == contour2.depth() &&
1788               ((contour1.rows == 1 && contour1.channels() == 2 &&
1789                 contour2.rows == 1 && contour2.channels() == 2) ||
1790                (contour1.cols*contour1.channels() == 2 &&
1791                 contour2.cols*contour2.channels() == 2)));
1792     
1793     CvMat c1 = Mat(contour1), c2 = Mat(contour2);
1794     return cvMatchShapes(&c1, &c2, method, parameter);
1795 }
1796
1797
1798 void cv::convexHull( const Mat& points, vector<int>& hull, bool clockwise )
1799 {
1800     CV_Assert(points.isContinuous() &&
1801               (points.depth() == CV_32S || points.depth() == CV_32F) &&
1802               ((points.rows == 1 && points.channels() == 2) ||
1803                points.cols*points.channels() == 2));
1804     hull.resize(points.cols*points.rows*points.channels()/2);
1805     CvMat _points = Mat(points), _hull=Mat(hull);
1806     cvConvexHull2(&_points, &_hull, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 0);
1807     hull.resize(_hull.cols + _hull.rows - 1);
1808 }
1809
1810
1811 void cv::convexHull( const Mat& points,
1812                      vector<Point>& hull, bool clockwise )
1813 {
1814     CV_Assert(points.isContinuous() && points.depth() == CV_32S &&
1815               ((points.rows == 1 && points.channels() == 2) ||
1816                points.cols*points.channels() == 2));
1817     hull.resize(points.cols*points.rows*points.channels()/2);
1818     CvMat _points = Mat(points), _hull=Mat(hull);
1819     cvConvexHull2(&_points, &_hull, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 1);
1820     hull.resize(_hull.cols + _hull.rows - 1);
1821 }
1822
1823
1824 void cv::convexHull( const Mat& points,
1825                      vector<Point2f>& hull, bool clockwise )
1826 {
1827     CV_Assert(points.isContinuous() && points.depth() == CV_32F &&
1828               ((points.rows == 1 && points.channels() == 2) ||
1829                points.cols*points.channels() == 2));
1830     hull.resize(points.cols*points.rows*points.channels()/2);
1831     CvMat _points = Mat(points), _hull=Mat(hull);
1832     cvConvexHull2(&_points, &_hull, clockwise ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE, 1);
1833     hull.resize(_hull.cols + _hull.rows - 1);
1834 }
1835
1836 bool cv::isContourConvex( const Mat& contour )
1837 {
1838     CV_Assert(contour.isContinuous() &&
1839               (contour.depth() == CV_32S || contour.depth() == CV_32F) &&
1840               ((contour.rows == 1 && contour.channels() == 2) ||
1841                contour.cols*contour.channels() == 2));
1842     CvMat c = Mat(contour);
1843     return cvCheckContourConvexity(&c) > 0;
1844 }
1845
1846 cv::RotatedRect cv::fitEllipse( const Mat& points )
1847 {
1848     CV_Assert(points.isContinuous() &&
1849               (points.depth() == CV_32S || points.depth() == CV_32F) &&
1850               ((points.rows == 1 && points.channels() == 2) ||
1851                points.cols*points.channels() == 2));
1852     CvMat _points = points;
1853     return cvFitEllipse2(&_points);
1854 }
1855
1856
1857 void cv::fitLine( const Mat& points, Vec4f& line, int distType,
1858                   double param, double reps, double aeps )
1859 {
1860     CV_Assert(points.isContinuous() &&
1861               (points.depth() == CV_32S || points.depth() == CV_32F) &&
1862               ((points.rows == 1 && points.channels() == 2) ||
1863                points.cols*points.channels() == 2));
1864     CvMat _points = points;
1865     cvFitLine(&_points, distType, param, reps, aeps, &line[0]);
1866 }
1867
1868
1869 void cv::fitLine( const Mat& points, Vec6f& line, int distType,
1870                   double param, double reps, double aeps )
1871 {
1872     CV_Assert(points.isContinuous() &&
1873               (points.depth() == CV_32S || points.depth() == CV_32F) &&
1874               ((points.rows == 1 && points.channels() == 3) ||
1875                points.cols*points.channels() == 3));
1876     CvMat _points = points;
1877     cvFitLine(&_points, distType, param, reps, aeps, &line[0]);
1878 }
1879
1880 double cv::pointPolygonTest( const Mat& contour,
1881                              Point2f pt, bool measureDist )
1882 {
1883     CV_Assert(contour.isContinuous() &&
1884               (contour.depth() == CV_32S || contour.depth() == CV_32F) &&
1885               ((contour.rows == 1 && contour.channels() == 2) ||
1886                contour.cols*contour.channels() == 2));
1887     CvMat c = Mat(contour);
1888     return cvPointPolygonTest( &c, pt, measureDist );
1889 }
1890
1891 /* End of file. */