利用OpenCV的函数findContours()和函数drawContours()进行轮廓的检测与绘制

问: 边缘检测与轮廓检测有什么区别?

边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。 这些包括(i)深度上的不连续、(ii)表面方向不连续、(iii)物质属性变化和(iv)场景照明变化。

而轮廓提取的目的是提取出目标物体的轮廓,轮廓可能是边缘的一部分,轮廓检测会常常用到边缘检测算法。轮廓通常都闭环的,即图像上的某一点要么位于轮廓内部,要么位于轮廓上,要么位于轮廓外部。

关于边缘检测的方法,前面已经有几篇博文介绍了(详情见 https://blog.csdn.net/wenhao_ir/article/details/51743382),所以不多说了。这里说轮廓检测

OpenCV中提供了函数findContours()用于对物体轮廓进行检测,该函数实现算法是由S.Suzuki K. Abe于1985年发表在CVGIP上的论文“Toplogical Structrual Analysis of Digitized Binary Images by Boder Following”中提出的,论文中详细叙述了轮廓决定层次结构的规则以及轮廓检测的方法,如果需要了解详细原理的可以参看这篇论文。下面介绍函数findContours()的使用。

函数findContours()的原型如下

void findContours( 	InputOutputArray image, 
					OutputArrayOfArrays contours,
					OutputArray hierarchy, 
					int mode,
					int method, 
					Point offset = Point());

官方解释如下

image – Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s. Zero pixels remain 0’s, so the image is treated as binary . You can use compare() , inRange() , threshold() , adaptiveThreshold() , Canny() , and others to create a binary image out of a grayscale or color one. The function modifies the image while extracting the contours. 
contours – Detected contours. Each contour is stored as a vector of points. 
hiararchy – Optional output vector containing information about the image topology. It has as many elements as the number of contours. For each contour contours[i] , the elements hierarchy[i][0] , hiearchy[i][1] , hiearchy[i][2] , and hiearchy[i][3] are set to 0-based indices in contours of the next and previous contours at the same hierarchical level: the first child contour and the parent contour, respectively. If for a contour i there are no next, previous, parent, or nested contours, the corresponding elements of hierarchy[i] will be negative. 

mode – Contour retrieval mode.
CV_RETR_EXTERNAL retrieves only the extreme outer contours. It sets hierarchy[i][2]=hierarchy[i][3]=-1 for all the contours. 
CV_RETR_LIST retrieves all of the contours without establishing any hierarchical relationships. 
CV_RETR_CCOMP retrieves all of the contours and organizes them into a two-level hierarchy. At the top level, there are external boundaries of the components. At the second level, there are boundaries of the holes. If there is another contour inside a hole of a connected component, it is still put at the top level. 
CV_RETR_TREE retrieves all of the contours and reconstructs a full hierarchy of nested contours. This full hierarchy is built and shown in the OpenCV contours.c demo. 

method – Contour approximation method.
CV_CHAIN_APPROX_NONE stores absolutely all the contour points. That is, any 2 subsequent points (x1,y1) and (x2,y2) of the contour will be either horizontal, vertical or diagonal neighbors, that is, max(abs(x1-x2),abs(y2-y1))==1. 
CV_CHAIN_APPROX_SIMPLE compresses horizontal, vertical, and diagonal segments and leaves only their end points. For example, an up-right rectangular contour is encoded with 4 points. 
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS applies one of the flavors of the Teh-Chin chain approximation algorithm. See [TehChin89] for details. 

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. 

翻译如下

image---原图像,数据类型为CV_8U的单通道灰度图像或者二值化图像,函数执行轮廓检测时,原图像不管是灰度图还是二值图都会被再次进行二值化处理,处理的方法是灰度值为0的按0值对待,不为0的按1对待。

contours---检测到的轮廓,每个轮廓都是一个由像素的坐标值组成的向量。

hiararchy---这是一个可选输出参数,它用来存储检测到的轮廓的拓扑结构信息。检测到的每个轮廓都对应一个拓扑结构信息。对于每个轮廓contours[i], hierarchy[i][0]、 hiearchy[i][1] 、 hierarchy[i][2] 、and hiearchy[i][3]的意义分别如下:

  • hierarchy[i][0]:与轮廓contours[i]同一个父轮廓的下一个轮廓的索引值;
  • hierarchy[i][1]:与轮廓contours[i]同一个父轮廓的上一个轮廓的索引值;
  • hierarchy[i][2]:轮廓contours[i]的第一个子轮廓的索引值;
  • hierarchy[i][3]:轮廓contours[i]的父轮廓的索引值;

关于参数hiararchy的更详细探究,可以看我的另一篇博客,链接:https://blog.csdn.net/wenhao_ir/article/details/125570930

mode---轮廓检测模式标志,有以下可选参数:

CV_RETR_EXTERNAL:只检测最外层轮廓,对所有轮廓设置hierarchy[i][2]= hierarchy[i][3]=-1
CV_RETR_LIST:返回所有的轮廓,但是不建立轮廓的拓扑关系,此时对于所有轮廓也是设置hierarchy[i][2]= hierarchy[i][3]=-1。
CV_RETR_CCOMP:提取所有轮廓,并且将其组织为双层结构。顶层(the top levell)为连通域的外围边界,次层(the second level)为孔(hole)的内层边界,如果孔(hole)中还有其它轮廓,那么这个轮廓被划分为顶层(the top levell)。
CV_RETR_TREE:返回所有的轮廓,并且建立完整的拓扑结构,

method---轮廓近似方法,有以下可选参数:

CV_CHAIN_APPROX_NONE:存储所有的轮廓点。这种方法下,两个连续的轮廓点,要么是水平相邻的,要么是垂直相邻的, 要么是对角相邻的,即满足max(abs(x1-x2),abs(y2-y1))==1. 
CV_CHAIN_APPROX_SIMPLE: 压缩水平方向、垂直方向和对角线方向的中间点,只保留某个方向的终点坐标,例如一个矩形轮廓只需4个点来保持轮廓信息。
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用The-Chinl链逼近算法中的一个

offset---每个轮廓点移动的可选偏移量。

看了博主对函数findContours()各参数的翻译解释后,大家可能还是对这些参数的意义比较模糊,没关系,如果您想把握它们的准确意义,可以参考博主的另一篇博文,链接 https://blog.csdn.net/wenhao_ir/article/details/125537919

使用了函数findContours()检测出轮廓后,我们通常还需要将轮廓画出,OpenCV提供了函数drawContours()来绘制检测出的轮廓。其原型如下:

C++: void drawContours(	InputOutputArray image, 
						InputArrayOfArrays contours, 
						int contourIdx, 
						const Scalar& color, 
						int thickness=1, 
						int lineType=LINE_8, 
						InputArray hierarchy=noArray(), 
						int maxLevel=INT_MAX, 
						Point offset=Point() )

参数意义如下:

image---轮廓画到image上。
contours---待画图的轮廓,每个轮廓都是一个由像素的坐标值组成的向量。
contourIdx---指定哪些轮廓需要被绘制,如果这个值为负,则表示所有的轮廓都需要绘制。
color---轮廓颜色。
thickness---轮廓线宽,如果参数为负数,则绘制轮廓的内部。
lineType---线类型。
hierarchy---可选参数,表示轮廓的拓扑结构。
maxLevel---表示要绘制轮廓的最大层级。在参数hierarchy有效的情况下,这个参数为0表示只绘制指定的轮廓;为1表示绘制所有的外轮廓和内嵌轮廓;为2表示绘制所有的外轮廓、内嵌轮廓和内嵌轮廓之间的联接轮廓。以此类推.....
offset:可选的轮廓偏移参数,按指定的移动距离绘制所有的轮廓。

利用OpenCV的函数findContours()和函数drawContours()进行轮廓的检测与绘制的示例代码如下:

代码中用到的图片下载链接:https://pan.baidu.com/s/1uAClJ3xklpSGE1iA-7py5g?pwd=h237

//博主微信/QQ 2487872782
//有问题可以联系博主交流
//有图像处理需求也可联系博主
//图像处理技术交流QQ群 271891601

//OpenCV版本:3.0
//VS版本:2013

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace std;
using namespace cv;

int main()
{

	Mat srcGary = imread("F:/material/images/P0044-hand-02.jpg",0);

	imshow("srcGary", srcGary);

	// 阈值化操作
	Mat threMat;
	int thresh = 128;
	threshold(srcGary, threMat, thresh, 255, THRESH_BINARY);

	// 轮廓检测
	vector<vector<Point> > contours;
	vector<Vec4i> hierarchy;
	findContours(threMat, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

	// 绘制轮廓
	Mat contours_img(srcGary.size(), CV_8U, Scalar(0));
	drawContours(contours_img, contours, -1, Scalar(255), 1);

	imshow("contours_img", contours_img);
	waitKey();
	return 0;
}

运行结果如下图所示:

再说明一下,由于在进行轮廓检测前我们通常要先要对图像进行灰度空间和二值化处理,所以可以写个函数把这两个处理一并封装于函数中,具体的函数代码可打开下面的博文搜索关键字“findcontours”,注意OpenCV的检测轮廓的官方函数名为“findContours”,我自己写的这个中间的C没有大写。
https://blog.csdn.net/wenhao_ir/article/details/124734512

  • 7
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值