1:轮廓发现与绘制:
实现:
void visionagin::Myfindcontours(Mat& img)
{
Mat gry, binary;
//GaussianBlur(img, img, Size(3, 3),10,20);
cvtColor(img, gry, COLOR_BGR2GRAY);
threshold(gry, binary, 140, 255, THRESH_BINARY);
imshow("二值化图像", binary);
vector<vector<Point>> contours;//存放检测结果
vector<Vec4i> h;//存放检测出的轮廓结构矩阵
findContours(binary, contours, h, RETR_TREE, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); ++i)
{
drawContours(img, contours, i, Scalar(0, 0, 200));
}
imshow("轮廓", img);
for (int j = 0; j < h.size(); ++j)
{
cout << h[j] << endl;
}
}
2:轮廓面积:
3:轮廓长度:
4:轮廓外接多边形:
矩形是常见的几何形状,矩形的处理和分析方法也较为简单
OpenCV4
提供了两个函数用于
求取轮廓外接矩形,分别是求取轮廓最大外接矩形的boundingRect()函数和求取轮廓最小外接矩形
minAreaRect().
寻找轮廓
外接最大矩形就是寻找轮廓X
方向和Y
方向两端的像素,该矩形的长和宽分别与图
像的两条轴平行.
![](https://i-blog.csdnimg.cn/blog_migrate/523f37567586628d5b4540e496771c5d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/88bdbdfb1c69b607aad9d5c97145d2c8.png)
实现:
void visionagin::Mycontours_areaANDlength()
{
vector<Point>contour;//存放轮廓结果
contour.push_back(Point(10, 30));
contour.push_back(Point(20, 43));
contour.push_back(Point(0, 24));
contour.push_back(Point(30, 30));
double res=contourArea(contour, false);//返回double
double length = arcLength(contour, 1);//返回double
cout << res << endl;
cout << length << endl;
Mat src = imread("C:\\Users\\86176\\Downloads\\visionimage\\contour.jfif");
Mat binary;
Canny(src, binary, 500, 900, 5);
imshow("binary", binary);
vector<vector<Point>>contours;
findContours(binary, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); ++i)
{
//drawContours(src, contours, i, Scalar(0, 200, 0));//绘制检测出的轮廓
Rect rect = boundingRect(contours[i]);//最大外接矩形
//rectangle(src, rect, Scalar(0, 0, 200));
RotatedRect rrect = minAreaRect(contours[i]);//旋转矩形类RotatedRect,最小外接矩形
Point2f points[4];
rrect.points(points);//旋转矩形类points方法
Point center = rrect.center;
circle(src, center, 1, Scalar(0, 200, 0));
for (int i = 0; i < 4; ++i)
{
if (i == 3)
{
line(src, points[i], points[0], Scalar(200, 0, 0));
break;
}
line(src, points[i], points[i + 1], Scalar(200, 0, 0));
}
}
namedWindow("res", WINDOW_NORMAL);
imshow("res", src);
}
先画出检测出的轮廓绿色:
最大外接矩形红色:
最小外接矩形 蓝色:
有时候用矩形逼近轮廓会造成较大的误差 ,
对于圆形轮廓的逼近矩形围成的面积比真实轮廓面积大,如果寻找逼近轮廓
的多边形,那么多
边形围成的面
积会更
加接近真实的圆形轮廓面积.
OpenCV
提供了
appro
xP
oly
DP()
函数用于
寻找逼近轮廓的多边形
![](https://i-blog.csdnimg.cn/blog_migrate/87ff41dedce1f598531a31831fa412c8.png)
实现:
void visionagin:: Myapproxpolydp()
{
Mat src = imread("C:\\Users\\86176\\Downloads\\visionimage\\contour.jfif");
imshow("原图", src);
Mat canny;
Canny(src, canny, 20, 50);
imshow("边缘", canny);
Mat core = getStructuringElement(0, Size(3, 3));//结构元素
dilate(canny, canny, core);//腐蚀
imshow("dilate",canny);
vector<vector<Point>> contours;
findContours(canny, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);//轮廓检测
for (int i = 0; i < contours.size(); ++i)
{
RotatedRect rrect;
rrect = minAreaRect(contours[i]);//每个轮廓的最小外接矩形
Point center = rrect.center;
circle(src, center, 2, Scalar(0, 0, 200));//用最小外接矩形的中心绘制轮廓中心
Mat result;
approxPolyDP(contours[i], result, 4, true);
for (int j = 0; j < result.rows; ++j)//绘制多边形轮廓
{
if (j == result.rows - 1)//绘制最后一个顶点与第一个顶点的连线
{
Point p1 = result.at<Vec2i>(j);
Point p2 = result.at<Vec2i>(0);
line(src, p1, p2, Scalar(0, 200, 0));
break;
}
Point p1 = result.at<Vec2i>(j);
Point p2 = result.at<Vec2i>(j + 1);
line(src, p1, p2, Scalar(0, 200, 0));
}
if (result.rows == 3)
{
putText(src, "three", center, 0, 1, Scalar(200, 0, 0));//不支持中文
}
if (result.rows == 4)
{
putText(src, "4", center, 0, 1, Scalar(200, 0, 0));
}
if (result.rows == 5)
{
putText(src, "5", center, 0, 1, Scalar(200, 0, 0));
}
if (result.rows == 6)
{
putText(src, "6", center, 0, 1, Scalar(200, 0, 0));
}
if (result.rows == 8)
{
putText(src, "8", center, 0, 1, Scalar(200, 0, 0));
}
if (result.rows >12)
{
putText(src, "circle", center, 0, 1, Scalar(200, 0, 0));
}
}
imshow("结果", src);
}
5.点到轮廓的距离
点到轮廓的距离,对于计算轮廓在图像中的位置、两个轮廓之间的距离以及确定图像上某一点
是否在轮廓内部具有重要的作用.
OpenCV
提供了计算像素点距离轮廓最小距离的
pointPolygonTestO函数
![](https://i-blog.csdnimg.cn/blog_migrate/f2f3d11705b8b0df33c3dc68da742800.png)
6.凸包检测
有时物体的形状过于复杂,用多边形逼近后处理起来依然较为复杂
例如入手、海星等.对于
形状较为复杂的物体,可以利用凸包近似表示.凸包是图形学中常见的概念
将二维平面上的点集
最外层的点连接起来构成的凸多边形称为凸包.虽然凸包检测也是对轮廓
进行多边
形逼近,但是逼
近结果一定为凸多边形.
![](https://i-blog.csdnimg.cn/blog_migrate/7a92c5cceb5604ef86d9811a45df61ee.png)
实现:
void visionagin:: Myconvxhull()
{
Mat src = imread("C:\\Users\\86176\\Downloads\\visionimage\\seastar.jfif");
namedWindow("原图", WINDOW_NORMAL);
imshow("原图", src);
Mat canny;
Canny(src, canny, 150, 100);
Mat core = getStructuringElement(0, Size(5, 5));//结构元素
dilate(canny, canny, core);//腐蚀
namedWindow("canny", WINDOW_NORMAL);
imshow("canny", canny);
vector<vector<Point>>contours;
findContours(canny, contours, RETR_TREE, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size(); i++)
{
vector<Point>result;
convexHull(contours[i], result, true, true);
for (int j = 0; j < result.size(); j++)
{
if (j == result.size() - 1)
{
line(src, result[j], result[0], Scalar(0, 0, 200));
break;
}
line(src, result[j], result[j + 1], Scalar(0, 0, 200));
}
}
imshow("res", src);
}