一、图像的轮廓检测
轮廓检测函数:
findContours(lnputArray image, OutputArrayOfArrays contours,OutputArray hierarchy, int mode, int method, Point offset = Point())
image:输入图像,数据类型为CV_8U的单通道灰度图像或者二值化图像。contours:检测到的轮廓,每个轮廓中存放着像素的坐标。
mode:轮廓检测模式标志。
method:轮廓逼近方法标志。
offset:每个轮廓点移动的可选偏移量。这个函数主要用在从ROI图像中找出的轮廓并基于整个图像分析轮廓的场景中。
轮廓绘制函数:
drawContours(InputoutputArray image, lnputArrayOfArrays contours,int contourldx, const Scalar & color, int thickness = 1, int lineType = LINE_8,hierarchy =, lnputArray noArray (), int maxLevel = INT_PAX, Point offset = Point())
image:绘制轮廓的目标图像。
contours:所有将要绘制的轮廓。
contourldx:要绘制的轮廓的参数,如果是负数,则绘制所有的轮廓。
color:绘制轮廓的颜色。
应用案例代码如下:
int main() {
//更改输出界面的颜色
system("color F0");
//读取图片
Mat src = imread("图片1.png");
if (src.empty())
{
printf("不能打开空图片");
return -1;
}
Mat gray, binary;
//转化为灰度图
cvtColor(src, gray, COLOR_BGR2GRAY);
//高斯平滑滤波
GaussianBlur(gray, gray, Size(13, 13), 4, 4);
//自适应二值化
threshold(gray, binary, 170, 255, THRESH_BINARY | THRESH_OTSU);
//轮廓检测
vector<vector<Point>>contours;
//存放轮廓结构变量
vector<Vec4i>hierarchy;
findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
//绘制轮廓
for (int i = 0; i < hierarchy.size(); i++)
{
cout << hierarchy[i] << endl;
}
for (int t = 0; t < contours.size(); t++)
{
drawContours(src, contours, -1, Scalar(0, 0, 255), 2, 6);
imshow("q", src);
waitKey(0);
}
//输出轮廓结构描述
return 0;
}
二、轮廓信息统计
轮廓面积计算函数:
contourArea(lnputArray contour, bool oriented = false)
contour:轮廓的像素点。
oriented:区域面积是否具有方向的标志,true表示面积具有方向性,false表示不具有方向性,默认值为不具有方向性的false。
轮廓长度计算函数:
arcLength(InputArray curve, bool closed)
curve:轮廓或者曲线的2D像素点。
closed:轮廓或者曲线是否闭合标志,true表示闭合。
应用案例如下:
int main() {
//更改输出界面的颜色
system("color F0");
//读取图片
Mat src = imread("图片1.png");
if (src.empty())
{
printf("不能打开空图片");
return -1;
}
Mat gray, binary;
//转化为灰度图
cvtColor(src, gray, COLOR_BGR2GRAY);
//高斯平滑滤波
GaussianBlur(gray, gray, Size(13, 13), 4, 4);
//自适应二值化
threshold(gray, binary, 170, 255, THRESH_BINARY | THRESH_OTSU);
//轮廓检测
vector<vector<Point>>contours;
//存放轮廓结构变量
vector<Vec4i>hierarchy;
findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
//输出轮廓面积
for (int i = 0; i < contours.size(); i++)
{
double area1 = contourArea(contours[i]);
cout << area1 << endl;
}
//输出轮廓长度
for (int i = 0; i < contours.size(); i++)
{
double length1 = arcLength(contours[i], true);
cout << length1 << endl;
}
return 0;
}
三、轮廓外接多边形拟合
轮廓外接矩形函数:
boundingRect(lnputArray array)
轮廓最小面积外界矩形:
minAreaRect(lnputArray points)
array:输入的灰度图像或者2D点集,数据类型为vector或者Mat。
轮廓多边形拟合:
approxPolyDP(InputArray curve, OutputArray approxCurve,double epsilon, bool closed)
curve:输入轮廓像素点。
approxCurve:多边形逼近结果,以多边形顶点坐标的形式给出。
epsilon:逼近的精度,即原始曲线和逼近曲线之间的最大距离。
closed:逼近曲线是否为封闭曲线的标志,true表示曲线封闭,即最后一个顶点与第一个顶点相连。
轮廓外接矩形函数、轮廓最小面积外界矩形应用案例:
int main() {
//读取图片
Mat src = imread("图片1.png");
if (src.empty())
{
printf("不能打开空图片");
return -1;
}
//深拷贝两张图像,用来做不同的外接图形操作
Mat img1, img2;
src.copyTo(img1);
src.copyTo(img2);
//canny的边缘检测
Mat canny;
Canny(src, canny, 80, 160, 3, false);
//膨胀运算,去除细小缝隙
Mat kernel = getStructuringElement(0, Size(3, 3));
dilate(canny, canny, kernel);
//轮廓检测
vector<vector<Point>>contours;
//存放轮廓结构变量
vector<Vec4i>hierarchy;
findContours(canny, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
//寻找轮廓的外接矩形
for (int n = 0; n < contours.size(); n++)
{
//最大外接矩形
Rect rect = boundingRect(contours[n]);
rectangle(img1, rect, Scalar(0, 0, 255), 2, 8, 0);
//最小外接矩形
RotatedRect rrect = minAreaRect(contours[n]);
Point2f points[4];
//读取最小外接矩形的四个顶点
rrect.points(points);
//最小外接矩形中心
Point2f cpt = rrect.center;
//绘制转转矩形与中心位置
for (int i = 0; i < 4; i++)
{
if (i == 3)
{
line(img2, points[i], points[0], Scalar(0, 255, 0), 2, 8, 0);
break;
}
line(img2, points[i], points[i+1], Scalar(0, 255, 0), 2, 8, 0);
}
//绘制矩形中心
circle(img2, cpt, 4, Scalar(255, 0, 0), -1, 8, 0);
imshow("q", img1);
imshow("w", img2);
waitKey(0);
return 0;
}
}
轮廓多边形拟合应用案例:
void drawapp(Mat result, Mat img2)
{
for (int n = 0; n < result.rows; n++)
{
//将第一个点与最后一个点相连
if (n == result.rows - 1)
{
Vec2i point1 = result.at<Vec2i>(n);
Vec2i point2 = result.at<Vec2i>(0);
line(img2, point1, point2, Scalar(0, 255, 0), 2, 8, 0);
break;
}
Vec2i point1 = result.at<Vec2i>(n);
Vec2i point2 = result.at<Vec2i>(n + 1);
line(img2, point1, point2, Scalar(0, 255, 0), 2, 8, 0);
}
}
int main() {
//读取图片
Mat src = imread("图片1.png");
if (src.empty())
{
printf("不能打开空图片");
return -1;
}
//canny的边缘检测
Mat canny;
Canny(src, canny, 80, 160, 3, false);
//膨胀运算,去除细小缝隙
Mat kernel = getStructuringElement(0, Size(3, 3));
dilate(canny, canny, kernel);
//轮廓检测
vector<vector<Point>>contours;
//存放轮廓结构变量
vector<Vec4i>hierarchy;
findContours(canny, contours, hierarchy, 0, 2, Point());
//绘制多边形
for (int i = 0; i < contours.size(); i++)
{
//用最小外接矩形求取轮廓中心
RotatedRect rrect = minAreaRect(contours[i]);
//最小外接矩形中心
Point2f cpt = rrect.center;
circle(src, cpt, 2, Scalar(255, 0, 0), 2, 8, 0);
Mat result;
//进行多边形拟合
approxPolyDP(contours[i], result, 4, true);
//绘制多边形
drawapp(result, src);
}
imshow("q", src);
waitKey(0);
return 0;
}