OpenCV 使用 findContours 函数 Note1: 利用各个轮廓的相互阶层(hierarchy)关系

当前位置:首页狮威官方网站 >

狮威官方网站

OpenCV 使用 findContours 函数 Note1: 利用各个轮廓的相互阶层(hierarchy)关系

时间:2019-11-18本站浏览次数:102

       

​输入图像

void Detect_Object(Mat img){ Mat gray, binaryIMG; Mat correct_IMG; cvtColor(img, gray, CV_BGR2GRAY); Canny(gray, binaryIMG, 90, 180); blur(binaryIMG, binaryIMG, Size(3, 3)); // Find contours vector<vector<Point> > contours; vector<Vec4i> hierarchy; double TargetArea = 0; findContours(binaryIMG, contours, hierarchy, RETR_TREE, CV_CHAIN_APPROX_NONE, Point(0, 0)); for (int i = 0; i < contours.size(); i++) { drawContours(img, contours, i, Scalar(0, 255, 0), 2, 8, hierarchy, 0, Point()); }}

先上代码, 上述函数是寻找一个图像内的所有轮廓。

执行后,利用

drawContours(img, contours, i, Scalar(0, 255, 0), 2, 8, hierarchy, 0, Point());

 这个函数,会画出所有图像内的轮廓。

执行上述代码后,我的代码上显示 contour.size() ,即轮廓个数是34个。 这个轮廓个数不是绝对的, 结果由你对canny()选取的阈值, blur() mask的大小选取都有影响。

Canny 和 Blurring 算法结果图像。

 

红色显示的是 FindContours函数所检测到的轮廓。

 

你或许会觉得,最终显示的结果像一幅捕捉边缘的图像,即Edge Map。也会不解,有了Canny,何须多此一举在寻找轮廓。

接下来我就要介绍本章的主角轮廓 Hierarchy的阶层关系。

先看一段修改后的代码:

for (int i = 0; i < contours.size(); i++) { if (hierarchy[i][3] == -1) { drawContours(img, contours, i, Scalar(0, 0, 255), 1, 8, hierarchy, 0, Point()); } }

 

这段代码中,多了一段条件语句,语句里写了 

hierarchy[i][3] == -1

首先,我们确认一下结果:

这次的结果里,只检测出了最外围轮廓。很明显

hierarchy[i][3] == -1 起了决定性的作用。 我们先看看OpenCV官方文件是怎么写的。

OpenCV represents it as an array of four values : [Next, Previous, First_Child, Parent].   (Link me: https://docs.opencv.org/3.4.0/d9/d8b/tutorial_py_contours_hierarchy.html)

 

hierarchy[i][3] == -1, 这里的hierarchy[i]指的是第i个轮廓的阶层关系。而hierarchy[i][0],hierarchy[i][1],hierarchy[i][2],hierarchy[i][3]分别指的是Next, Previous, First_child, Parent。我们设定的hierarchy[i][3]== -1 的意思就是 “轮廓没有父母”, 即“这个轮廓没有上层阶级的轮廓”。同理, hierarchy[i][2]== -1 的意思就是 “此轮廓没有第一个孩子”,即“此轮廓没有下层阶级的轮廓”。至于,hierarchy[][0],hierarchy[][1] 指的是此轮廓的后一个轮廓,和前一个轮廓。他们都是同一个阶级的轮廓。这个前后顺序可能是很随意的,至今还没找到规律。所以还没有到怎么利用他们。所以,

hierarchy[i][3]== -1 条件下的结果, 是选中了没有父母的轮廓,即他的外围没有包围他的轮廓。再看看

hierarchy[i][2]== -1 条件下的结果:

 

和预想的一样,它只标出了没有“孩子”的轮廓,即此轮廓内没有更小的轮廓。对了,我要强调一下,这个例子里我在使用FindContours函数的时候,我用了RETR_TREE 模式。这个模式是“万能的”,把图像内各轮廓的亲属关系都联系上了。简而言之,你能知道一个轮廓的”爷爷奶奶“,”孙子孙女“。甚至更深的祖辈关系。 opencv 提供了各种模式,RETR_LIST, RETR_EXTERNAL等。 上面的官方文件有详细说明。RETR_LIST 就是这个图像的轮廓只可能是两个阶层的其中之一,要么你就是爹, 要么你就是儿子。本章只讲RETR_TREE。这时候你可能还没领会到Hierarchy的魅力。 他不会马上帮你挑出你最想要的信息,但是他确实个帮你排除“杂质”帮手。例如, 我们这次测试的Heliport图像, 很明显这个图像里的“H”是叫无人机去识别, 并且在其中心降落的。 那我们怎么去识别他呢? 如果不用Deep Learning。我们可以在这个图像里找没有孩子的轮廓,但没有孩子的轮廓候补也很多。怎么办? 很简单, 选取轮廓面积最大的,或者大于一定面积以上的,其实方法真的很多。只要你多加一个条件语句。简单的看下代码:

for (int i = 0; i < contours.size(); i++) { if (hierarchy[i][2] == -1 && contourArea(contours[i]) > 9800) { drawContours(img, contours, i, Scalar(0, 0, 255), 2, 8, hierarchy, 0, Point()); } }

 

我加了一段 面积大于 9800 像素的条件。结果就找到了 “H”。

 

你问我怎么算的9800? 估算的, 但是我想说的不是面积这部分,利用面积也只是方法之一。 想要更精确确定的方法有很多。比如是高和宽的比例。

今天主要是为了介绍hierarchy的魅力,其实利用好真的能排除很多没用的信息。hierarchy 只是OpenCV Contours 这部分的魅力之一, 仔细翻阅官方文件你会发现,opencv 这部分还真的准备了很多宝贝。

 

 

 

 

 




公司地址:安徽省合肥市庐江县城西开发区
联系人:韩慧娟 18508929573
黄小华 15224782275
电话:15576790792 传真:5m2jlo@msn.com
邮箱:sbqbzjumz@163.com

粤公网安备 44030702001579号

狮威国际投注@