在上一篇文章:OpenCV之轮廓查找与绘制(findContours和drawContours函数详解)中,详细介绍了利用OpenCV进行轮廓的查找与绘制,但是实战中发现,我们经常需要绘制最大轮廓(主要目的是将小轮廓等噪声去除)以及绘制轮廓的外接矩形。下面这篇文章详细介绍一下如何绘制最大轮廓自己绘制轮廓的外接矩形。
查找最大轮廓时用到一个函数contourArea函数,其具体用法如下:
contourArea(InputArray contour, bool oriented=false);
计算图像轮廓的面积
• contour : 输入的点,一般是图像的轮廓点
• oriented = false : 默认值为false,表示某一个方向上的轮廓的面积值
核心代码如下:
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(image, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());//寻找最外层轮廓
Mat imageContours0 = Mat::zeros(image.size(), CV_8UC1); //最小外接正矩形画布
vector<double> g_dConArea(contours.size());
for (int i = 0; i < contours.size(); i++)
{
//绘制轮廓
/*drawContours(imageContours0, contours, i, Scalar(255), 1, 8, hierarchy);*/
//计算轮廓的面积
g_dConArea[i] = contourArea(contours[i]);
cout << "【用轮廓面积计算函数计算出来的第" << i << "个轮廓的面积为:】" << g_dConArea[i] << endl;
}
//寻找面积最大的部分
int max = 0;
for (int i = 1; i < contours.size(); i++) {
if (g_dConArea[i] > g_dConArea[max]) {
max = i;
}
}
//输出最大面积即索引
cout << "max=" << g_dConArea[max] << endl;
cout << "idx=" << max << endl;
//绘制轮廓
drawContours(imageContours0, contours, max, Scalar(255), 1, 8, hierarchy);
上述操作是根据图像边缘轮廓面积得到的最大值,进而只绘制最大的边缘,其输出结果如下:
面积结果:
当然,完整代码可以参考:
https://download.csdn.net/download/didi_ya/15385236
minAreaRect( InputArray points );
返回包覆输入信息的最小斜矩形
• points:输入信息,可以为包含点的容器(vector)或是Mat。
返回类型为RotatedRect类
关于RotatedRect类:
RotatedRect该类表示平面上的旋转矩形,该类对象有三个重要属性:矩形中心点(质心),边长(长和宽),旋转角度。三种构造函数和三种成员操作函数,RotatedRect类定义如下:
class CV_EXPORTS RotatedRect
{
public:
//构造函数
RotatedRect();
RotatedRect(const Point2f& center, const Size2f& size, float angle);
RotatedRect(const CvBox2D& box);
//!返回矩形的4个顶点
void points(Point2f pts[]) const;
//返回包含旋转矩形的最小矩形
Rect boundingRect() const;
//!转换到旧式的cvbox2d结构
operator CvBox2D() const;
Point2f center; //矩形的质心
Size2f size; //矩形的边长
float angle; //旋转角度,当角度为0、90、180、270等时,矩形就成了一个直立的矩形
【注意】:外接最小正小矩形参考函数boundingRect,其用法与minAreaRect类似,但是返回的类是Rect类。
#include
#include "iostream"
using namespace std;
using namespace cv;
int main(int argc, char *argv[])
{
Mat imageSource = imread("D:/Desktop/1.png", 0);
imshow("Source Image", imageSource);
Mat image;
GaussianBlur(imageSource, image, Size(3, 3), 0);//高斯滤波
Canny(image, image, 100, 250);//canny算子边缘检测
//寻找最外层轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;//存储查找到的第i个轮廓的后[i][0]、前[i][1]、父[i][2]、子轮廓[i][3]
findContours(image, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
Mat imageContours0 = Mat::zeros(image.size(), CV_8UC1); //最小外接正矩形画布
Mat imageContours = Mat::zeros(image.size(), CV_8UC1); //最小外接矩形画布
Mat imageContours1 = Mat::zeros(image.size(), CV_8UC1); //最小外接圆画布
for (int i = 0; i < contours.size(); i++)
{
//绘制轮廓
drawContours(imageContours0, contours, i, Scalar(255), 1, 8, hierarchy);
drawContours(imageContours, contours, i, Scalar(255), 1, 8, hierarchy);
drawContours(imageContours1, contours, i, Scalar(255), 1, 8, hierarchy);
//绘制轮廓的最小外接正矩形
Rect boundRect = boundingRect(Mat(contours[i]));
rectangle(imageContours0, Point(boundRect.x, boundRect.y), Point(boundRect.x + boundRect.width, boundRect.y + boundRect.height), Scalar(255), 2, 8);
//绘制轮廓的最小外结矩形
RotatedRect rect = minAreaRect(contours[i]);
Point2f P[4];//初始化矩形四个顶点坐标
rect.points(P);
for (int j = 0; j <= 3; j++)
{
line(imageContours, P[j], P[(j + 1) % 4], Scalar(255), 2);
}
//绘制轮廓的最小外结圆
Point2f center; float radius;
minEnclosingCircle(contours[i], center, radius);
circle(imageContours1, center, radius, Scalar(255), 2);
}
imshow("最小正外接矩形", imageContours0);
imshow("MinAreaRect", imageContours);
imshow("MinAreaCircle", imageContours1);
waitKey(0);
return 0;
}
最小外接斜矩形图像:
最小外接正矩形图像:
当然也可以将其外接框框绘制在原图上,这样可以使图像看起来更加整洁直观,如果想要代码,可以参考:
https://download.csdn.net/download/didi_ya/15368183
如果对你有所帮助,记得点赞哟~
参考:
【1】https://blog.csdn.net/qq_23880193/article/details/49256999
【2】https://blog.csdn.net/u011028345/article/details/75354953
【3】https://blog.csdn.net/dcrmg/article/details/52260699
【4】https://www.cnblogs.com/little-monkey/p/7429579.html