直线拟合算法

本文介绍了一种用于计算机视觉应用中的直线拟合方法,该方法基于最小二乘法,能够有效地处理XY坐标均有误差的情况,适用于图像处理中直线位置的精确提取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在计算机视觉的应用中,经常会用到提取一条直线的精确位置这样的工作。这时就要用到直线的拟合算法了。

这里,我也贴一个利用最小二乘法计算最佳拟合直线的代码。

这个代码是我以前学习《机器视觉算法与应用(双语版)》[德] 斯蒂格(Steger C) 著;杨少荣 等 译 的书时写的。所有的公式推导都在书中 3.8.1 ,还算比较有用。
与一元线性回归算法的区别:一元线性回归算法假定 X 是无误差的,只有 Y 有误差。 而这个算法假设每个点的 X Y 坐标的误差都是符合 0 均值的正态分布的。 因此,在计算机视觉的应用中比普通的一元线性回归拟合的结果要好。

#include <QVector>
#include <QPoint>
#include <math.h>

/// 本代码用到了 Qt5 中的 QVector 和 QPoint。但是可以很容易的改为其他数组类型。

/**
  * 最小二乘法直线拟合(不是常见的一元线性回归算法)
  * 将离散点拟合为  a x + b y + c = 0 型直线
  * 假设每个点的 X Y 坐标的误差都是符合 0 均值的正态分布的。
  * 与一元线性回归算法的区别:一元线性回归算法假定 X 是无误差的,只有 Y 有误差。
  */
bool lineFit(const QVector<QPoint> &points, double &a, double &b, double &c)
{
     int size = points.size();
     if(size < 2)
     {
         a = 0;
         b = 0;
         c = 0;
         return false;
     }
     double x_mean = 0;
     double y_mean = 0;
     for(int i = 0; i < size; i++)
     {
         x_mean += points[i].x();
         y_mean += points[i].y();
     }
     x_mean /= size;
     y_mean /= size; //至此,计算出了 x y 的均值

     double Dxx = 0, Dxy = 0, Dyy = 0;

     for(int i = 0; i < size; i++)
     {
         Dxx += (points[i].x() - x_mean) * (points[i].x() - x_mean);
         Dxy += (points[i].x() - x_mean) * (points[i].y() - y_mean);
         Dyy += (points[i].y() - y_mean) * (points[i].y() - y_mean);
     }
     double lambda = ( (Dxx + Dyy) - sqrt( (Dxx - Dyy) * (Dxx - Dyy) + 4 * Dxy * Dxy) ) / 2.0;
     double den = sqrt( Dxy * Dxy + (lambda - Dxx) * (lambda - Dxx) );
     a = Dxy / den;
     b = (lambda - Dxx) / den;
     c = - a * x_mean - b * y_mean;
     return true;
} 
### 点云数据直线拟合算法的实现方法 点云数据的直线拟合是一种常见的几何建模技术,其目的是通过一组离散点找到一条最佳拟合直线来表示这些点的空间分布特性。稳健估计作为一种重要的统计学工具,在处理含有噪声或异常值的数据集时尤为有效[^1]。 #### 稳健估计的核心概念 稳健估计旨在减少异常值对模型参数的影响,从而提高拟合结果的可靠性。该方法的主要目标是在存在噪声的情况下仍能获得稳定的参数估计值。具体来说,它通过对误差函数施加特定约束条件或者采用权重机制,使得异常值不会显著影响最终的结果。 #### 常见的点云直线拟合算法 以下是几种常用的点云直线拟合算法及其特点: ##### 1. **最小二乘法** 最小二乘法是最基本也是最广泛使用的曲线拟合方法之一。对于点云中的直线拟合问题,可以通过解以下优化方程得到最优直线参数 \(a\) 和 \(b\): \[ \min_{a, b} \sum_{i=1}^{n}(y_i - (ax_i + b))^2 \] 其中,\(x_i, y_i\) 表示点云中某一点的坐标。然而,当数据集中存在大量异常值时,此方法可能失效,因此通常会结合其他鲁棒性更强的方法一起使用。 ```python import numpy as np def least_squares_fit(points): """ 使用最小二乘法进行直线拟合 :param points: ndarray, 形状为(n, 2),代表二维空间内的点集合 :return: tuple(float), 返回(a,b)形式的一次函数系数 """ X = points[:,0].reshape(-1,1) Y = points[:,1].reshape(-1,1) ones = np.ones((X.shape[0],1)) A = np.hstack([X,ones]) a_b = np.linalg.inv(A.T @ A) @ A.T @ Y return float(a_b[0]),float(a_b[1]) points = np.array([[1,2],[2,3],[3,4]]) print(least_squares_fit(points)) ``` ##### 2. **RANSAC(随机抽样一致性)** RANSAC 是一种迭代式的稳健估计方法,特别适合于含噪环境下的结构化数据分析。它的核心思想是从原始数据中随机选取子样本构建初始假设,并验证其余数据对该假设的支持程度。经过多次重复操作后选出支持率最高的模型作为最终结果。 ```python from sklearn import linear_model def ransac_line_fitting(points): """ 利用 RANSAC 进行直线拟合 :param points: list of tuples or array-like object with shape (N,2), where N is the number of data samples. :returns model parameters and inlier mask """ lr = linear_model.RANSACRegressor() X = [[p[0]] for p in points] y = [p[1] for p in points] lr.fit(X,y) line_X = np.arange(min(p[0] for p in points), max(p[0] for p in points)).reshape(-1,1) line_y_ransac = lr.predict(line_X.reshape(-1,1)) return lr.estimator_.coef_[0],lr.estimator_.intercept_,line_X,line_y_ransac # Example usage: data_points = [(1,2),(2,3),(3,5),(8,-7)] slope, intercept, _, _ = ransac_line_fitting(data_points) print(f"Slope={slope}, Intercept={intercept}") ``` ##### 3. **M-Estimation** M-estimators 提供了一种更灵活的方式来定义损失函数的形式,允许我们自定义如何对待不同大小的残差项。相比传统的均方误差准则,它可以赋予较大偏差更低的重要性因子,进而达到抑制极端值干扰的效果。 --- #### 总结 针对点云数据的直线拟合任务,可以根据实际需选择合适的算法。如果数据质量较高且无明显异常,则可优先考虑简单高效的最小二乘法;而面对复杂场景下掺杂较多噪音的情况,推荐选用具备较强抗扰能力的技术方案如 RANSAC 或 M-estimation 来完成相应工作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值