什么叫轮廓呢?大概就是能以某种方式连续连接起来的一系列点所组成的一个整体,当然了,点也能看做是一种特殊的轮廓吧。
了解到,利用cv的库函数findcontours提取出来的轮廓是有一定的内在关系的,比如说内外轮廓的包含,父子关系等等,可以通过这些关系来提取出我们真正所需要的轮廓。
而cv的库函数Canny所提取出来的轮廓则是没有所谓的内在关系的。
那么,以下图为例,来说明findcontours提取出来的轮廓的具体关系
在opencv中,通过一个数组来表达轮廓的层级关系
[Next, Previous, Parent, First_Child]
好的,那么现在对findcontours的轮廓已经有了一个基本的认识,现在来看下API接口。
findContours( InputOutputArray image, //参数1
OutputArrayOfArrays contours, //参数2
OutputArray hierarchy, //参数3
int mode, //参数4
int method, //参数5
Point offset=Point()); //参数6
vector<vector<Point>> contours
这是一个向量,向量内的每一个元素,分别是一组连续的点(Point(x,y))构成的点的集合所组成的向量。也就是说,一组点(Point(x,y))构成的集合就是一个轮廓,轮廓的个数就是向量contours的总数。
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
CV_RETR_EXTERNAL //只检测最外围轮廓,包含在外轮廓内的内轮廓被忽略
CV_RETR_LIST //检测所有轮廓。但轮廓之间不建立等级关系,彼此相互独立。
//也就是在此模式下不存在父轮廓和子轮廓,hierarchy的[i][3],[i][4]均为-1
CV_RETR_CCOMP //检测所有轮廓。但轮廓之间只有两个等级关系,外围为顶层,外层内的轮廓都属于它的子轮廓
CV_RETR_TREE //检测所有轮廓,轮廓之间建立一个完整的关系,就如同前面讲的例子一样。
CV_CHAIN_APPROX_NONE //保存物体边界上所有连续的轮廓点到coutours向量内
CV_CHAIN_APPROX_SIMPLE //仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不保留
噢,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参数:
实验代码在此下方,你可以下下来自己改参数来观察实验结果,并自己发散一下。
http://download.csdn.net/download/csdn_dzh/10142914