OpenCV——contours学习笔记(一)

一、轮廓及API介绍

什么叫轮廓呢?大概就是能以某种方式连续连接起来的一系列点所组成的一个整体,当然了,点也能看做是一种特殊的轮廓吧。

了解到,利用cv的库函数findcontours提取出来的轮廓是有一定的内在关系的,比如说内外轮廓的包含,父子关系等等,可以通过这些关系来提取出我们真正所需要的轮廓。

而cv的库函数Canny所提取出来的轮廓则是没有所谓的内在关系的。

那么,以下图为例,来说明findcontours提取出来的轮廓的具体关系
OpenCV——contours学习笔记(一)_第1张图片

  1. 对于最大的矩形而言,B是其外轮廓,B’是其内轮廓
  2. 对元素B是B’的父轮廓,所以B’就是B的子轮廓。C就是B’的子轮廓,D和E都是C’的子轮廓,而D或E其中一个是C’的第一个子轮廓。
  3. A和B都属于最外围的轮廓。它们是同一层级,均属于 hierarchy[0]

在opencv中,通过一个数组来表达轮廓的层级关系

[Next, Previous, Parent, First_Child]
  • Next表示同一层级的下一个轮廓。比如A的Next是B,但B的Next没有了,用-1表示。
  • Previous表示同一层级的上一个轮廓。比如B的上一层级是A,但A的上一层级没有了,也用-1表示。
  • 父子关系,前面已经提过了。

好的,那么现在对findcontours的轮廓已经有了一个基本的认识,现在来看下API接口。

findContours( InputOutputArray image,         //参数1
			  OutputArrayOfArrays contours,   //参数2
              OutputArray hierarchy,          //参数3
              int mode,                       //参数4
              int method,                     //参数5
              Point offset=Point());          //参数6
  • 参数1:单通道的图像,可以是灰度图,一般是经过canny、laplace等边缘检测后得到的二值图像。
  • 参数2:定义为
vector<vector<Point>> contours

这是一个向量,向量内的每一个元素,分别是一组连续的点(Point(x,y))构成的点的集合所组成的向量。也就是说,一组点(Point(x,y))构成的集合就是一个轮廓,轮廓的个数就是向量contours的总数。

  • 参数3:定义为
vector<Vec4i> hierarchy

hierarchy[3][3]表示轮廓3的父级轮廓 hierarchy[ hierarchy[3][3]][3]表示轮廓3父级轮廓的父级轮廓
hierarchy[3][0]、hierarchy[3][1]、hierarchy[3][2]、hierarchy[3][3]分别表示轮廓3的前一个、后一个、子级、父级轮廓。具体可以参考
http://blog.csdn.net/guanyonglai/article/details/60140228

  • 参数4:mode定义轮廓的检索模式,有些面的参数可以选择:
CV_RETR_EXTERNAL       //只检测最外围轮廓,包含在外轮廓内的内轮廓被忽略
CV_RETR_LIST   //检测所有轮廓。但轮廓之间不建立等级关系,彼此相互独立。
			   //也就是在此模式下不存在父轮廓和子轮廓,hierarchy的[i][3],[i][4]均为-1
CV_RETR_CCOMP  //检测所有轮廓。但轮廓之间只有两个等级关系,外围为顶层,外层内的轮廓都属于它的子轮廓
CV_RETR_TREE  //检测所有轮廓,轮廓之间建立一个完整的关系,就如同前面讲的例子一样。
  • 参数5:定义轮廓近似方法method
CV_CHAIN_APPROX_NONE   //保存物体边界上所有连续的轮廓点到coutours向量内
CV_CHAIN_APPROX_SIMPLE //仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不保留
  • 参数6:一般就用默认的啦,后面需要再做学习吧,大概就是一个偏移量。让轮廓往别的地方去。

噢,BTW,需要用一个绘制轮廓的API来将提取的轮廓绘制出来

	for (int i = 0; i< contours.size(); i++)
	{
		drawContours(contoursImage, contours, i, Scalar(255), 1, 8, hierarchy);
	}

特别注意这个i是需要绘制的边缘索引,如果全部绘制则为-1

二、实验

好,基本知识也知道了,API也懂了,那来做个试验吧。
首先上原图:
OpenCV——contours学习笔记(一)_第2张图片

method参数为CV_CHAIN_APPROX_NONE

将检测到的所有轮廓保存至contours向量中

实验前我遇到一个问题,就是你不提前把边缘提取出来的话边缘图的最外层会被默认画出来,你在边缘图上只能看到最外层的一个框框。。。所以最好先用canny或者什么方法来先把原图的边缘先提取出来。

下面改变mode参数:

  1. 当mode参数为CV_RETR_EXTERNAL
    这个参数只检测最外围轮廓,包含在外轮廓内的内轮廓被忽略,那么表现在结果上你猜猜是什么?没错,那几个原点是会被忽略掉的。结果如图:
    OpenCV——contours学习笔记(一)_第3张图片
  2. 当mode参数为CV_RETR_LIST
    这个参数检测所有轮廓。但轮廓之间不建立等级关系,彼此相互独立。也就是在此模式下不存在父轮廓和子轮廓,hierarchy的[i][3],[i][4]均为-1
  3. 当mode参数为CV_RETR_CCOMP 和CV_RETR_TREE,就是检测所有轮廓,只不过层级不一样,这个就不把实验放出来了。

实验代码在此下方,你可以下下来自己改参数来观察实验结果,并自己发散一下。
http://download.csdn.net/download/csdn_dzh/10142914

你可能感兴趣的:(OpenCV)