/* trace contour until certain point is met. returns 1 if met, 0 else. */ static int icvTraceContour( char *ptr, int step, char *stop_ptr, int is_hole ) { int deltas[16]; char *i0 = ptr, *i1, *i3, *i4; int s, s_end; /* initialize local state */ CV_INIT_3X3_DELTAS( deltas, step, 1 ); memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] )); assert( (*i0 & -2) != 0 ); s_end = s = is_hole ? 0 : 4; do { s = (s - 1) & 7; i1 = i0 + deltas[s]; if( *i1 != 0 ) break; } while( s != s_end ); i3 = i0; /* check single pixel domain */ if( s != s_end ) { /* follow border */ for( ;; ) { s_end = s; for( ;; ) { i4 = i3 + deltas[++s]; if( *i4 != 0 ) break; } if( i3 == stop_ptr || (i4 == i0 && i3 == i1) ) break; i3 = i4; s = (s + 4) & 7; } /* end of border following loop */ } return i3 == stop_ptr; }
static CvSeq* icvGetComponent(uchar* img, int step, CvRect rect, CvMemStorage* storage) { const char nbd = 4; int deltas[16]; int x, y; CvSeq* exterior = 0; char* ptr; /* initialize local state */ CV_INIT_3X3_DELTAS(deltas, step, 1); memcpy(deltas + 8, deltas, 8 * sizeof(deltas[0])); ptr = (char*)(img + step * rect.y); rect.width += rect.x; rect.height += rect.y; for (y = rect.y; y < rect.height; y++, ptr += step) { int prev = ptr[rect.x - 1] & -2; for (x = rect.x; x < rect.width; x++) { int p = ptr[x] & -2; //assert( exterior || ((p | prev) & -4) == 0 ); if (p != prev) { CvSeq* seq = 0; int is_hole = 0; CvSeqWriter writer; char* i0, *i1, *i3, *i4 = 0; int prev_s = -1, s, s_end; CvPoint pt = { x, y }; if (!(prev == 0 && p == 2)) { /* if not external contour */ /* check hole */ if (p != 0 || prev < 1) { prev = p; continue; } is_hole = 1; if (!exterior) { assert(0); return 0; } } cvStartWriteSeq(CV_SEQ_CONTOUR | (is_hole ? CV_SEQ_FLAG_HOLE : 0), sizeof(CvContour), sizeof(CvPoint), storage, &writer); s_end = s = is_hole ? 0 : 4; i0 = ptr + x - is_hole; do { s = (s - 1) & 7; i1 = i0 + deltas[s]; if ((*i1 & -2) != 0) { break; } } while (s != s_end); if (s == s_end) { /* single pixel domain */ *i0 = (char)(nbd | -128); CV_WRITE_SEQ_ELEM(pt, writer); } else { i3 = i0; prev_s = s ^ 4; /* follow border */ for (;;) { s_end = s; for (;;) { i4 = i3 + deltas[++s]; if ((*i4 & -2) != 0) { break; } } s &= 7; /* check "right" bound */ if ((unsigned)(s - 1) < (unsigned) s_end) { *i3 = (char)(nbd | -128); } else if (*i3 > 0) { *i3 = nbd; } if (s != prev_s) { CV_WRITE_SEQ_ELEM(pt, writer); prev_s = s; } pt.x += icvCodeDeltas[s].x; pt.y += icvCodeDeltas[s].y; if (i4 == i0 && i3 == i1) { break; } i3 = i4; s = (s + 4) & 7; } /* end of border following loop */ } seq = cvEndWriteSeq(&writer); cvContourBoundingRect(seq, 1); if (!is_hole) { exterior = seq; } else { seq->v_prev = exterior; seq->h_next = exterior->v_next; if (seq->h_next) { seq->h_next->h_prev = seq; } exterior->v_next = seq; } prev = ptr[x] & -2; } } } return exterior; }
static CvStatus icvFetchContourEx( char* ptr, int step, CvPoint pt, CvSeq* contour, int _method, int nbd, CvRect* _rect ) { int deltas[16]; CvSeqWriter writer; char *i0 = ptr, *i1, *i3, *i4; CvRect rect; int prev_s = -1, s, s_end; int method = _method - 1; assert( (unsigned) _method <= CV_CHAIN_APPROX_SIMPLE ); assert( 1 < nbd && nbd < 128 ); /* initialize local state */ CV_INIT_3X3_DELTAS( deltas, step, 1 ); memcpy( deltas + 8, deltas, 8 * sizeof( deltas[0] )); /* initialize writer */ cvStartAppendToSeq( contour, &writer ); if( method < 0 ) ((CvChain *)contour)->origin = pt; rect.x = rect.width = pt.x; rect.y = rect.height = pt.y; s_end = s = CV_IS_SEQ_HOLE( contour ) ? 0 : 4; do { s = (s - 1) & 7; i1 = i0 + deltas[s]; if( *i1 != 0 ) break; } while( s != s_end ); if( s == s_end ) /* single pixel domain */ { *i0 = (char) (nbd | 0x80); if( method >= 0 ) { CV_WRITE_SEQ_ELEM( pt, writer ); } } else { i3 = i0; prev_s = s ^ 4; /* follow border */ for( ;; ) { s_end = s; for( ;; ) { i4 = i3 + deltas[++s]; if( *i4 != 0 ) break; } s &= 7; /* check "right" bound */ if( (unsigned) (s - 1) < (unsigned) s_end ) { *i3 = (char) (nbd | 0x80); } else if( *i3 == 1 ) { *i3 = (char) nbd; } if( method < 0 ) { char _s = (char) s; CV_WRITE_SEQ_ELEM( _s, writer ); } else if( s != prev_s || method == 0 ) { CV_WRITE_SEQ_ELEM( pt, writer ); } if( s != prev_s ) { /* update bounds */ if( pt.x < rect.x ) rect.x = pt.x; else if( pt.x > rect.width ) rect.width = pt.x; if( pt.y < rect.y ) rect.y = pt.y; else if( pt.y > rect.height ) rect.height = pt.y; } prev_s = s; pt.x += icvCodeDeltas[s].x; pt.y += icvCodeDeltas[s].y; if( i4 == i0 && i3 == i1 ) break; i3 = i4; s = (s + 4) & 7; } /* end of border following loop */ } rect.width -= rect.x - 1; rect.height -= rect.y - 1; cvEndWriteSeq( &writer ); if( _method != CV_CHAIN_CODE ) ((CvContour*)contour)->rect = rect; assert( writer.seq->total == 0 && writer.seq->first == 0 || writer.seq->total > writer.seq->first->count || (writer.seq->first->prev == writer.seq->first && writer.seq->first->next == writer.seq->first) ); if( _rect ) *_rect = rect; return CV_OK; }