OpenCV图像处理——直线拟合并找出拟合直线的起点与端点

引言

对轮廓进行分析,除了可以对轮廓进行椭圆或者圆的拟合之外,还可以对轮廓点集进行直线拟合。在 OpenCV 中,直线拟合通常是通过 cv::fitLine 函数实现的,该函数采用最小二乘法对一组 2D 或 3D 点进行直线拟合。对于 2D 点集,拟合结果是一个 cv::Vec4f 类型的向量,包含了直线的方向向量和直线上的一个点。这个方向向量可以被转换为直线的斜率和截距,从而得到直线的方程。

OpenCV实现直线拟合的API如下:

bash 复制代码
void cv::fitLine(
	InputArray points,
	OutputArray line,
	int distType,
	double param,
	double reps,
	double aeps 
)
points表示待拟合的输入点集合
line在二维拟合时候输出的是vec4f类型的数据,在三维拟合的时候输出是vec6f的vector
distType表示在拟合时候使用距离计算公式是哪一种,OpenCV支持如下六种方式:
    DIST_L1 = 1
    DIST_L2 = 2
    DIST_L12 = 4
    DIST_FAIR = 5
    DIST_WELSCH = 6
    DIST_HUBER = 7
param对模型拟合距离计算公式需要参数C,5~7 distType需要参数C
reps与aeps是指对拟合结果的精度要求,一般取0.01

示例代码

cpp 复制代码
void fit_line_points(std::vector<cv::Point>& points, cv::Point2f& p1, cv::Point2f& p2)
{
	// 使用 fitLine 拟合直线
	cv::Vec4f line;
	fitLine(points, line, cv::DIST_L2, 0, 0.01, 0.01);

	cv::Point2f pointOnLine(line[2], line[3]); // 直线上的一个点
	cv::Point2f direction(line[0], line[1]);   // 直线的方向向量

	// 找到拟合直线方向上投影距离最小和最大的点(计算端点)
	float t_min = FLT_MAX, t_max = -FLT_MAX;
	cv::Point2f minPoint, maxPoint;

	for (const auto& pt : points) {
		// 投影长度 t = (pt - pointOnLine) · direction
		float t = (pt.x - pointOnLine.x) * direction.x + (pt.y - pointOnLine.y) * direction.y;
		if (t < t_min) {
			t_min = t;
			minPoint = pt;
		}
		if (t > t_max) {
			t_max = t;
			maxPoint = pt;
		}
	}

	// 使用方向向量扩展点,计算直线的两个顶点
	p1 = pointOnLine + direction * t_min;
	p2 = pointOnLine + direction * t_max;
}

调用函数:

cpp 复制代码
int main() 
{
    // 创建一些示例点
    vector<Point2f> points = {
        Point2f(100, 100), Point2f(150, 200), Point2f(200, 300),
        Point2f(300, 400), Point2f(400, 500), Point2f(500, 600)
    };

    // 拟合直线并找到直线的两个顶点
    LineEndpoints result = fitLineAndFindEndpoints(points);

    // 打印结果
    cout << "Endpoint 1: [" << result.endpoint1.x << ", " << result.endpoint1.y << "]" << endl;
    cout << "Endpoint 2: [" << result.endpoint2.x << ", " << result.endpoint2.y << "]" << endl;

    // 在图像上绘制这些点和拟合的直线
    Mat image = Mat::zeros(Size(800, 800), CV_8UC3);
    for (const auto& pt : points) {
        circle(image, pt, 5, Scalar(0, 0, 255), FILLED);
    }
    line(image, result.endpoint1, result.endpoint2, Scalar(0, 255, 0), 2);
    circle(image, result.endpoint1, 5, Scalar(255, 0, 0), FILLED);
    circle(image, result.endpoint2, 5, Scalar(255, 0, 0), FILLED);

    // 显示结果图像
    namedWindow("Fitted Line", WINDOW_AUTOSIZE);
    imshow("Fitted Line", image);
    waitKey(0);

    return 0;
}

实现结果:

代码说明

  1. 点集创建:

    • 首先创建了一组示例点,这些点可以是任意想要拟合的点集。
  2. 拟合直线:

    • cv::fitLine 函数用于对点集进行直线拟合。它返回一个包含直线参数的 Vec4f 向量:
      • line[0]line[1] 是直线的方向向量 (vx, vy)
      • line[2]line[3] 是直线上的一个点 (x0, y0)
  3. 计算最远的两个点:

    • 对于每个点,计算其在拟合直线上的投影长度 t。投影长度 t 计算方式是点到直线上某一点的向量与方向向量的点积。
    • 通过比较 t 值,找到投影最小的点 minPoint 和投影最大的点 maxPoint。这两个点就是距离最远的点。
  4. 绘制直线与最远的点:

    • 使用 line 函数在图像上绘制拟合的直线(连接 minPointmaxPoint)。
    • 使用 circle 函数标记最远的两个点。
  5. 显示结果:

    • 使用 imshow 函数显示结果图像,其中红色点表示原始点集,绿色直线是拟合的直线,蓝色点是距离最远的两个点。
相关推荐
NAGNIP19 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab20 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab20 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP1 天前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年1 天前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼1 天前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS1 天前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区1 天前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈1 天前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
端平入洛1 天前
delete又未完全delete
c++