2020年12月7日
Contour Properties in findContours
OpenCV中的轮廓(Contours)是形状分析以及对象检测和识别的非常有用的工具,我们可以通过函数findContours获取。今天我们继续来学习Contours的相关的常用函数boundingRect,minAreaRect,contourArea,convexHull。
参考资料
参考链接中有一系列关于findContours获得的Contours的相关函数与属性,值得认真学习哦,感谢原作者!
测试环境
Visual studio 2019
Opencv4.3
前言
上一篇文章Contours Hierarchy and order in OpenCV我们学习了findContours不同轮廓检索模式(Contour Retrieval Mode)下返回轮廓的层次结构与排序规律,本文将继续学习findContours得到的Contours的相关的常用函数boundingRect,minAreaRect,contourArea,convexHull。上述函数在Structural Analysis and Shape Descriptors均有具体说明,本文将以代码为例来学习上述函数。
boundingRect/minAreaRect/contourArea/convexHull测试与说明
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 35 36 37 38 39 40 41 42 43 |
void findContoursInfo(string testImgPath) { Mat srcImg = imread(testImgPath); Mat grayImg, bwImg; cvtColor(srcImg, grayImg, COLOR_BGR2GRAY); threshold(grayImg, bwImg, 128, 255, CV_THRESH_BINARY); vector<vector<Point>> contours; std::vector<cv::Vec4i> hierarchy; cv::findContours(bwImg, contours, hierarchy, CV_RETR_LIST, CHAIN_APPROX_SIMPLE); int Height = srcImg.rows; int count = contours.size(); vector<vector<Point>> hull(count); for (int i = 0; i < count; i ++) { Rect tmpR = boundingRect(contours[i]); rectangle(srcImg, tmpR, Scalar(0, 0, 255), 1); RotatedRect tmpRR = minAreaRect(contours[i]); Point2f vertices[4]; //定义矩形的4个顶点 tmpRR.points(vertices); //计算矩形的4个顶点 for (int i = 0; i < 4; i++) line(srcImg, vertices[i], vertices[(i + 1) % 4], Scalar(0, 255, 0), 1); 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); convexHull(contours[i], hull[i]); int area = contourArea(contours[i]); int bbRectArea = tmpR.width * tmpR.height; int hullArea = contourArea(hull[i]); cout << "contourArea: " << area << " bbRectArea: " << bbRectArea << " HullArea: " << hullArea << " "<< " Extent: " << (float)area/ bbRectArea << " Solidity: " << (float)area / hullArea << " " << endl; } drawContours(srcImg, hull, -1, Scalar(0, 255, 255), 2); drawContours(srcImg, contours, -1, Scalar(255, 0, 255), 2); } |
第3~6行代码读取测试图像,并获取其二值化图像;
第8~10行代码通过调用findContours函数以CV_RETR_LIST模式获取二值化图像中的轮廓;
接下来开始遍历每一个轮廓并绘制外接矩形和最小外接矩形,获取相应轮廓的凸包:
第17~18行获取当前轮廓的外接矩形(boundingRect),用红色线绘制;
第20~24行获取当前轮廓的最小外接矩形(minAreaRect),用绿色线绘制;
第26~33行在原图中外接轮廓左上角附近用红色字体显示其轮廓的编号;
第35行调用convexHull函数获取当前轮廓的凸包;
第36~38行在命令行中输出轮廓面积(contourArea),外接矩形面积(bbRectArea),凸包面积(hullArea);
第39行在命令中输出contourArea/bbRectArea/hullArea/Extent/Solidity。
第41~42行在原图中绘制所有轮廓和凸包。
在原图中同时绘制了各轮廓外接矩形,最小外接矩形,凸包以及自身轮廓的图像如下:
该测试图原图如下所示:
运行上述代码后得到的命令行测试结果如下:
1 2 3 4 5 6 7 8 9 |
contourArea: 2166 bbRectArea: 13580 HullArea: 12998 Extent: 0.159499 Solidity: 0.166641 contourArea: 9780 bbRectArea: 13860 HullArea: 10173 Extent: 0.705628 Solidity: 0.961368 contourArea: 16830 bbRectArea: 17094 HullArea: 16830 Extent: 0.984556 Solidity: 1 contourArea: 6907 bbRectArea: 13875 HullArea: 6964 Extent: 0.497802 Solidity: 0.991815 contourArea: 13953 bbRectArea: 14400 HullArea: 13972 Extent: 0.968958 Solidity: 0.99864 contourArea: 5702 bbRectArea: 16236 HullArea: 11054 Extent: 0.351195 Solidity: 0.515831 contourArea: 16901 bbRectArea: 17556 HullArea: 16970 Extent: 0.962691 Solidity: 0.995934 contourArea: 10019 bbRectArea: 18834 HullArea: 10084 Extent: 0.531963 Solidity: 0.993554 contourArea: 9662 bbRectArea: 24613 HullArea: 17084 Extent: 0.392557 Solidity: 0.565558 |
接下来我们来看一下参考链接Contour Properties中提到的Extent和Solidity。
Extent:其值小于1,因为contourArea得到的是当前轮廓所包围的像素数量,而boundingRect得到的是当前轮廓外接矩形的面积。
Solidity:与Extent相同,Solidity不能大于1。形状内的像素数不能超过凸包中的像素数,因为根据定义,凸包是包围形状的最小像素集 。
在某些需要区分固定形状的物件时,通过计算和判断Extent和Solidity的范围就可以实现,例如本文中的测试图形。大家可以参考Advanced contour properties解锁本文体积函数的更多有趣的应用。
本文到此结束,感谢阅读,欢迎关注。