Opencv笔记——findContours函数

 好长时间没写博客了,主要是前一段时间读的论文不多,也没什么新的想法,学到的东西别人的博客已经写的挺好的了,自己就没必要再写了。寒假做数字图像处理的作业的时候用OpenCV的findContours函数来寻找轮廓,对这个函数有点理解,我觉得还比较有价值。

    先来看看findContours的声明


[cpp]  view plain  copy
  1. findContours( InputOutputArray image, OutputArrayOfArrays contours,  
  2.           OutputArray hierarchy, int mode,  
  3.               int method, Point offset=Point());  

[cpp]  view plain  copy
  1. findContours( InputOutputArray image, OutputArrayOfArrays contours,  
  2.               int mode, int method, Point offset=Point());  


   image:输入图像。8-bit的单通道二值图像,非零的像素都会被当作1。

   contours:检测到的轮廓。是一个向量,向量的每个元素都是一个轮廓。因此,这个向量的每个元素仍是一个向量。即

[cpp]  view plain  copy
  1. vector<vector<Point> > contours;  

    hierarchy:各个轮廓的继承关系。hierarchy也是一个向量,长度和contours相等,每个元素和contours的元素对应。hierarchy的每个元素是一个包含四个整型数的向量。即:

[cpp]  view plain  copy
  1. vector<Vec4i> hierarchy; //Vec4i is a vector contains four number of int  

    hierarchy[i][0],hierarchy[i][1],hierarchy[i][2],hierarchy[i][3],分别表示的是第i条轮廓(contours[i])的下一条,前一条,包含的第一条轮廓(第一条子轮廓)和包含他的轮廓(父轮廓)。

    mod:检测轮廓的方法。有四种方法。

    —CV_RETR_EXTERNAL:只检测外轮廓。忽略轮廓内部的洞。

    —CV_RETR_LIST:检测所有轮廓,但不建立继承(包含)关系。

    —CV_RETR_TREE:检测所有轮廓,并且建立所有的继承(包含)关系。也就是说用CV_RETR_EXTERNAL和CV_RETR_LIST方法的时候hierarchy这个变量是没用的,因为前者没有包含关系,找到的都是外轮廓,后者仅仅是找到所哟的轮廓但并不把包含关系区分。用TREE这种检测方法的时候我们的hierarchy这个参数才是有意义的。事实上,应用前两种方法的时候,我们就用findContours这个函数的第二种声明了。

    —CV_RETR_CCOMP:检测所有轮廓,但是仅仅建立两层包含关系。外轮廓放到顶层,外轮廓包含的第一层内轮廓放到底层,如果内轮廓还包含轮廓,那就把这些内轮廓放到顶层去。

    method:表示一条轮廓的方法。

    – CV_CHAIN_APPROX_NONE:把轮廓上所有的点存储。

    – CV_CHAIN_APPROX_SIMPLE:只存储水平,垂直,对角直线的起始点。对drawContours函数来说,这两种方法没有区别。

    – CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:实现的“Teh-Chin chain approximation algorithm.”这个不太懂。他们的论文:Teh, C.H. and Chin, R.T., On the Detection of Dominant Points on Digital Curve. PAMI 11 8, pp 859-872 (1989)

    offset:Optional offset by which every contour point is shifted. This is useful if the contours are extracted from the image ROI and then they should be analyzed in the whole image context。懒得翻译了,直接把参考手册原文拿过来了。

     函数将白色区域当作前景物体。所以找轮廓找到的是白色区域的轮廓。
     这个函数有一个特点,如果白色区域延伸到了图像边界,那么图像的边界也是被当作轮廓的一部分。测试如下:
[cpp]  view plain  copy
  1. //read as gray image  
  2. Mat im=imread("G:\\sample.png",0);  
  3. if(!im.data) {cout<<"Can't find image!";return -1;}  
  4.   
  5. //change the image to binary by setting a threshold  
  6. threshold(im,im,120,255,THRESH_BINARY);  
  7.   
  8. vector<vector<Point> > contours;  
  9. vector<Vec4i> hierarchy;  
  10. findContours(im,contours,hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);  
  11.   
  12. Mat contoursImage(im.rows,im.cols,CV_8U,Scalar(255));  
  13. for(int i=0;i<contours.size();i++){  
  14.     if(hierarchy[i][3]!=-1) drawContours(contoursImage,contours,i,Scalar(0),3);  
  15. }  
     这是测试代码,注意,这里我们用的是CV_RETR_CCOMP这个方法。代码实现了找到图像的轮廓,并且,如果该轮廓有父轮廓就画出来
这是测试用的图像。

左边是运行结果,右边是把所有的轮廓画出来。可见,白色区域的轮廓包含了整个图像的边界。
并且有一点令人疑惑的是,原图中的那几个白色小圆圈应该也有父轮廓吧,至少是包含在黑色长方形中的。其实这几个小白色的区域是有父轮廓的,只不过它们是子轮廓的子轮廓,所以就被安排到第一级上了。
当我们变换参数为CV_RETR_TREE的时候,我们可以看到白色的圆圈的轮廓又出来了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值