CvSeq类型在cvFindContours()中的使用

一.cvFindContours()函数实例

图像分割是图像处理中算是比较核心的部分了,就图像分割方法很多但也很灵活,切忌拘泥于一种算法而套用。图像分割的主要应用是利用一些特性从复杂环境中把需要的目标分割出来处理。比如说交通监制系统把视野中的车辆分割提取出来,从而实现对车辆的监控的。


这里假设已经通过基本的分割方法,得到了图像分割结果的Mask图像。那么,如果从Mask图像中提取各个连通区域并提取相关属性呢。幸运的是opencv 中给我们提供了这些需要的环境。这里要介绍的是cvFindContours()函数的应用。也是查找轮廓,应用比较广主要是因为它的参数容易出彩。

在二值图像中寻找轮廓

int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,
                    int header_size=sizeof(CvContour), int mode=CV_RETR_LIST,
                    int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );
image
输入的 8-比特、单通道图像. 非零元素被当成 1, 0 象素值保留为 0 - 从而图像被看成二值的。为了从灰度图像中得到这样的二值图像,可以使用 cvThreshold, cvAdaptiveThreshold 或 cvCanny. 本函数改变输入图像内容。
storage
得到的轮廓的存储容器
first_contour
输出参数:包含第一个输出轮廓的指针
header_size
如果 method=CV_CHAIN_CODE,则序列头的大小 >=sizeof(CvChain),否则 >=sizeof(CvContour) .
mode
提取模式.
  • CV_RETR_EXTERNAL - 只提取最外层的轮廓
  • CV_RETR_LIST - 提取所有轮廓,并且放置在 list 中
  • CV_RETR_CCOMP - 提取所有轮廓,并且将其组织为两层的 hierarchy: 顶层为连通域的外围边界,次层为洞的内层边界。
  • CV_RETR_TREE - 提取所有轮廓,并且重构嵌套轮廓的全部 hierarchy
method
逼近方法 (对所有节点, 不包括使用内部逼近的 CV_RETR_RUNS).
  • CV_CHAIN_CODE - Freeman 链码的输出轮廓. 其它方法输出多边形(定点序列).
  • CV_CHAIN_APPROX_NONE - 将所有点由链码形式翻译(转化)为点序列形式
  • CV_CHAIN_APPROX_SIMPLE - 压缩水平、垂直和对角分割,即函数只保留末端的象素点;
  • CV_CHAIN_APPROX_TC89_L1,
  • CV_CHAIN_APPROX_TC89_KCOS - 应用 Teh-Chin 链逼近算法. CV_LINK_RUNS - 通过连接为 1 的水平碎片使用完全不同的轮廓提取算法。仅有 CV_RETR_LIST 提取模式可以在本方法中应用.
offset
每一个轮廓点的偏移量. 当轮廓是从图像 ROI 中提取出来的时候,使用偏移量有用,因为可以从整个图像上下文来对轮廓做分析.

函数 cvFindContours 从二值图像中提取轮廓,并且返回提取轮廓的数目。指针 first_contour 的内容由函数填写。它包含第一个最外层轮廓的指针,如果指针为 NULL,则没有检测到轮廓(比如图像是全黑的)。其它轮廓可以从 first_contour 利用 h_next 和 v_next 链接访问到。 在 cvDrawContours 的样例显示如何使用轮廓来进行连通域的检测。轮廓也可以用来做形状分析和对象识别 - 见CVPR2001 教程中的 squares 样例。该教程可以在 SourceForge 网站上找到。

// findcontours
//writen @ polly_yang
	CvMemStorage * p_storage = cvCreateMemStorage(0);
	CvSeq *p_first_contour = 0;
	
	int region_num = cvFindContours(img,p_storage,&p_first_contour,sizeof(CvContour),CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0));
	
	printf("the region number is %d...\n",region_num);
	
	double area;
	int flag = 0 ;
	for (;p_first_contour;p_first_contour = p_first_contour->h_next)   //访问cvseq
	{
		if (p_first_contour)
		{
			area = fabs(cvContourArea(p_first_contour,CV_WHOLE_SEQ));
			printf(" no. %d  area == %lf ..\n",flag,area);
			flag++;
			if (area > 100)
			{
				CvRect area_Rect = cvBoundingRect(p_first_contour,0);
				cvRectangleR(m_pNowImg,area_Rect,CV_RGB(255,0,0));
			}
			
		}
		
	}
	CString out_temp_region = m_OutTempStr + CString(_T("_2_region.bmp"));
	cvSaveImage(CT2A(out_temp_region),m_pNowImg);


这段代码实现了检测Mask图像中的所有连通域并将所有连通域的外接矩形绘制到原始图像上去,连通域的结果序列存放在CvSeq序列中。通过cvContourArea可以得到一个连通域的面积;通过cvBoundingRect可以得到连通域的外接矩形。剩下的就是对ROI操作了。

二.CvSeq数据结构解析

函数原型 说明
CvSeq* cvCreateSeq(int seq_flags,int header_size,int elem_size,CvMemStorage* storage) 功能:创建一序列 

参数:seq_flags为序列的符号标志。如果序列不会被传递给任何使用特定序列的函数,那么将它设为0,否则从预定义的序列类型中选择一合适的类型。 Header_size为序列头部的大小;必须大于或等于sizeof(CvSeq)。如果制定了类型或它的扩展名,则此类型必须适合基类的头部大小。 Elem_size为元素的大小,以字节计。这个大小必须与序列类型(由seq_flags指定)相一致。例如,对于一个点的序列,元素类型 CV_SEQ_ELTYPE_POINT应当被指定,参数elem_size必须等同于sizeof(CvPoint)。Storage为指向前面定义的 内存存储器
CvSeq* cvCloneSeq(const CvSeq* seq,CvMemStorage* storage=NULL) 功能:创建序列的一份拷贝
Void cvSeqInvert(CvSeq* seq) 功能:将序列中的元素进行逆序操作
Void cvSeqSort(CvSeq* seq,CvCmpFunc func,void *userdata=NULL)

功能:使用特定的比较函数对序列中的元素进行排序

Char* cvSeqSearch(CvSeq* seq,const void* elem,CvCmpFunc func,int is_sorted,int *elem_idx,void *userdata=NULL) 功能:查询序列中的元素
Void cvClearSeq(CvSeq* seq); 功能:清空序列
Char* cvSeqPush(CvSeq* seq,void* element=NULL) 功能:添加元素到序列的尾部

void cvSeqPop(CvSeq* seq,void* element=NULL)

功能:删除序列尾部元素

Char* cvSeqPushFront(CvSeq* seq,void* element=NULL)

功能:在序列头部添加元素

Void cvSeqPopFront(CvSeq* seq,void* element=NULL)

功能:删除在序列的头部的元素

Void cvSeqPushMulti(CvSeq* seq,void* elements,int count,int in_front=0);

功能:添加多个元素到序列尾部或头部

Void cvSeqPopMulti(CvSeq* seq,void* elements,int count,int in_front=0)

功能:删除多个序列头部或尾部元素

Char* cvSeqInsert(CvSeq* seq,int before_index,void* element=NULL)

功能:在序列中的指定位置添加元素

Void cvSeqRemove(CvSeq* seq,int index)

功能:删除序列中的指定位置的元素

Char* cvGetSeqElem(const CvSeq* seq,int index)

功能:返回索引所指定的元素指针

Int cvSeqElemIdx(const CvSeq* seq,const void* element,CvSeqBlock** block=NULL)

功能:返回序列中元素的索引

Void cvStartAppendToSeq(CvSeq* seq,CvSeqWriter* writer)

功能:将数据写入序列中,并初始化该过程

Void cvStartWriteSeq(int seq_flags,int header_size,int elem_size,CvMemStorage* storage,CvSeqWriter* writer)

功能:创建新序列,并初始化写入部分

CvSeq* cvEndWriteSeq(CvSeqWriter* writer)

功能:完成写入操作

Void cvStartReadSeq(const CvSeq* seq,CvSeqReader* reader,int reverse=0)

功能:初始化序列中的读取过程




你可能感兴趣的:(CvSeq类型在cvFindContours()中的使用)