多边形拟合

多边形近似

API

approxPolyDP(curve, approxCurve, epsilon, closed)
  • curve:输入像素轮廓点,类型为vector<Point>或者Mat
  • approxCurve:多边形逼近结果,以多边形顶点坐标的形式给出,类型为 vector<Point2f>CV_32SC2 类型的 Nx1Mat 类矩阵
  • epsilon:逼近的精度,即原始曲线和逼近曲线之间的最大距离,类型为 double
  • closed:逼近曲线是否为封闭曲线的标志,true 表示曲线封闭,即最后一个顶点与第一个顶点相连

示例代码:

#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
// 绘制轮廓函数
inline void drawapp(vector<Point2f> result, Mat img2)
{
for (int i = 0; i < result.size(); i++)
{
// 最后一个坐标点与第一个坐标点相连
if (i == result.size() - 1)
{
Point2f point1 = result.at(i);
Point2f point2 = result.at(0);
line(img2, point1, point2, Scalar(0, 255, 0), 2);
break;
}
Point2f point1 = result.at(i);
Point2f point2 = result.at(i + 1);
line(img2, point1, point2, Scalar(0, 255, 0), 2);
}
}
int main()
{
Mat img = imread("/home/kslas/test.jpg");
imshow("original", img);
// 边缘检测
Mat canny;
Canny(img, 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);
// 绘制多边形
for (int i = 0; i < contours.size(); i++)
{
// 用最小外接矩形求取轮廓中心
RotatedRect rrect = minAreaRect(contours[i]);
Point2f center = rrect.center;
circle(img, center, 2, Scalar(0, 255, 0), 2);
vector<Point2f> result;
approxPolyDP(contours[i], result, 4, true); // 多边形逼近
drawapp(result, img);
}
imshow("result", img);
waitKey(0);
destroyAllWindows();
return 0;
}

运行结果:

凸包检测

简介

  • 有时物体的形状过于复杂,用多边形逼近后处理起来依然较为复杂,例如人手、海星等。对于形状较为复杂的物体,可以利用凸包近似表示

  • 凸包是图形学中常见的概念,将二维平面上的点集最外层的点连接起来构成的凸多边形称为凸包

  • 虽然凸包检测也是对轮廓进行多边形逼近,但是逼近结果一定为凸多边形

  • 凸包检测往往用于加强approxPolyDP()的结果

API

convexHull(points, hull, clockwise, returnPoints)
  • points:输入的二维点集或轮廓坐标,类型为 vector<Point> 或者 Mat
  • hull:输出凸包的顶点坐标或索引,类型为 vector<Point> 或者 vector<int>
  • clockwise:方向标志。当参数取值为 true 时,凸包顺序为顺时针方向;当参数取值为 false 时,凸包顺序为逆时针方向
  • returnPoints:输出数据的类型标志。当参数为 true 时,第二个参数输出的结果是凸包顶点的坐标;当参数取值为为 false 时,第二个参数输出的结果是凸包顶点的索引

示例代码:

在该程序中,首先对图像进行二值化,并利用开运算消除二值化过程中产生的较小区域,之后寻找图像的轮廓,最后对图像中的每一个轮廓进行凸包检测,并绘制凸包的顶点和每一条边

#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main()
{
Mat img = imread("/home/kslas/OpenCV/hand.jpg");
// 二值化
Mat gray, binary;
cvtColor(img, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 230, 255, THRESH_BINARY);
bitwise_not(binary, binary);
// 开运算消除细小区域
Mat k = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(binary, binary, MORPH_OPEN, k);
imshow("binary", binary);
// 轮廓发现
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(binary, contours, hierarchy, 0, 2);
for (int i = 0; i < contours.size(); i++)
{
// 计算凸包
vector<Point> hull;
convexHull(contours[i], hull);
// 绘制凸包
for (int j = 0; i < hull.size(); j++)
{
// 绘制凸包顶点
circle(img, hull[j], 4, Scalar(255, 0, 0), 2);
// 连接凸包
if (j == hull.size() - 1)
{
line(img, hull[j], hull[0], Scalar(0, 0, 255), 2);
break;
}
line(img, hull[j], hull[j + 1], Scalar(0, 0, 255), 2);
}
}
imshow("hull", img);
waitKey(0);
destroyAllWindows();
return 0;
}

运行结果:



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   TNTksals  阅读(514)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示