2020年12月2日
Contours Hierarchy and order in OpenCV
Opencv中的轮廓是形状分析以及对象检测和识别的非常有用的工具。本文将记录findContours函数,在不同的轮廓检索模式(Contour Retrieval Mode)下,所得到的轮廓的层次结构,即Contours中的父子关系,以及轮廓的排序规则。
参考资料
本文中的部分图像来源于上述链接,在此致谢原作者!
前言
我们先来了解一下findContours函数的参数,如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void cv::findContours ( //二值化输入图像,找到轮廓就像从黑色背景中找到白色物体。因此要找到的对象应该是白色,背景应该是黑色。 InputArray image, //输出检测到的轮廓,每个轮廓均已点集保存。 OutputArrayOfArrays contours, //可选输出(std::vector<cv::Vec4i>),记录轮廓的层次信息,hierarchy[i][0]/hierarchy[i][1]/hierarchy[i][2]/hierarchy[i][3], //分别表示第i个轮廓的同层次下一个轮廓,前一个轮廓,第一个子轮廓与父轮廓,若当前轮廓没有相应的层次关系,则其值为-1. OutputArray hierarchy, //轮廓检索模式(Contour Retrieval Mode: RETR_EXTERNAL/RETR_LIST /RETR_CCOMP /RETR_TREE/RETR_FLOODFILL ) int mode, int method,//轮廓近似法 Point offset = Point() //每个轮廓点移动的可选偏移量 ) |
在findContours函数中,RETR_FLOODFILL是一种比较特殊的存在,介绍该模式的资料非常少,本文也暂不介绍。接下来,我们来测试findContours设置不同的Contour Retrieval Mode时返回轮廓的层次结构与排序规律。
1. Hierarchy and order in RETR_EXTERNAL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
void findContoursInfo(string testImgPath) { Mat srcImg = imread(testImgPath); Mat grayImg, bwImg; cvtColor(srcImg, grayImg, COLOR_BGR2GRAY); threshold(grayImg, bwImg, 128, 255, CV_THRESH_BINARY); int Height = srcImg.rows; vector<vector<Point>> contours; std::vector<cv::Vec4i> hierarchy; cv::findContours(bwImg, contours, hierarchy,CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point()); int count = contours.size(); for (int i = 0; i < count; i ++) { Rect tmpR = boundingRect(contours[i]); Point textOrg; textOrg.x = tmpR.tl().x; textOrg.y = tmpR.tl().y + 20; if (textOrg.y > Height) { textOrg.y = Height; } putText(srcImg , FileUtils::toString(i), textOrg,1,1,Scalar(0,0,255),2,1); cout << "List Rect Info:" << tmpR.tl()<<" " << tmpR.width << " " << tmpR.height <<" " << hierarchy[i] <<endl; } imshow("CV_RETR_EXT", srcImg ); } |
1 2 3 4 |
boundingRect.tl() width height hierarchy(next, pre, child,parent) [5, 103] 660 339 [1, -1, -1, -1] [167, 19] 501 6 [2, 0, -1, -1] [26, 11] 107 6 [-1, 1, -1, -1] |
根据图片以及输出轮廓的外接矩形(boundingRect)的信息可知,在CV_RETR_EXTERNAL模式下,输出轮廓的排序方式以每个轮廓的boundingRect的左上角Y坐标降序排列。
2. Hierarchy and order in RETR_LIST
1 2 3 4 5 6 7 8 9 10 |
boundingRect.tl() width height hierarchy(next, pre, child,parent) [163, 293] 160 44 [1, -1, -1, -1] [164, 240] 147 28 [2, 0, -1, -1] [131, 200] 228 164 [3, 1, -1, -1] [72, 158] 546 239 [4, 2, -1, -1] [67, 153] 556 249 [5, 3, -1, -1] [10, 107] 650 331 [6, 4, -1, -1] [5, 103] 660 339 [7, 5, -1, -1] [167, 19] 501 6 [8, 6, -1, -1] [26, 11] 107 6 [-1, 7, -1, -1] |
将【Hierarchy and order in RETR_EXTERNAL】小节代码中findContours函数的参数mode修改为CV_RETR_LIST,可以观察到同一张图片中CV_RETR_LIST模式下的轮廓信息输出。
在CV_RETR_LIST模式下,输出轮廓的排序方式以每个轮廓的boundingRect的左上角Y坐标降序排列。
3. Hierarchy and order in RETR_CCOMP
1 2 3 4 5 6 7 8 9 10 |
boundingRect.tl() width height hierarchy(next, pre, child,parent) [131, 200] 228 164 [3, -1, 1, -1] [163, 293] 160 44 [2, -1, -1, 0] [164, 240] 147 28 [-1, 1, -1, 0] [67, 153] 556 249 [5, 0, 4, -1] [72, 158] 546 239 [-1, -1, -1, 3] [5, 103] 660 339 [7, 3, 6, -1] [10, 107] 650 331 [-1, -1, -1, 5] [167, 19] 501 6 [8, 5, -1, -1] [26, 11] 107 6 [-1, 7, -1, -1] |
将【Hierarchy and order in RETR_EXTERNAL】小节代码中findContours函数的参数mode修改为CV_RETR_CCOMP,可以观察到同一张图片中CV_RETR_CCOMP模式下的轮廓信息输出。
在CV_RETR_CCOMP模式下,同一层级的输出轮廓的排序方式以每个轮廓的boundingRect的左上角Y坐标降序排列。
为了更清晰的说明CV_RETR_CCOMP模式下各层级轮廓的关系,我们使用了参考链接中的图,并对图中标注的序号根据实际情况进行了修改。
4. Hierarchy and order in RETR_TREE
1 2 3 4 5 6 7 8 9 10 |
boundingRect.tl() width height hierarchy(next, pre, child,parent) [5, 103] 660 339 [7, -1, 1, -1] [10, 107] 650 331 [-1, -1, 2, 0] [67, 153] 556 249 [-1, -1, 3, 1] [72, 158] 546 239 [-1, -1, 4, 2] [131, 200] 228 164 [-1, -1, 5, 3] [163, 293] 160 44 [6, -1, -1, 4] [164, 240] 147 28 [-1, 5, -1, 4] [167, 19] 501 6 [8, 0, -1, -1] [26, 11] 107 6 [-1, 7, -1, -1] |
将【Hierarchy and order in RETR_EXTERNAL】小节代码中findContours函数的参数mode修改为CV_RETR_TREE,可以观察到同一张图片中CV_RETR_TREE模式下的轮廓信息输出。
在CV_RETR_TREE模式下,同一层级的输出轮廓的排序方式以每个轮廓的boundingRect的左上角Y坐标降序排列。
为了更清晰的说明CV_RETR_TREE模式下各层级轮廓的关系,我们使用了参考链接中的图,并对图中的序号根据实际输出进行了修改。
本文到此结束,感谢阅读,欢迎关注。