关于轮廓的遍历,如何解释cvDrawContours函数及相关的数据结构是如何实现轮廓遍历的

来源:互联网 发布:网络教育统考报名网址 编辑:程序博客网 时间:2024/05/13 14:24
下面代码1能够覆盖所有轮廓,但是代码2当出现多个环套接在一起(类似箭靶子的样子)时,就不能把内部的轮廓遍历到
代码1,原版opencv的cvDrawContours函数:
CV_IMPL void
cvDrawContours( void* _img, CvSeq* contour,
CvScalar _externalColor, CvScalar _holeColor, 
int maxLevel, int thickness,
int line_type, CvPoint _offset )
{
CvSeq *contour0 = contour, *h_next = 0;
CvTreeNodeIterator iterator;
cv::vector<cv::PolyEdge> edges;
cv::vector<cv::Point> pts;
cv::Scalar externalColor = _externalColor, holeColor = _holeColor;
cv::Mat img = cv::cvarrToMat(_img);
cv::Point offset = _offset;
double ext_buf[4], hole_buf[4];

if( line_type == CV_AA && img.depth() != CV_8U )
line_type = 8;

if( !contour )
return;

CV_Assert( thickness <= 255 );

scalarToRawData( externalColor, ext_buf, img.type(), 0 );
scalarToRawData( holeColor, hole_buf, img.type(), 0 );

maxLevel = MAX(maxLevel, INT_MIN+2);
maxLevel = MIN(maxLevel, INT_MAX-1);

if( maxLevel < 0 )
{
h_next = contour->h_next;
contour->h_next = 0;
maxLevel = -maxLevel+1;
}

cvInitTreeNodeIterator( &iterator, contour, maxLevel );
while( (contour = (CvSeq*)cvNextTreeNode( &iterator )) != 0 )
{
CvSeqReader reader;
int i, count = contour->total;
int elem_type = CV_MAT_TYPE(contour->flags);
void* clr = (contour->flags & CV_SEQ_FLAG_HOLE) == 0 ? ext_buf : hole_buf;

cvStartReadSeq( contour, &reader, 0 );
if( thickness < 0 )
pts.resize(0);

if( CV_IS_SEQ_CHAIN_CONTOUR( contour ))
{
cv::Point pt = ((CvChain*)contour)->origin;
cv::Point prev_pt = pt;
char prev_code = reader.ptr ? reader.ptr[0] : '\0';

prev_pt += offset;

for( i = 0; i < count; i++ )
{
char code;
CV_READ_SEQ_ELEM( code, reader );

assert( (code & ~7) == 0 );

if( code != prev_code )
{
prev_code = code;
if( thickness >= 0 )
cv::ThickLine( img, prev_pt, pt, clr, thickness, line_type, 2, 0 );
else
pts.push_back(pt);
prev_pt = pt;
}

pt.x += CodeDeltas[(int)code][0];
pt.y += CodeDeltas[(int)code][1];
}

if( thickness >= 0 )
cv::ThickLine( img, prev_pt,
cv::Point(((CvChain*)contour)->origin) + offset,
clr, thickness, line_type, 2, 0 );
else
cv::CollectPolyEdges(img, &pts[0], (int)pts.size(),
edges, ext_buf, line_type, 0, offset);
}
else if( CV_IS_SEQ_POLYLINE( contour ))
{
CV_Assert( elem_type == CV_32SC2 );
cv::Point pt1, pt2;
int shift = 0;

count -= !CV_IS_SEQ_CLOSED(contour);
CV_READ_SEQ_ELEM( pt1, reader );
pt1 += offset;
if( thickness < 0 )
pts.push_back(pt1);

for( i = 0; i < count; i++ )
{
CV_READ_SEQ_ELEM( pt2, reader );
pt2 += offset;
if( thickness >= 0 )
cv::ThickLine( img, pt1, pt2, clr, thickness, line_type, 2, shift );
else
pts.push_back(pt2);
pt1 = pt2;
}
if( thickness < 0 )
cv::CollectPolyEdges( img, &pts[0], (int)pts.size(),
edges, ext_buf, line_type, 0, cv::Point() );
}
}

if( thickness < 0 )
cv::FillEdgeCollection( img, edges, ext_buf );

if( h_next && contour0 )
contour0->h_next = h_next;
}
代码2,简化的遍历代码:
////////////////////////////////////////////////////////////////////////////////////////////
CvTreeNodeIterator iterator; 
int iOneTourLength=0;
CvSeq *contour = contours;
cvInitTreeNodeIterator(&iterator,contour,3); 
//把所有轮廓的点收集起来 
CvSeq* allpointsSeq = cvCreateSeq(CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvContour), 
sizeof(CvPoint), storage); 
while( 0 != (contour = (CvSeq*)cvNextTreeNode(&iterator)) ){ 
//找到一个轮廓就可以用for循环提取里面的点了 
//这里遍历CvSeq里面的元素的方法很怪异 
iOneTourLength = contour->total; 
//给点数组分配空间,记得释放 
CvPoint *points = (CvPoint *)malloc(sizeof(CvPoint) * iOneTourLength); 
//printf("seqlength:%d\n",seqlength); 
CvSeqReader reader; 
CvPoint pt = cvPoint(0,0);
cvStartReadSeq(contour,&reader); 
//开始提取 
for(int i = 0 ;i < iOneTourLength; i++){ 
CV_READ_SEQ_ELEM(pt,reader); 
points[i] = pt; 
cvSeqPush(allpointsSeq,&pt); 

//把这个轮廓点找出后,就可以用这些点画个封闭线 
cvPolyLine(frmIn1, &points, &iOneTourLength, 1, 1, CV_RGB(0,255,0),2 , 8, 0); 

////////////////////////////////////////////////////////////////////////////////////////////
原创粉丝点击