一、轮廓及API介绍
什么叫轮廓呢?大概就是能以某种方式连续连接起来的一系列点所组成的一个整体,当然了,点也能看做是一种特殊的轮廓吧。
了解到,利用cv的库函数findcontours提取出来的轮廓是有一定的内在关系的,比如说内外轮廓的包含,父子关系等等,可以通过这些关系来提取出我们真正所需要的轮廓。
而cv的库函数Canny所提取出来的轮廓则是没有所谓的内在关系的。
那么,以下图为例,来说明findcontours提取出来的轮廓的具体关系
- 对于最大的矩形而言,B是其外轮廓,B’是其内轮廓
- 对元素B是B’的父轮廓,所以B’就是B的子轮廓。C就是B’的子轮廓,D和E都是C’的子轮廓,而D或E其中一个是C’的第一个子轮廓。
- 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也懂了,那来做个试验吧。
首先上原图:
method参数为CV_CHAIN_APPROX_NONE
将检测到的所有轮廓保存至contours向量中
实验前我遇到一个问题,就是你不提前把边缘提取出来的话边缘图的最外层会被默认画出来,你在边缘图上只能看到最外层的一个框框。。。所以最好先用canny或者什么方法来先把原图的边缘先提取出来。
下面改变mode参数:
- 当mode参数为CV_RETR_EXTERNAL
这个参数只检测最外围轮廓,包含在外轮廓内的内轮廓被忽略,那么表现在结果上你猜猜是什么?没错,那几个原点是会被忽略掉的。结果如图:
- 当mode参数为CV_RETR_LIST
这个参数检测所有轮廓。但轮廓之间不建立等级关系,彼此相互独立。也就是在此模式下不存在父轮廓和子轮廓,hierarchy的[i][3],[i][4]均为-1 - 当mode参数为CV_RETR_CCOMP 和CV_RETR_TREE,就是检测所有轮廓,只不过层级不一样,这个就不把实验放出来了。
实验代码在此下方,你可以下下来自己改参数来观察实验结果,并自己发散一下。
http://download.csdn.net/download/csdn_dzh/10142914