OpenCV中寻找轮廓函数cvFindContours的使用说明以及序列cvSeq的用法说明

http://blog.163.com/qingyu_1984/blog/static/1444145032013014104222956/

OpenCV中寻找轮廓函数cvFindContours的使用说明以及序列cvSeq的用法说明

cvFindContours(tour_buf,storage, &contour,sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); 
tour_buf: 是需要查找轮廓的 单通道灰度图像
storage: 是临时存储区 ,
contour:是存储轮廓点的CvSeq实例,
CV_RECT_EXTERNAL: 只查找外围轮廓,还有CV_RECT_TREE

正确调用查找函数后,接下来就是从轮廓序列contour(这里的contour不单单只有一个轮廓序列) 提取轮廓点了.
contour可能是空指针,提取前最好判断一下
在提取之前还可以调用一个函数:
contour = cvApproxPoly( contour, sizeof(CvContour), storage, CV_POLY_APPROX_DP, 3, 1 ); 
可能是拟合,有这一句找出的轮廓线更直。

contour里面包含了很多个轮廓,每个轮廓是单独存放的 .

( 要通过一个迭代器遍历里面每一个轮廓,教程里面都没提到,还是看了源代码学来的
CvTreeNodeIterator iterator; 
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循环提取里面的点了 ) 这个方法不推荐 --zhengjw 2013/1/14
	// 推荐 mode = CV_RETR_LIST; contours_num=cvFindContours(preimg, storage, &contours, sizeof(CvContour), mode, CV_CHAIN_APPROX_NONE, cvPoint(0,0)); //-- contours_num 表示的是一共有多少条轮廓线for (;contours!=0;contours=contours->h_next) //-- 指向下一个轮廓序列{ 这里遍历CvSeq里面的元素的方法很怪异 
	onetourlength = contour->total; 
	//给点数组分配空间,记得释放 
	CvPoint *points = (CvPoint *)malloc(sizeof(CvPoint) * onetourlength); 
	//printf("seqlength:%dn",seqlength); 
	CvSeqReader reader; //-- 读其中一个轮廓序列
	CvPoint pt = cvPoint(0,0); 
	cvStartReadSeq(contour,&reader); //开始提取 
	for(int i = 0 ;i < onetourlength; i++){ 
		CV_READ_SEQ_ELEM(pt,reader); //--读其中一个序列中的一个元素点
		points[i] = pt; 
		cvSeqPush(allpointsSeq,&pt); 
	} //把这个轮廓点找出后,就可以用这些点画个封闭线 
	cvPolyLine(image,&points,&onetourlength,1,0,CV_RGB(0,255,0),2,8,0); 
} //-- zhengjw 2013/1/14//刚刚已经画出了找出的每个轮廓,还收集了所有轮廓点, 
//因此还可以将这些点用一个围线包围起来,即把所有轮廓包围起来 
//这里要用到新的函数 
CvSeq* hull; 
hull = cvConvexHull2(allpointsSeq,0,CV_CLOCKWISE,0); 

cvConvexHull2返回一个hull对象,里面包含了围线的点
可以用上面的方法将点取出,然后画出来
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
阅读了上面的内容后还是感觉有点茫然,就自己写了一个例子,贴出来供大家交流指正。
源代码:
#include 
#include 
#include 
#include 
#include 

#pragma comment(lib, "cv.lib")
#pragma comment(lib, "cxcore.lib")
#pragma comment(lib, "highgui.lib")

int main( int argc, char** argv )
{
	//声明IplImage指针
	IplImage* pImg = NULL; 
	IplImage* pContourImg = NULL;
	CvMemStorage * storage = cvCreateMemStorage(0);
	CvSeq * contour = 0;
	int mode = CV_RETR_EXTERNAL;// CV_RETR_EXTERNAL
	unsigned th=0;
	if( argc == 3)
		if(strcmp(argv[2], "all") == 0)
			mode = CV_RETR_CCOMP; //内外轮廓都检测 
	//创建窗口
	cvNamedWindow("src", 1);
	cvNamedWindow("contour",1);
	//载入图像,强制转化为Gray
	if( argc >= 2 && (pImg = cvLoadImage( argv[1], 0)) != 0 )
	{
		cvShowImage( "src", pImg );
		//为轮廓显示图像申请空间
		//3通道图像,以便用彩色显示
		pContourImg = cvCreateImage(cvGetSize(pImg),IPL_DEPTH_8U,3);
		//copy source image and convert it to BGR image
		cvCvtColor(pImg, pContourImg, CV_GRAY2BGR);
		cvCanny(pImg, pImg, 50, 150, 5); 
		int Num=cvFindContours( pImg, storage, &contour, sizeof(CvContour), mode, CV_CHAIN_APPROX_SIMPLE);
		std::cout<<"The number of Contours is:"<h_next)
		{
			printf("***************************************************\n");
			for(int i=0;itotal;i++)
			{
				CvPoint* p=(CvPoint*)cvGetSeqElem(contour,i);
				printf("p->x=%d,p->y=%d\n",p->x,p->y); 
			}
			//将轮廓画出 
			cvDrawContours(pContourImg, contour, CV_RGB(255,0,0), CV_RGB(0, 255, 0), 0, 2, 0); 
		}
	}
	else
	{
		//销毁窗口
		cvDestroyWindow( "src" );
		cvDestroyWindow( "contour" );
		cvReleaseMemStorage(&storage);
		return -1;
	}
	//显示图像
	cvShowImage( "contour", pContourImg );
	cvWaitKey(0);
	//销毁窗口
	cvDestroyWindow( "src" );
	cvDestroyWindow( "contour" );
	//释放图像
	cvReleaseImage( &pImg ); 
	cvReleaseImage( &pContourImg ); 
	cvReleaseMemStorage(&storage);
	return 0;
}

通过此代码我找到了轮廓的个数,如dos窗口中显示,另外还找到了各个轮廓上的若干点。
说明:cvFindContours函数返回找到的轮廓个人,contour->total的值为序列中点的个数,特此说明一下。据某书上说只返回找到的直线的端点的坐标,这样理解应该就没有问题了,但是为什么是6个点,有点诡异。请大神赐教,呵呵。。

结果:
OpenCV中寻找轮廓函数cvFindContours的使用说明以及序列cvSeq的用法说明_第1张图片

你可能感兴趣的:(OpenCV)