1、使用轮廓扫描器查找轮廓(组合函数)喻小波总述: 2API 函数名: 2运行实例效果: 2cvStartFindContours 函数: .3输入: 3输出: 3运行逻辑: 4cvFindNextContour 函数: .5输入: 5输出: 5运行逻辑: 5cvSubstituteContour 函数: 6输入: 6输出: 6运行逻辑: 6cvEndFindContours 函数: 6输入: 6输出: 6运行逻辑: 6运行实例: 7使用场合: 7使用注意: 7例子流程: 7综合总结: 7总述:本文中四个 API 是一组,是一种轮廓查找的方法!(Cvcontours.c) ,API 运行效果见实例
2、运行效果!这四个 API 为了解决一幅图像有多个轮廓的问题,通过这四个 API 可将一幅图像中多个轮廓变成多个序列块。而 FINDCONTOURS,是将所有的轮廓做一个序列链表,无法实现多个轮廓序列块的地址。API 函数名:cvStartFindContours:初始化轮廓扫描器cvFindNextContour:使用初始好的轮廓扫描器查找一个轮廓(返回序列指针)cvSubstituteContour:用户自定义的轮廓替换前一次的函数 cvFindNextContour 所提取的轮廓cvEndFindContours:结束轮廓扫描器,也就是释放扫描器空间运行实例效果:四个 API 一个实例!见
3、实例。 。 。 。 。 。cvStartFindContours 函数:cvStartFindContours( void* _img, CvMemStorage* storage,int header_size, int mode, int method, CvPoint offset )输入:image 输入的 8-比特、单通道二值图像 输出:一个被初始好的轮廓扫描器(CvContourScanner),这个会被下一个 API 函数(FindNextContour)所使用.实现参数选择:storage 提取到的轮廓容器,也就是 CvMemStorage开辟的内存块!header_size
4、序列头的尺寸 .常用的方法, sizeof(CvContourEx),mode 提取模式 .有四种提取方法 CV_RETR_EXTERNAL - 只提取最外层的轮廓 CV_RETR_LIST - 提取所有轮廓,并且放置在 list 中 CV_RETR_CCOMP - 提取所有轮廓,并且将其组织为两层的 hierarchy: 顶层为连通域的外围边界,次层为洞的内层边界。 CV_RETR_TREE - 提取所有轮廓,并且重构嵌套轮廓的全部 hierarchy method 逼近方法 CV_CHAIN_CODE - Freeman 链码的输出轮廓. 其它方法输出多边形(定点序列). CV_CHAIN
5、_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 偏移量 ,常用方法 cvPoint(0,0),也就是偏移量对整个图像有效!运行逻辑:本 API函
6、数,就是对轮廓扫描器(CvContourScanner 数据结构体)进行初始化,返回的给 FindNextContour API函数使用!首先,判断输入的内存块(指针不为空)和图像数据(8 位单通道)的数据格式是否正确,初始化(CvContourScanner)结构体中的成员,然后对传入的图像进行二值化,方式为 CV_THRESH_BINARY,如果初始化成功就返回轮廓扫描器的指针头.本 API无运行实例,因为它返回是轮廓扫描器的头!另附:轮廓扫描器的数据结构:typedef struct _CvContourScannerCvMemStorage *storage1; /*包含提取的轮廓*/
7、CvMemStorage *storage2; /*载有近似等高线(!=storage1 if approx_method2 != approx_method1) */CvMemStorage *cinfo_storage; /*存放轮廓信息节点*/CvSet *cinfo_set; /* 轮廓信息的设置 */CvMemStoragePos initial_pos; /* starting storage pos */CvMemStoragePos backup_pos; /* beginning of the latest approx. contour */CvMemStoragePos
8、backup_pos2; /* ending of the latest approx. contour */char *img0; /* image origin */char *img; /* current image row */int img_step; /* image step */CvSize img_size; /* ROI size */CvPoint offset; /* ROI offset: coordinates, added to each contour point */CvPoint pt; /* current scanner position */CvPo
9、int lnbd; /* position of the last met contour */int nbd; /* current mark val */_CvContourInfo *l_cinfo; /* information about latest approx. contour */_CvContourInfo cinfo_temp; /* temporary var which is used in simple modes */_CvContourInfo frame_info; /* information about frame */CvSeq frame; /* fr
10、ame itself */int approx_method1; /* approx method when tracing */int approx_method2; /* final approx method */int mode; /* contour scanning mode:0 - external only1 - all the contours w/o any hierarchy2 - connected components (i.e. two-level structure -external contours and holes) */int subst_flag;in
11、t seq_type1; /* type of fetched contours */int header_size1; /* hdr size of fetched contours */int elem_size1; /* elem size of fetched contours */int seq_type2; /* */int header_size2; /* the same for approx. contours */int elem_size2; /* */_CvContourInfo *cinfo_table126;_CvContourScanner;cvFindNextC
12、ontour 函数:CvSeq* cvFindNextContour( CvContourScanner scanner )确定和提取图像的下一个轮廓,并且返回它的指针。若没有更多的轮廓,则函数返回 NULL输入:scanner 一个初始化好的轮廓扫描器。输出:CvSeq 返回查找到的轮廓(序列) 。运行逻辑:首先判断轮廓扫描器信息(_CvContourInfo) ,将即将查找到的轮廓(序列)开辟空间和将扫描器信息结构值 0,表示序列链表的最后(icvEndProcessContour 通过此函数完成) ,然后,按行方式,以初始化时的 STEP 为步长,再按列,步长为 1,通过(icvTrac
13、eContour)此函数查找图像中所有的轮廓区域,并返回第一个区域的轮廓区域信息结构体,同时也将轮廓区域信息链表指向下一个,对选定的区域寻找起始点,然后对区域进行边界扫描跟踪(根据不同的逼近方式和轮廓类型)icvFetchContour,得边界轮廓。然后再对扫描器信息结构体进行赋值,将区域链表指针指向下一个区域,下一次调用此函数时,就从这个轮廓区域开始。最后将找到的轮廓坐标点存放到中序列,一个序列存放一个轮廓区域的轮廓信息,多个轮廓序列形成轮廓序列链表。其结束为就是两个 3X3 卷积核中心点的领域,通过四连通方式比较,得到就是轮廓点一个像素,然后将轮廓点,按序列的方式存储得到我们所操作的轮廓序
14、列头.cvSubstituteContour 函数:void cvSubstituteContour( CvContourScanner scanner, CvSeq* new_contour );替换提取的轮廓;输入:scanner 初始化的轮廓扫描器contour 新轮廓序列输出:无 void运行逻辑:修改扫描器信息结构体,将输出的新轮廓序列的地址,替换原来的。这个怎么理解?cvEndFindContours 函数:CvSeq* cvEndFindContours( CvContourScanner* scanner )结束扫描过程,返回序列链表头。输入:scanner 被初始化的轮廓扫描
15、器输出:CvSeq 序列链表头运行逻辑:调用 icvEndProcessContour,释放存储内存空间。将返回最高层的第一个轮廓的指针运行实例:本实例综合,综合 Cvcontours.c 文件中的三个 API,对图像进行轮廓查找,目的是验证三个 API 的组合使用,其表现形式是找到一个轮廓,用篮线标出,输入任意键,查找下一个轮廓。具体例子效果见实际运行!(本例子存在一些问题,但能说明三个 API 的使用)使用场合:一幅图像中多个轮廓的查找,选取有用的轮廓。 (序列)使用注意:注意例子中所使用的指针变量,防止内存泄漏!三个函数必须组合使用!例子流程:开始c v S m o o t hc v C
16、 v t C o l o rc v T h r e s h o l dc v S t a r t F i n d C o n t o u r sc v F i n d N e x t C o n t o u rc v E n d F i n d C o n t o u r s结束W h i l e ( 1 )I f ( f l a g )综合总结:上面的流程图,只是简要说明,具体细节见 C 文件!1、 本例子是一种不同的轮廓查找的办法。图像中查找到轮廓序列是相互独立的。2、 本例子中使用到了很多的序列操作。使用时需要注意。3、 使用时很容易出现内存泄漏4、 改进意见暂无!#include “c
17、v.h“#include “cxcore.h“#include “highgui.h“CvSeq* contour = NULL;double minarea = 10000.0;double tmparea = 0.0;void main()CvMemStorage* storage = cvCreateMemStorage(0);IplImage* img_src = cvLoadImage(“1.bmp“, CV_LOAD_IMAGE_GRAYSCALE);/显示原始图像cvNamedWindow(“img_src“,CV_WINDOW_AUTOSIZE);cvShowImage(“im
18、g_src“, img_src);IplImage* img_dst = cvCreateImage(cvGetSize(img_src),IPL_DEPTH_8U,1);/-搜索二值图中的轮廓,并从轮廓树中删除面积小于某个阈值minarea的轮廓-/CvScalar color = cvScalar(255,0,0);/CV_RGB(128,0,0);CvContourScanner scanner = NULL;/初始化轮廓扫描器scanner = cvStartFindContours(img_src,storage,sizeof(CvContour),CV_RETR_TREE,CV_C
19、HAIN_APPROX_SIMPLE,cvPoint(0,0);/开始遍历轮廓树while (contour=cvFindNextContour(scanner)tmparea = fabs(cvContourArea(contour);if (tmparea minarea)cvSubstituteContour(scanner,NULL);/删除当前的轮廓/结束轮廓搜索,并返回轮廓树的根节点contour = cvEndFindContours(/绘制经过删除操作后图像中剩下的轮廓/cvZero(img_dst);cvDrawContours(img_dst,contour,color,color,2,1,8,cvPoint(0,0);cvNamedWindow(“dst_contour“,CV_WINDOW_AUTOSIZE);cvShowImage(“dst_contour“, img_dst);cvSaveImage(“dst_contour.jpg“,img_dst);cvWaitKey(0);cvReleaseMemStorage(cvReleaseImage(cvReleaseImage(cvDestroyAllWindows();