Home | History | Annotate | Download | only in src
      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_FROM_STATUS( CV_BADSIZE_ERR );
     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_FROM_STATUS( CV_BADRANGE_ERR );
    222 
    223     if( header_size < (int) (method == CV_CHAIN_CODE ? sizeof( CvChain ) : sizeof( CvContour )))
    224         CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
    225 
    226     scanner = (CvContourScanner)cvAlloc( sizeof( *scanner ));
    227     if( !scanner )
    228         CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
    229 
    230     memset( scanner, 0, sizeof( *scanner ));
    231 
    232     scanner->storage1 = scanner->storage2 = storage;
    233     scanner->img0 = (schar *) img;
    234     scanner->img = (schar *) (img + step);
    235     scanner->img_step = step;
    236     scanner->img_size.width = size.width - 1;   /* exclude rightest column */
    237     scanner->img_size.height = size.height - 1; /* exclude bottomost row */
    238     scanner->mode = mode;
    239     scanner->offset = offset;
    240     scanner->pt.x = scanner->pt.y = 1;
    241     scanner->lnbd.x = 0;
    242     scanner->lnbd.y = 1;
    243     scanner->nbd = 2;
    244     scanner->mode = (int) mode;
    245     scanner->frame_info.contour = &(scanner->frame);
    246     scanner->frame_info.is_hole = 1;
    247     scanner->frame_info.next = 0;
    248     scanner->frame_info.parent = 0;
    249     scanner->frame_info.rect = cvRect( 0, 0, size.width, size.height );
    250     scanner->l_cinfo = 0;
    251     scanner->subst_flag = 0;
    252 
    253     scanner->frame.flags = CV_SEQ_FLAG_HOLE;
    254 
    255     scanner->approx_method2 = scanner->approx_method1 = method;
    256 
    257     if( method == CV_CHAIN_APPROX_TC89_L1 || method == CV_CHAIN_APPROX_TC89_KCOS )
    258         scanner->approx_method1 = CV_CHAIN_CODE;
    259 
    260     if( scanner->approx_method1 == CV_CHAIN_CODE )
    261     {
    262         scanner->seq_type1 = CV_SEQ_CHAIN_CONTOUR;
    263         scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ?
    264             header_size : sizeof( CvChain );
    265         scanner->elem_size1 = sizeof( char );
    266     }
    267     else
    268     {
    269         scanner->seq_type1 = CV_SEQ_POLYGON;
    270         scanner->header_size1 = scanner->approx_method1 == scanner->approx_method2 ?
    271             header_size : sizeof( CvContour );
    272         scanner->elem_size1 = sizeof( CvPoint );
    273     }
    274 
    275     scanner->header_size2 = header_size;
    276 
    277     if( scanner->approx_method2 == CV_CHAIN_CODE )
    278     {
    279         scanner->seq_type2 = scanner->seq_type1;
    280         scanner->elem_size2 = scanner->elem_size1;
    281     }
    282     else
    283     {
    284         scanner->seq_type2 = CV_SEQ_POLYGON;
    285         scanner->elem_size2 = sizeof( CvPoint );
    286     }
    287 
    288     scanner->seq_type1 = scanner->approx_method1 == CV_CHAIN_CODE ?
    289         CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON;
    290 
    291     scanner->seq_type2 = scanner->approx_method2 == CV_CHAIN_CODE ?
    292         CV_SEQ_CHAIN_CONTOUR : CV_SEQ_POLYGON;
    293 
    294     cvSaveMemStoragePos( storage, &(scanner->initial_pos) );
    295 
    296     if( method > CV_CHAIN_APPROX_SIMPLE )
    297     {
    298         scanner->storage1 = cvCreateChildMemStorage( scanner->storage2 );
    299     }
    300 
    301     if( mode > CV_RETR_LIST )
    302     {
    303         scanner->cinfo_storage = cvCreateChildMemStorage( scanner->storage2 );
    304         scanner->cinfo_set = cvCreateSet( 0, sizeof( CvSet ), sizeof( _CvContourInfo ),
    305                                           scanner->cinfo_storage );
    306         if( scanner->cinfo_storage == 0 || scanner->cinfo_set == 0 )
    307             CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
    308     }
    309 
    310     /* make zero borders */
    311     memset( img, 0, size.width );
    312     memset( img + step * (size.height - 1), 0, size.width );
    313 
    314     for( y = 1, img += step; y < size.height - 1; y++, img += step )
    315     {
    316         img[0] = img[size.width - 1] = 0;
    317     }
    318 
    319     /* converts all pixels to 0 or 1 */
    320     cvThreshold( mat, mat, 0, 1, CV_THRESH_BINARY );
    321     CV_CHECK();
    322 
    323     __END__;
    324 
    325     if( cvGetErrStatus() < 0 )
    326         cvFree( &scanner );
    327 
    328     return scanner;
    329 }
    330 
    331 /*
    332    Final stage of contour processing.
    333    Three variants possible:
    334       1. Contour, which was retrieved using border following, is added to
    335          the contour tree. It is the case when the icvSubstituteContour function
    336          was not called after retrieving the contour.
    337 
    338       2. New contour, assigned by icvSubstituteContour function, is added to the
    339          tree. The retrieved contour itself is removed from the storage.
    340          Here two cases are possible:
    341             2a. If one deals with plane variant of algorithm
    342                 (hierarchical strucutre is not reconstructed),
    343                 the contour is removed completely.
    344             2b. In hierarchical case, the header of the contour is not removed.
    345                 It's marked as "link to contour" and h_next pointer of it is set to
    346                 new, substituting contour.
    347 
    348       3. The similar to 2, but when NULL pointer was assigned by
    349          icvSubstituteContour function. In this case, the function removes
    350          retrieved contour completely if plane case and
    351          leaves header if hierarchical (but doesn't mark header as "link").
    352       ------------------------------------------------------------------------
    353       The 1st variant can be used to retrieve and store all the contours from the image
    354       (with optional convertion from chains to contours using some approximation from
    355       restriced set of methods). Some characteristics of contour can be computed in the
    356       same pass.
    357 
    358       The usage scheme can look like:
    359 
    360       icvContourScanner scanner;
    361       CvMemStorage*  contour_storage;
    362       CvSeq*  first_contour;
    363       CvStatus  result;
    364 
    365       ...
    366 
    367       icvCreateMemStorage( &contour_storage, block_size/0 );
    368 
    369       ...
    370 
    371       cvStartFindContours
    372               ( img, contour_storage,
    373                 header_size, approx_method,
    374                 [external_only,]
    375                 &scanner );
    376 
    377       for(;;)
    378       {
    379           [CvSeq* contour;]
    380           result = icvFindNextContour( &scanner, &contour/0 );
    381 
    382           if( result != CV_OK ) break;
    383 
    384           // calculate some characteristics
    385           ...
    386       }
    387 
    388       if( result < 0 ) goto error_processing;
    389 
    390       cvEndFindContours( &scanner, &first_contour );
    391       ...
    392 
    393       -----------------------------------------------------------------
    394 
    395       Second variant is more complex and can be used when someone wants store not
    396       the retrieved contours but transformed ones. (e.g. approximated with some
    397       non-default algorithm ).
    398 
    399       The scheme can be the as following:
    400 
    401       icvContourScanner scanner;
    402       CvMemStorage*  contour_storage;
    403       CvMemStorage*  temp_storage;
    404       CvSeq*  first_contour;
    405       CvStatus  result;
    406 
    407       ...
    408 
    409       icvCreateMemStorage( &contour_storage, block_size/0 );
    410       icvCreateMemStorage( &temp_storage, block_size/0 );
    411 
    412       ...
    413 
    414       icvStartFindContours8uC1R
    415               ( <img_params>, temp_storage,
    416                 header_size, approx_method,
    417                 [retrival_mode],
    418                 &scanner );
    419 
    420       for(;;)
    421       {
    422           CvSeq* temp_contour;
    423           CvSeq* new_contour;
    424           result = icvFindNextContour( scanner, &temp_contour );
    425 
    426           if( result != CV_OK ) break;
    427 
    428           <approximation_function>( temp_contour, contour_storage,
    429                                     &new_contour, <parameters...> );
    430 
    431           icvSubstituteContour( scanner, new_contour );
    432           ...
    433       }
    434 
    435       if( result < 0 ) goto error_processing;
    436 
    437       cvEndFindContours( &scanner, &first_contour );
    438       ...
    439 
    440       ----------------------------------------------------------------------------
    441       Third method to retrieve contours may be applied if contours are irrelevant
    442       themselves but some characteristics of them are used only.
    443       The usage is similar to second except slightly different internal loop
    444 
    445       for(;;)
    446       {
    447           CvSeq* temp_contour;
    448           result = icvFindNextContour( &scanner, &temp_contour );
    449 
    450           if( result != CV_OK ) break;
    451 
    452           // calculate some characteristics of temp_contour
    453 
    454           icvSubstituteContour( scanner, 0 );
    455           ...
    456       }
    457 
    458       new_storage variable is not needed here.
    459 
    460       Two notes.
    461       1. Second and third method can interleave. I.e. it is possible to
    462          remain contours that satisfy with some criteria and reject others.
    463          In hierarchic case the resulting tree is the part of original tree with
    464          some nodes absent. But in the resulting tree the contour1 is a child
    465          (may be indirect) of contour2 iff in the original tree the contour1
    466          is a child (may be indirect) of contour2.
    467 */
    468 static void
    469 icvEndProcessContour( CvContourScanner scanner )
    470 {
    471     _CvContourInfo *l_cinfo = scanner->l_cinfo;
    472 
    473     if( l_cinfo )
    474     {
    475         if( scanner->subst_flag )
    476         {
    477             CvMemStoragePos temp;
    478 
    479             cvSaveMemStoragePos( scanner->storage2, &temp );
    480 
    481             if( temp.top == scanner->backup_pos2.top &&
    482                 temp.free_space == scanner->backup_pos2.free_space )
    483             {
    484                 cvRestoreMemStoragePos( scanner->storage2, &scanner->backup_pos );
    485             }
    486             scanner->subst_flag = 0;
    487         }
    488 
    489         if( l_cinfo->contour )
    490         {
    491             cvInsertNodeIntoTree( l_cinfo->contour, l_cinfo->parent->contour,
    492                                   &(scanner->frame) );
    493         }
    494         scanner->l_cinfo = 0;
    495     }
    496 }
    497 
    498 /* replaces one contour with another */
    499 CV_IMPL void
    500 cvSubstituteContour( CvContourScanner scanner, CvSeq * new_contour )
    501 {
    502     _CvContourInfo *l_cinfo;
    503 
    504     CV_FUNCNAME( "cvSubstituteContour" );
    505 
    506     __BEGIN__;
    507 
    508     if( !scanner )
    509         CV_ERROR( CV_StsNullPtr, "" );
    510 
    511     l_cinfo = scanner->l_cinfo;
    512     if( l_cinfo && l_cinfo->contour && l_cinfo->contour != new_contour )
    513     {
    514         l_cinfo->contour = new_contour;
    515         scanner->subst_flag = 1;
    516     }
    517 
    518     __END__;
    519 }
    520 
    521 
    522 /*
    523     marks domain border with +/-<constant> and stores the contour into CvSeq.
    524         method:
    525             <0  - chain
    526             ==0 - direct
    527             >0  - simple approximation
    528 */
    529 static CvStatus
    530 icvFetchContour( schar                  *ptr,
    531                  int                    step,
    532                  CvPoint                pt,
    533                  CvSeq*                 contour,
    534                  int    _method )
    535 {
    536     const schar     nbd = 2;
    537     int             deltas[16];
    538     CvSeqWriter     writer;
    539     schar           *i0 = ptr, *i1, *i3, *i4 = 0;
    540     int             prev_s = -1, s, s_end;
    541     int             method = _method - 1;
    542 
    543     assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
    544 
    545     /* initialize local state */
    546     CV_INIT_3X3_DELTAS( deltas, step, 1 );
    547     memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
    548 
    549     /* initialize writer */
    550     cvStartAppendToSeq( contour, &writer );
    551 
    552     if( method < 0 )
    553         ((CvChain *) contour)->origin = pt;
    554 
    555     s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
    556 
    557     do
    558     {
    559         s = (s - 1) & 7;
    560         i1 = i0 + deltas[s];
    561         if( *i1 != 0 )
    562             break;
    563     }
    564     while( s != s_end );
    565 
    566     if( s == s_end )            /* single pixel domain */
    567     {
    568         *i0 = (schar) (nbd | -128);
    569         if( method >= 0 )
    570         {
    571             CV_WRITE_SEQ_ELEM( pt, writer );
    572         }
    573     }
    574     else
    575     {
    576         i3 = i0;
    577         prev_s = s ^ 4;
    578 
    579         /* follow border */
    580         for( ;; )
    581         {
    582             s_end = s;
    583 
    584             for( ;; )
    585             {
    586                 i4 = i3 + deltas[++s];
    587                 if( *i4 != 0 )
    588                     break;
    589             }
    590             s &= 7;
    591 
    592             /* check "right" bound */
    593             if( (unsigned) (s - 1) < (unsigned) s_end )
    594             {
    595                 *i3 = (schar) (nbd | -128);
    596             }
    597             else if( *i3 == 1 )
    598             {
    599                 *i3 = nbd;
    600             }
    601 
    602             if( method < 0 )
    603             {
    604                 schar _s = (schar) s;
    605 
    606                 CV_WRITE_SEQ_ELEM( _s, writer );
    607             }
    608             else
    609             {
    610                 if( s != prev_s || method == 0 )
    611                 {
    612                     CV_WRITE_SEQ_ELEM( pt, writer );
    613                     prev_s = s;
    614                 }
    615 
    616                 pt.x += icvCodeDeltas[s].x;
    617                 pt.y += icvCodeDeltas[s].y;
    618 
    619             }
    620 
    621             if( i4 == i0 && i3 == i1 )
    622                 break;
    623 
    624             i3 = i4;
    625             s = (s + 4) & 7;
    626         }                       /* end of border following loop */
    627     }
    628 
    629     cvEndWriteSeq( &writer );
    630 
    631     if( _method != CV_CHAIN_CODE )
    632         cvBoundingRect( contour, 1 );
    633 
    634     assert( writer.seq->total == 0 && writer.seq->first == 0 ||
    635             writer.seq->total > writer.seq->first->count ||
    636             (writer.seq->first->prev == writer.seq->first &&
    637              writer.seq->first->next == writer.seq->first) );
    638 
    639     return CV_OK;
    640 }
    641 
    642 
    643 
    644 /*
    645    trace contour until certain point is met.
    646    returns 1 if met, 0 else.
    647 */
    648 static int
    649 icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole )
    650 {
    651     int deltas[16];
    652     schar *i0 = ptr, *i1, *i3, *i4;
    653     int s, s_end;
    654 
    655     /* initialize local state */
    656     CV_INIT_3X3_DELTAS( deltas, step, 1 );
    657     memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
    658 
    659     assert( (*i0 & -2) != 0 );
    660 
    661     s_end = s = is_hole ? 0 : 4;
    662 
    663     do
    664     {
    665         s = (s - 1) & 7;
    666         i1 = i0 + deltas[s];
    667         if( *i1 != 0 )
    668             break;
    669     }
    670     while( s != s_end );
    671 
    672     i3 = i0;
    673 
    674     /* check single pixel domain */
    675     if( s != s_end )
    676     {
    677         /* follow border */
    678         for( ;; )
    679         {
    680             s_end = s;
    681 
    682             for( ;; )
    683             {
    684                 i4 = i3 + deltas[++s];
    685                 if( *i4 != 0 )
    686                     break;
    687             }
    688 
    689             if( i3 == stop_ptr || (i4 == i0 && i3 == i1) )
    690                 break;
    691 
    692             i3 = i4;
    693             s = (s + 4) & 7;
    694         }                       /* end of border following loop */
    695     }
    696     return i3 == stop_ptr;
    697 }
    698 
    699 
    700 static CvStatus
    701 icvFetchContourEx( schar*               ptr,
    702                    int                  step,
    703                    CvPoint              pt,
    704                    CvSeq*               contour,
    705                    int  _method,
    706                    int                  nbd,
    707                    CvRect*              _rect )
    708 {
    709     int         deltas[16];
    710     CvSeqWriter writer;
    711     schar        *i0 = ptr, *i1, *i3, *i4;
    712     CvRect      rect;
    713     int         prev_s = -1, s, s_end;
    714     int         method = _method - 1;
    715 
    716     assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE );
    717     assert( 1 < nbd && nbd < 128 );
    718 
    719     /* initialize local state */
    720     CV_INIT_3X3_DELTAS( deltas, step, 1 );
    721     memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] ));
    722 
    723     /* initialize writer */
    724     cvStartAppendToSeq( contour, &writer );
    725 
    726     if( method < 0 )
    727         ((CvChain *)contour)->origin = pt;
    728 
    729     rect.x = rect.width = pt.x;
    730     rect.y = rect.height = pt.y;
    731 
    732     s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4;
    733 
    734     do
    735     {
    736         s = (s - 1) & 7;
    737         i1 = i0 + deltas[s];
    738         if( *i1 != 0 )
    739             break;
    740     }
    741     while( s != s_end );
    742 
    743     if( s == s_end )            /* single pixel domain */
    744     {
    745         *i0 = (schar) (nbd | 0x80);
    746         if( method >= 0 )
    747         {
    748             CV_WRITE_SEQ_ELEM( pt, writer );
    749         }
    750     }
    751     else
    752     {
    753         i3 = i0;
    754 
    755         prev_s = s ^ 4;
    756 
    757         /* follow border */
    758         for( ;; )
    759         {
    760             s_end = s;
    761 
    762             for( ;; )
    763             {
    764                 i4 = i3 + deltas[++s];
    765                 if( *i4 != 0 )
    766                     break;
    767             }
    768             s &= 7;
    769 
    770             /* check "right" bound */
    771             if( (unsigned) (s - 1) < (unsigned) s_end )
    772             {
    773                 *i3 = (schar) (nbd | 0x80);
    774             }
    775             else if( *i3 == 1 )
    776             {
    777                 *i3 = (schar) nbd;
    778             }
    779 
    780             if( method < 0 )
    781             {
    782                 schar _s = (schar) s;
    783                 CV_WRITE_SEQ_ELEM( _s, writer );
    784             }
    785             else if( s != prev_s || method == 0 )
    786             {
    787                 CV_WRITE_SEQ_ELEM( pt, writer );
    788             }
    789 
    790             if( s != prev_s )
    791             {
    792                 /* update bounds */
    793                 if( pt.x < rect.x )
    794                     rect.x = pt.x;
    795                 else if( pt.x > rect.width )
    796                     rect.width = pt.x;
    797 
    798                 if( pt.y < rect.y )
    799                     rect.y = pt.y;
    800                 else if( pt.y > rect.height )
    801                     rect.height = pt.y;
    802             }
    803 
    804             prev_s = s;
    805             pt.x += icvCodeDeltas[s].x;
    806             pt.y += icvCodeDeltas[s].y;
    807 
    808             if( i4 == i0 && i3 == i1 )  break;
    809 
    810             i3 = i4;
    811             s = (s + 4) & 7;
    812         }                       /* end of border following loop */
    813     }
    814 
    815     rect.width -= rect.x - 1;
    816     rect.height -= rect.y - 1;
    817 
    818     cvEndWriteSeq( &writer );
    819 
    820     if( _method != CV_CHAIN_CODE )
    821         ((CvContour*)contour)->rect = rect;
    822 
    823     assert( writer.seq->total == 0 && writer.seq->first == 0 ||
    824             writer.seq->total > writer.seq->first->count ||
    825             (writer.seq->first->prev == writer.seq->first &&
    826              writer.seq->first->next == writer.seq->first) );
    827 
    828     if( _rect )  *_rect = rect;
    829 
    830     return CV_OK;
    831 }
    832 
    833 
    834 CvSeq *
    835 cvFindNextContour( CvContourScanner scanner )
    836 {
    837     schar *img0;
    838     schar *img;
    839     int step;
    840     int width, height;
    841     int x, y;
    842     int prev;
    843     CvPoint lnbd;
    844     CvSeq *contour = 0;
    845     int nbd;
    846     int mode;
    847     CvStatus result = (CvStatus) 1;
    848 
    849     CV_FUNCNAME( "cvFindNextContour" );
    850 
    851     __BEGIN__;
    852 
    853     if( !scanner )
    854         CV_ERROR( CV_StsNullPtr, "" );
    855     icvEndProcessContour( scanner );
    856 
    857     /* initialize local state */
    858     img0 = scanner->img0;
    859     img = scanner->img;
    860     step = scanner->img_step;
    861     x = scanner->pt.x;
    862     y = scanner->pt.y;
    863     width = scanner->img_size.width;
    864     height = scanner->img_size.height;
    865     mode = scanner->mode;
    866     lnbd = scanner->lnbd;
    867     nbd = scanner->nbd;
    868 
    869     prev = img[x - 1];
    870 
    871     for( ; y < height; y++, img += step )
    872     {
    873         for( ; x < width; x++ )
    874         {
    875             int p = img[x];
    876 
    877             if( p != prev )
    878             {
    879                 _CvContourInfo *par_info = 0;
    880                 _CvContourInfo *l_cinfo = 0;
    881                 CvSeq *seq = 0;
    882                 int is_hole = 0;
    883                 CvPoint origin;
    884 
    885                 if( !(prev == 0 && p == 1) )    /* if not external contour */
    886                 {
    887                     /* check hole */
    888                     if( p != 0 || prev < 1 )
    889                         goto resume_scan;
    890 
    891                     if( prev & -2 )
    892                     {
    893                         lnbd.x = x - 1;
    894                     }
    895                     is_hole = 1;
    896                 }
    897 
    898                 if( mode == 0 && (is_hole || img0[lnbd.y * step + lnbd.x] > 0) )
    899                     goto resume_scan;
    900 
    901                 origin.y = y;
    902                 origin.x = x - is_hole;
    903 
    904                 /* find contour parent */
    905                 if( mode <= 1 || (!is_hole && mode == 2) || lnbd.x <= 0 )
    906                 {
    907                     par_info = &(scanner->frame_info);
    908                 }
    909                 else
    910                 {
    911                     int lval = img0[lnbd.y * step + lnbd.x] & 0x7f;
    912                     _CvContourInfo *cur = scanner->cinfo_table[lval - 2];
    913 
    914                     assert( lval >= 2 );
    915 
    916                     /* find the first bounding contour */
    917                     while( cur )
    918                     {
    919                         if( (unsigned) (lnbd.x - cur->rect.x) < (unsigned) cur->rect.width &&
    920                             (unsigned) (lnbd.y - cur->rect.y) < (unsigned) cur->rect.height )
    921                         {
    922                             if( par_info )
    923                             {
    924                                 if( icvTraceContour( scanner->img0 +
    925                                                      par_info->origin.y * step +
    926                                                      par_info->origin.x, step, img + lnbd.x,
    927                                                      par_info->is_hole ) > 0 )
    928                                     break;
    929                             }
    930                             par_info = cur;
    931                         }
    932                         cur = cur->next;
    933                     }
    934 
    935                     assert( par_info != 0 );
    936 
    937                     /* if current contour is a hole and previous contour is a hole or
    938                        current contour is external and previous contour is external then
    939                        the parent of the contour is the parent of the previous contour else
    940                        the parent is the previous contour itself. */
    941                     if( par_info->is_hole == is_hole )
    942                     {
    943                         par_info = par_info->parent;
    944                         /* every contour must have a parent
    945                            (at least, the frame of the image) */
    946                         if( !par_info )
    947                             par_info = &(scanner->frame_info);
    948                     }
    949 
    950                     /* hole flag of the parent must differ from the flag of the contour */
    951                     assert( par_info->is_hole != is_hole );
    952                     if( par_info->contour == 0 )        /* removed contour */
    953                         goto resume_scan;
    954                 }
    955 
    956                 lnbd.x = x - is_hole;
    957 
    958                 cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos) );
    959 
    960                 seq = cvCreateSeq( scanner->seq_type1, scanner->header_size1,
    961                                    scanner->elem_size1, scanner->storage1 );
    962                 if( !seq )
    963                 {
    964                     result = CV_OUTOFMEM_ERR;
    965                     goto exit_func;
    966                 }
    967                 seq->flags |= is_hole ? CV_SEQ_FLAG_HOLE : 0;
    968 
    969                 /* initialize header */
    970                 if( mode <= 1 )
    971                 {
    972                     l_cinfo = &(scanner->cinfo_temp);
    973                     result = icvFetchContour( img + x - is_hole, step,
    974                                               cvPoint( origin.x + scanner->offset.x,
    975                                                        origin.y + scanner->offset.y),
    976                                               seq, scanner->approx_method1 );
    977                     if( result < 0 )
    978                         goto exit_func;
    979                 }
    980                 else
    981                 {
    982                     union { _CvContourInfo* ci; CvSetElem* se; } v;
    983                     v.ci = l_cinfo;
    984                     cvSetAdd( scanner->cinfo_set, 0, &v.se );
    985                     l_cinfo = v.ci;
    986 
    987                     result = icvFetchContourEx( img + x - is_hole, step,
    988                                                 cvPoint( origin.x + scanner->offset.x,
    989                                                          origin.y + scanner->offset.y),
    990                                                 seq, scanner->approx_method1,
    991                                                 nbd, &(l_cinfo->rect) );
    992                     if( result < 0 )
    993                         goto exit_func;
    994                     l_cinfo->rect.x -= scanner->offset.x;
    995                     l_cinfo->rect.y -= scanner->offset.y;
    996 
    997                     l_cinfo->next = scanner->cinfo_table[nbd - 2];
    998                     scanner->cinfo_table[nbd - 2] = l_cinfo;
    999 
   1000                     /* change nbd */
   1001                     nbd = (nbd + 1) & 127;
   1002                     nbd += nbd == 0 ? 3 : 0;
   1003                 }
   1004 
   1005                 l_cinfo->is_hole = is_hole;
   1006                 l_cinfo->contour = seq;
   1007                 l_cinfo->origin = origin;
   1008                 l_cinfo->parent = par_info;
   1009 
   1010                 if( scanner->approx_method1 != scanner->approx_method2 )
   1011                 {
   1012                     result = icvApproximateChainTC89( (CvChain *) seq,
   1013                                                       scanner->header_size2,
   1014                                                       scanner->storage2,
   1015                                                       &(l_cinfo->contour),
   1016                                                       scanner->approx_method2 );
   1017                     if( result < 0 )
   1018                         goto exit_func;
   1019                     cvClearMemStorage( scanner->storage1 );
   1020                 }
   1021 
   1022                 l_cinfo->contour->v_prev = l_cinfo->parent->contour;
   1023 
   1024                 if( par_info->contour == 0 )
   1025                 {
   1026                     l_cinfo->contour = 0;
   1027                     if( scanner->storage1 == scanner->storage2 )
   1028                     {
   1029                         cvRestoreMemStoragePos( scanner->storage1, &(scanner->backup_pos) );
   1030                     }
   1031                     else
   1032                     {
   1033                         cvClearMemStorage( scanner->storage1 );
   1034                     }
   1035                     p = img[x];
   1036                     goto resume_scan;
   1037                 }
   1038 
   1039                 cvSaveMemStoragePos( scanner->storage2, &(scanner->backup_pos2) );
   1040                 scanner->l_cinfo = l_cinfo;
   1041                 scanner->pt.x = x + 1;
   1042                 scanner->pt.y = y;
   1043                 scanner->lnbd = lnbd;
   1044                 scanner->img = (schar *) img;
   1045                 scanner->nbd = nbd;
   1046                 contour = l_cinfo->contour;
   1047 
   1048                 result = CV_OK;
   1049                 goto exit_func;
   1050               resume_scan:
   1051                 prev = p;
   1052                 /* update lnbd */
   1053                 if( prev & -2 )
   1054                 {
   1055                     lnbd.x = x;
   1056                 }
   1057             }                   /* end of prev != p */
   1058         }                       /* end of loop on x */
   1059 
   1060         lnbd.x = 0;
   1061         lnbd.y = y + 1;
   1062         x = 1;
   1063         prev = 0;
   1064 
   1065     }                           /* end of loop on y */
   1066 
   1067   exit_func:
   1068 
   1069     if( result != 0 )
   1070         contour = 0;
   1071     if( result < 0 )
   1072         CV_ERROR_FROM_STATUS( result );
   1073 
   1074     __END__;
   1075 
   1076     return contour;
   1077 }
   1078 
   1079 
   1080 /*
   1081    The function add to tree the last retrieved/substituted contour,
   1082    releases temp_storage, restores state of dst_storage (if needed), and
   1083    returns pointer to root of the contour tree */
   1084 CV_IMPL CvSeq *
   1085 cvEndFindContours( CvContourScanner * _scanner )
   1086 {
   1087     CvContourScanner scanner;
   1088     CvSeq *first = 0;
   1089 
   1090     CV_FUNCNAME( "cvFindNextContour" );
   1091 
   1092     __BEGIN__;
   1093 
   1094     if( !_scanner )
   1095         CV_ERROR( CV_StsNullPtr, "" );
   1096     scanner = *_scanner;
   1097 
   1098     if( scanner )
   1099     {
   1100         icvEndProcessContour( scanner );
   1101 
   1102         if( scanner->storage1 != scanner->storage2 )
   1103             cvReleaseMemStorage( &(scanner->storage1) );
   1104 
   1105         if( scanner->cinfo_storage )
   1106             cvReleaseMemStorage( &(scanner->cinfo_storage) );
   1107 
   1108         first = scanner->frame.v_next;
   1109         cvFree( _scanner );
   1110     }
   1111 
   1112     __END__;
   1113 
   1114     return first;
   1115 }
   1116 
   1117 
   1118 #define ICV_SINGLE                  0
   1119 #define ICV_CONNECTING_ABOVE        1
   1120 #define ICV_CONNECTING_BELOW        -1
   1121 #define ICV_IS_COMPONENT_POINT(val) ((val) != 0)
   1122 
   1123 #define CV_GET_WRITTEN_ELEM( writer ) ((writer).ptr - (writer).seq->elem_size)
   1124 
   1125 typedef  struct CvLinkedRunPoint
   1126 {
   1127     struct CvLinkedRunPoint* link;
   1128     struct CvLinkedRunPoint* next;
   1129     CvPoint pt;
   1130 }
   1131 CvLinkedRunPoint;
   1132 
   1133 
   1134 static int
   1135 icvFindContoursInInterval( const CvArr* src,
   1136                            /*int minValue, int maxValue,*/
   1137                            CvMemStorage* storage,
   1138                            CvSeq** result,
   1139                            int contourHeaderSize )
   1140 {
   1141     int count = 0;
   1142     CvMemStorage* storage00 = 0;
   1143     CvMemStorage* storage01 = 0;
   1144     CvSeq* first = 0;
   1145 
   1146     CV_FUNCNAME( "icvFindContoursInInterval" );
   1147 
   1148     __BEGIN__;
   1149 
   1150     int i, j, k, n;
   1151 
   1152     uchar*  src_data = 0;
   1153     int  img_step = 0;
   1154     CvSize  img_size;
   1155 
   1156     int  connect_flag;
   1157     int  lower_total;
   1158     int  upper_total;
   1159     int  all_total;
   1160 
   1161     CvSeq*  runs;
   1162     CvLinkedRunPoint  tmp;
   1163     CvLinkedRunPoint*  tmp_prev;
   1164     CvLinkedRunPoint*  upper_line = 0;
   1165     CvLinkedRunPoint*  lower_line = 0;
   1166     CvLinkedRunPoint*  last_elem;
   1167 
   1168     CvLinkedRunPoint*  upper_run = 0;
   1169     CvLinkedRunPoint*  lower_run = 0;
   1170     CvLinkedRunPoint*  prev_point = 0;
   1171 
   1172     CvSeqWriter  writer_ext;
   1173     CvSeqWriter  writer_int;
   1174     CvSeqWriter  writer;
   1175     CvSeqReader  reader;
   1176 
   1177     CvSeq* external_contours;
   1178     CvSeq* internal_contours;
   1179     CvSeq* prev = 0;
   1180 
   1181     if( !storage )
   1182         CV_ERROR( CV_StsNullPtr, "NULL storage pointer" );
   1183 
   1184     if( !result )
   1185         CV_ERROR( CV_StsNullPtr, "NULL double CvSeq pointer" );
   1186 
   1187     if( contourHeaderSize < (int)sizeof(CvContour))
   1188         CV_ERROR( CV_StsBadSize, "Contour header size must be >= sizeof(CvContour)" );
   1189 
   1190     CV_CALL( storage00 = cvCreateChildMemStorage(storage));
   1191     CV_CALL( storage01 = cvCreateChildMemStorage(storage));
   1192 
   1193     {
   1194         CvMat stub, *mat;
   1195 
   1196         CV_CALL( mat = cvGetMat( src, &stub ));
   1197         if( !CV_IS_MASK_ARR(mat))
   1198             CV_ERROR( CV_StsBadArg, "Input array must be 8uC1 or 8sC1" );
   1199         src_data = mat->data.ptr;
   1200         img_step = mat->step;
   1201         img_size = cvGetMatSize( mat );
   1202     }
   1203 
   1204     // Create temporary sequences
   1205     runs = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvLinkedRunPoint), storage00 );
   1206     cvStartAppendToSeq( runs, &writer );
   1207 
   1208     cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_ext );
   1209     cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_int );
   1210 
   1211     tmp_prev = &(tmp);
   1212     tmp_prev->next = 0;
   1213     tmp_prev->link = 0;
   1214 
   1215     // First line. None of runs is binded
   1216     tmp.pt.y = 0;
   1217     i = 0;
   1218     CV_WRITE_SEQ_ELEM( tmp, writer );
   1219     upper_line = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
   1220 
   1221     tmp_prev = upper_line;
   1222     for( j = 0; j < img_size.width; )
   1223     {
   1224         for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
   1225             ;
   1226         if( j == img_size.width )
   1227             break;
   1228 
   1229         tmp.pt.x = j;
   1230         CV_WRITE_SEQ_ELEM( tmp, writer );
   1231         tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
   1232         tmp_prev = tmp_prev->next;
   1233 
   1234         for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
   1235             ;
   1236 
   1237         tmp.pt.x = j-1;
   1238         CV_WRITE_SEQ_ELEM( tmp, writer );
   1239         tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
   1240         tmp_prev->link = tmp_prev->next;
   1241         // First point of contour
   1242         CV_WRITE_SEQ_ELEM( tmp_prev, writer_ext );
   1243         tmp_prev = tmp_prev->next;
   1244     }
   1245     cvFlushSeqWriter( &writer );
   1246     upper_line = upper_line->next;
   1247     upper_total = runs->total - 1;
   1248     last_elem = tmp_prev;
   1249     tmp_prev->next = 0;
   1250 
   1251     for( i = 1; i < img_size.height; i++ )
   1252     {
   1253 //------// Find runs in next line
   1254         src_data += img_step;
   1255         tmp.pt.y = i;
   1256         all_total = runs->total;
   1257         for( j = 0; j < img_size.width; )
   1258         {
   1259             for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
   1260                 ;
   1261             if( j == img_size.width ) break;
   1262 
   1263             tmp.pt.x = j;
   1264             CV_WRITE_SEQ_ELEM( tmp, writer );
   1265             tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
   1266             tmp_prev = tmp_prev->next;
   1267 
   1268             for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
   1269                 ;
   1270 
   1271             tmp.pt.x = j-1;
   1272             CV_WRITE_SEQ_ELEM( tmp, writer );
   1273             tmp_prev = tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
   1274         }//j
   1275         cvFlushSeqWriter( &writer );
   1276         lower_line = last_elem->next;
   1277         lower_total = runs->total - all_total;
   1278         last_elem = tmp_prev;
   1279         tmp_prev->next = 0;
   1280 //------//
   1281 //------// Find links between runs of lower_line and upper_line
   1282         upper_run = upper_line;
   1283         lower_run = lower_line;
   1284         connect_flag = ICV_SINGLE;
   1285 
   1286         for( k = 0, n = 0; k < upper_total/2 && n < lower_total/2; )
   1287         {
   1288             switch( connect_flag )
   1289             {
   1290             case ICV_SINGLE:
   1291                 if( upper_run->next->pt.x < lower_run->next->pt.x )
   1292                 {
   1293                     if( upper_run->next->pt.x >= lower_run->pt.x  -1 )
   1294                     {
   1295                         lower_run->link = upper_run;
   1296                         connect_flag = ICV_CONNECTING_ABOVE;
   1297                         prev_point = upper_run->next;
   1298                     }
   1299                     else
   1300                         upper_run->next->link = upper_run;
   1301                     k++;
   1302                     upper_run = upper_run->next->next;
   1303                 }
   1304                 else
   1305                 {
   1306                     if( upper_run->pt.x <= lower_run->next->pt.x  +1 )
   1307                     {
   1308                         lower_run->link = upper_run;
   1309                         connect_flag = ICV_CONNECTING_BELOW;
   1310                         prev_point = lower_run->next;
   1311                     }
   1312                     else
   1313                     {
   1314                         lower_run->link = lower_run->next;
   1315                         // First point of contour
   1316                         CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
   1317                     }
   1318                     n++;
   1319                     lower_run = lower_run->next->next;
   1320                 }
   1321                 break;
   1322             case ICV_CONNECTING_ABOVE:
   1323                 if( upper_run->pt.x > lower_run->next->pt.x +1 )
   1324                 {
   1325                     prev_point->link = lower_run->next;
   1326                     connect_flag = ICV_SINGLE;
   1327                     n++;
   1328                     lower_run = lower_run->next->next;
   1329                 }
   1330                 else
   1331                 {
   1332                     prev_point->link = upper_run;
   1333                     if( upper_run->next->pt.x < lower_run->next->pt.x )
   1334                     {
   1335                         k++;
   1336                         prev_point = upper_run->next;
   1337                         upper_run = upper_run->next->next;
   1338                     }
   1339                     else
   1340                     {
   1341                         connect_flag = ICV_CONNECTING_BELOW;
   1342                         prev_point = lower_run->next;
   1343                         n++;
   1344                         lower_run = lower_run->next->next;
   1345                     }
   1346                 }
   1347                 break;
   1348             case ICV_CONNECTING_BELOW:
   1349                 if( lower_run->pt.x > upper_run->next->pt.x +1 )
   1350                 {
   1351                     upper_run->next->link = prev_point;
   1352                     connect_flag = ICV_SINGLE;
   1353                     k++;
   1354                     upper_run = upper_run->next->next;
   1355                 }
   1356                 else
   1357                 {
   1358                     // First point of contour
   1359                     CV_WRITE_SEQ_ELEM( lower_run, writer_int );
   1360 
   1361                     lower_run->link = prev_point;
   1362                     if( lower_run->next->pt.x < upper_run->next->pt.x )
   1363                     {
   1364                         n++;
   1365                         prev_point = lower_run->next;
   1366                         lower_run = lower_run->next->next;
   1367                     }
   1368                     else
   1369                     {
   1370                         connect_flag = ICV_CONNECTING_ABOVE;
   1371                         k++;
   1372                         prev_point = upper_run->next;
   1373                         upper_run = upper_run->next->next;
   1374                     }
   1375                 }
   1376                 break;
   1377             }
   1378         }// k, n
   1379 
   1380         for( ; n < lower_total/2; n++ )
   1381         {
   1382             if( connect_flag != ICV_SINGLE )
   1383             {
   1384                 prev_point->link = lower_run->next;
   1385                 connect_flag = ICV_SINGLE;
   1386                 lower_run = lower_run->next->next;
   1387                 continue;
   1388             }
   1389             lower_run->link = lower_run->next;
   1390 
   1391             //First point of contour
   1392             CV_WRITE_SEQ_ELEM( lower_run, writer_ext );
   1393 
   1394             lower_run = lower_run->next->next;
   1395         }
   1396 
   1397         for( ; k < upper_total/2; k++ )
   1398         {
   1399             if( connect_flag != ICV_SINGLE )
   1400             {
   1401                 upper_run->next->link = prev_point;
   1402                 connect_flag = ICV_SINGLE;
   1403                 upper_run = upper_run->next->next;
   1404                 continue;
   1405             }
   1406             upper_run->next->link = upper_run;
   1407             upper_run = upper_run->next->next;
   1408         }
   1409         upper_line = lower_line;
   1410         upper_total = lower_total;
   1411     }//i
   1412 
   1413     upper_run = upper_line;
   1414 
   1415     //the last line of image
   1416     for( k = 0; k < upper_total/2; k++ )
   1417     {
   1418         upper_run->next->link = upper_run;
   1419         upper_run = upper_run->next->next;
   1420     }
   1421 
   1422 //------//
   1423 //------//Find end read contours
   1424     external_contours = cvEndWriteSeq( &writer_ext );
   1425     internal_contours = cvEndWriteSeq( &writer_int );
   1426 
   1427     for( k = 0; k < 2; k++ )
   1428     {
   1429         CvSeq* contours = k == 0 ? external_contours : internal_contours;
   1430 
   1431         cvStartReadSeq( contours, &reader );
   1432 
   1433         for( j = 0; j < contours->total; j++, count++ )
   1434         {
   1435             CvLinkedRunPoint* p_temp;
   1436             CvLinkedRunPoint* p00;
   1437             CvLinkedRunPoint* p01;
   1438             CvSeq* contour;
   1439 
   1440             CV_READ_SEQ_ELEM( p00, reader );
   1441             p01 = p00;
   1442 
   1443             if( !p00->link )
   1444                 continue;
   1445 
   1446             cvStartWriteSeq( CV_SEQ_ELTYPE_POINT | CV_SEQ_POLYLINE | CV_SEQ_FLAG_CLOSED,
   1447                              contourHeaderSize, sizeof(CvPoint), storage, &writer );
   1448             do
   1449             {
   1450                 CV_WRITE_SEQ_ELEM( p00->pt, writer );
   1451                 p_temp = p00;
   1452                 p00 = p00->link;
   1453                 p_temp->link = 0;
   1454             }
   1455             while( p00 != p01 );
   1456 
   1457             contour = cvEndWriteSeq( &writer );
   1458             cvBoundingRect( contour, 1 );
   1459 
   1460             if( k != 0 )
   1461                 contour->flags |= CV_SEQ_FLAG_HOLE;
   1462 
   1463             if( !first )
   1464                 prev = first = contour;
   1465             else
   1466             {
   1467                 contour->h_prev = prev;
   1468                 prev = prev->h_next = contour;
   1469             }
   1470         }
   1471     }
   1472 
   1473     __END__;
   1474 
   1475     if( !first )
   1476         count = -1;
   1477 
   1478     if( result )
   1479         *result = first;
   1480 
   1481     cvReleaseMemStorage(&storage00);
   1482     cvReleaseMemStorage(&storage01);
   1483 
   1484     return count;
   1485 }
   1486 
   1487 
   1488 
   1489 /*F///////////////////////////////////////////////////////////////////////////////////////
   1490 //    Name: cvFindContours
   1491 //    Purpose:
   1492 //      Finds all the contours on the bi-level image.
   1493 //    Context:
   1494 //    Parameters:
   1495 //      img  - source image.
   1496 //             Non-zero pixels are considered as 1-pixels
   1497 //             and zero pixels as 0-pixels.
   1498 //      step - full width of source image in bytes.
   1499 //      size - width and height of the image in pixels
   1500 //      storage - pointer to storage where will the output contours be placed.
   1501 //      header_size - header size of resulting contours
   1502 //      mode - mode of contour retrieval.
   1503 //      method - method of approximation that is applied to contours
   1504 //      first_contour - pointer to first contour pointer
   1505 //    Returns:
   1506 //      CV_OK or error code
   1507 //    Notes:
   1508 //F*/
   1509 CV_IMPL int
   1510 cvFindContours( void*  img,  CvMemStorage*  storage,
   1511                 CvSeq**  firstContour, int  cntHeaderSize,
   1512                 int  mode,
   1513                 int  method, CvPoint offset )
   1514 {
   1515     CvContourScanner scanner = 0;
   1516     CvSeq *contour = 0;
   1517     int count = -1;
   1518 
   1519     CV_FUNCNAME( "cvFindContours" );
   1520 
   1521     __BEGIN__;
   1522 
   1523     if( !firstContour )
   1524         CV_ERROR( CV_StsNullPtr, "NULL double CvSeq pointer" );
   1525 
   1526     if( method == CV_LINK_RUNS )
   1527     {
   1528         if( offset.x != 0 || offset.y != 0 )
   1529             CV_ERROR( CV_StsOutOfRange,
   1530             "Nonzero offset is not supported in CV_LINK_RUNS yet" );
   1531 
   1532         CV_CALL( count = icvFindContoursInInterval( img, storage,
   1533                                     firstContour, cntHeaderSize ));
   1534     }
   1535     else
   1536     {
   1537         CV_CALL( scanner = cvStartFindContours( img, storage,
   1538                         cntHeaderSize, mode, method, offset ));
   1539         assert( scanner );
   1540 
   1541         do
   1542         {
   1543             count++;
   1544             contour = cvFindNextContour( scanner );
   1545         }
   1546         while( contour != 0 );
   1547 
   1548         *firstContour = cvEndFindContours( &scanner );
   1549     }
   1550 
   1551     __END__;
   1552 
   1553     return count;
   1554 }
   1555 
   1556 
   1557 /* End of file. */
   1558