首页 > 其他分享 >直线一般式拟合直线

直线一般式拟合直线

时间:2023-06-27 20:44:31浏览次数:36  
标签:直线 sum back 一般 coes points weights 拟合 Point2f

为了防止忘记,特转载至此。本文方法来源是《最小二乘法直线拟合:Ax+By+C=0 - 会飞的大象会飞的大象 (whudj.cn)》。用一次函数${ y=kx+b }$形式拟合直线非常简单,直接带入最小二乘法公式就行了。而用直线一般式${ ax+by+c=0 }$拟合由于不是线性方程组则需要一些求解技巧。这里不再重复原文内容,而是在原文基础上更进一步。考虑实际情况,在机器视觉应用中从图像中提取的点往往包含一定的噪声,所以通常采取多次加权拟合以消除噪点对结果的影响。下面将给出加权拟合的公式。拟合直线的加权的误差函数如下:

$${ \begin{equation} e=\sum_{i=1}^{N}w_{i}(ax_{i}+by_{i}+c)^{2},满足a^{2}+b^{2}=1 \end{equation} }$$

对c求偏导数并令其为0:

$${ \frac{\partial e}{\partial c}=2\sum_{i=1}^{N}w_{i}(ax_{i}+by_{i}+c)=0 }$$

解得:

$${ \begin{equation} c=-\left( a\frac{ \sum_{i=1}^{N}w_{i}x_{i} }{ \sum_{i=1}^{N}w_{i} }+b\frac{ \sum_{i=1}^{N}w_{i}y_{i} }{ \sum_{i=1}^{N}w_{i} } \right) \end{equation} }$$

把上式代入(1)式,有:

$${ \begin{align*} e &= \sum_{j=1}^{N} w_{j}\left( ax_{j}+by_{j} - a\frac{ \sum_{i=1}^{N}w_{i}x_{i} }{ \sum_{i=1}^{N}w_{i} }-b\frac{ \sum_{i=1}^{N}w_{i}y_{i} }{ \sum_{i=1}^{N}w_{i} } \right)^{2} \\  &= \sum_{j=1}^{N} \left[ a \sqrt{w_{j}} \left( x_{j}-\frac{ \sum_{i=1}^{N}w_{i}x_{i} }{ \sum_{i=1}^{N}w_{i} } \right) + b \sqrt{w_{j}} \left( y_{j}-\frac{ \sum_{i=1}^{N}w_{i}y_{i} }{ \sum_{i=1}^{N}w_{i} } \right) \right]^{2} \end{align*} }$$

现在令${ p_{j}=\sqrt{w_{j}} \left( x_{j}-\frac{ \sum_{i=1}^{N}w_{i}x_{i} }{ \sum_{i=1}^{N}w_{i} } \right),q_{j}=\sqrt{w_{j}} \left( y_{j}-\frac{ \sum_{i=1}^{N}w_{i}y_{i} }{ \sum_{i=1}^{N}w_{i} } \right) }$则上式可简写成:

$${ \begin{align*} e &=\sum_{j=1}^{N} \left( a p_{j} + b q_{j} \right)^{2} \\  &=\begin{pmatrix} a & b \end{pmatrix}\underbrace{\begin{pmatrix} \sum_{j=1}^{N} p_{j}^{2} & \sum_{j=1}^{N} p_{j}q_{j} \\ \sum_{j=1}^{N} p_{j}q_{j} & \sum_{j=1}^{N} q_{j}^{2} \end{pmatrix}}_{S}\begin{pmatrix} a \\ b \end{pmatrix} \end{align*} }$$

接下来的内容就跟不加权的方法相同了。矩阵S的最小特征值对应的特征向量里的两个数就是系数a,b的值。至于为什么可以搜索“二次型求最小值”相关内容。调用OpenCV的cv::eigen(...)函数可得到矩阵的特征值与特征向量。c的值用式(2)求。对应的代码如下。程序运行环境是VS2017和OpenCV430:

Point3f fitLine(const vector<Point2f>& points, const vector<float>& weights)
{
    float swx = 0;
    float swy = 0;
    float sw = 0;
    int count = (int)points.size();
    for (int i = 0; i < count; i++)
    {
        swx += weights[i] * points[i].x;
        swy += weights[i] * points[i].y;
        sw += weights[i];
    }
    float p = 0;
    float q = 0;
    Matx22f pq = Matx22f::zeros();
    for (int i = 0; i < count; i++)
    {
        float pi = sqrtf(weights[i]) * (points[i].x - (swx / sw));
        float qi = sqrtf(weights[i]) * (points[i].y - (swy / sw));
        pq(0, 0) += pi * pi;
        pq(0, 1) += pi * qi;
        pq(1, 0) += pi * qi;
        pq(1, 1) += qi * qi;
    }
    Mat eval, evec;
    eigen(pq, eval, evec);
    float a, b, c;
    a = evec.at<float>(1, 0);
    b = evec.at<float>(1, 1);
    c = -(a * swx + b * swy) / sw;
    return Point3f(a, b, c);
}

int main()
{
    vector<Point2f> points;
    points.push_back(Point2f(10, -0.3f));
    points.push_back(Point2f(20.3f, 10));
    points.push_back(Point2f(30, 18.0f));
    points.push_back(Point2f(80, 71.0f));
    points.push_back(Point2f(110, 100));
    points.push_back(Point2f(215.0f, 200));
    points.push_back(Point2f(315.0f, 299));
    points.push_back(Point2f(425.0f, 412));
    points.push_back(Point2f(565.4f, 560));
    points.push_back(Point2f(410, 440));
    points.push_back(Point2f(59, 20));

    vector<float> weights = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };

    Point3f coes = fitLine(points, weights);
    Mat image(600, 600, CV_8UC3, Scalar(0, 0, 0));
    for (auto& item : points)
    {
        image.at<Vec3b>(item) = Vec3b::all(255);
    }
    Point2f p1(0,0), p2(600,0);
    p1.y = -(coes.x * p1.x + coes.z) / coes.y;
    p2.y = -(coes.x * p2.x + coes.z) / coes.y;
    line(image, p1, p2, Scalar(127, 127, 255)); /* 红色 */

    weights[9] = 0.2f;
    weights[10] = 0.2f;
    coes = fitLine(points, weights);
    p1.y = -(coes.x * p1.x + coes.z) / coes.y;
    p2.y = -(coes.x * p2.x + coes.z) / coes.y;
    line(image, p1, p2, Scalar(127, 255, 127)); /* 绿色 */
    imshow("拟合直线示意图", image);
    waitKey(-1);
    return 0;
}

下面是运行结果:

从上图可以看出来,红色直线受噪点影响有所偏离,而绿色直线较好地贴合大部分的样本。因此给噪点赋予小的权重可以优化结果。实际应用中,可能采用的策略是第一次拟合时所有点的权重相同;第二次拟合时根据每个点到直线的距离赋予不同的权重来优化结果。

标签:直线,sum,back,一般,coes,points,weights,拟合,Point2f
From: https://www.cnblogs.com/mengxiangdu/p/17509051.html

相关文章

  • 直线导轨在焊接领域有什么作用?
    焊接技术在现代制造业中的应用越来越广泛,直线导轨作为重要的传动元件,已经成为焊接设备中不可或缺的部分。相对于直线轴承来说,直线导轨具有较高的负载能力和刚度,能够保证高精度的直线运动,滑动摩擦小,惯量小,能够实现高速运动;摩擦小、磨损小,噪音低、寿命长,能有效减少能量损耗,有利于节能......
  • P9400 「DBOI」Round 1 三班不一般 做题笔记
    题目链接最近搬运一些洛谷上的题解到这里来,一是增加我的博文数量,二是缓解一下我的博客园冷清的气氛。我的做法和题解里的做法不一样,麻烦了许多。首先看到连续的几盏灯刺眼就不行了,当然能够想到动态规划,设$f[i][j]$为看到第$i$个宿舍,末尾有连续$j$个灯刺眼,且前面的灯都合......
  • linux文件夹的一般作用
    /var 存放可以变化的文件或者目录 variable/etc 存放各种各样的服务相关的配置文件/usr 存放linux里安装的软件的目录资源目录-->unixsystemresource/bin 二进制文件/proc存放内核文件(内核管理进程,也有很多进程相关的文件) process/tmp 临时文件,任何用户都可......
  • Android Bresenham 直线算法 让你的手势更丝滑
    Bresenham算法是一种用于绘制直线的算法,它通过在离散的像素点上进行逐步的迭代来绘制出近似直线。以下是一个示例代码,演示了如何使用Bresenham算法绘制直线:fundrawLine(x0:Int,y0:Int,x1:Int,y1:Int){valdx=Math.abs(x1-x0)valdy=Math.abs(y1-......
  • 直线模组在工业自动化领域中的作用和使用
    中国工业制造业快速发展,工业自动化领域也进入了飞速发展的阶段,直线模组作为工业自动化领域不可缺少的机器人之一,有着重要的不可或缺的作用。那直线模组在工业自动化行业中主要有什么作用呢?接下来我们来看看:1>半导体行业2>3C电子行业3>锂电行业4>焊接工程5>显示面板行业6>医疗行业7>......
  • labview最小二乘法拟合曲线报表生成,波形拟合最小二乘法 Lab
    labview最小二乘法拟合曲线报表生成,波形拟合最小二乘法LabVIEW是一种流程图编程语言和开发环境,用于控制和测量系统的自动化。最小二乘法是一种数学优化技术,用于拟合数据点到一个函数曲线上。在LabVIEW中,可以使用最小二乘法来生成报表和进行波形拟合。最小二乘法是一种通过最小化数......
  • 盘点直线模组的主流应用行业
    中国工业制造业快速发展,工业自动化领域也进入了飞速发展的阶段,直线模组作为工业自动化领域不可缺少的机器人之一,有着重要的不可或缺的作用。目前来说,直线模组已普遍运用于测量、激光焊接、激光切割、涂胶机、喷涂机、打孔机、点胶机、小型数控机床、雕铣机、样本绘图机、裁床、移载......
  • m基于MPC模型预测控制算法的永磁直线同步电机控制系统simulink仿真,MPC分别使用工具箱
    1.算法仿真效果matlab2022a仿真结果如下:2.算法涉及理论知识概要MPC(ModelPredictiveControl)模型预测控制算法是一种先进的控制算法,能够有效地解决非线性、多变量、约束条件等复杂系统的控制问题。永磁直线同步电机是一种高性能、高效率的电机,广泛应用于机器人、医疗设备、工业......
  • m基于MPC模型预测控制算法的永磁直线同步电机控制系统simulink仿真,MPC分别使用工具箱
    1.算法仿真效果matlab2022a仿真结果如下:  2.算法涉及理论知识概要      MPC(ModelPredictiveControl)模型预测控制算法是一种先进的控制算法,能够有效地解决非线性、多变量、约束条件等复杂系统的控制问题。永磁直线同步电机是一种高性能、高效率的电机,广泛应用于机......
  • [C++/PTA] 计算点到直线的距离一一友元函数的应用
    题目要求计算点到直线的距离。首先设计一个点类Point,它有2个私有数据成员x和y,表示点的坐标。另一个类为直线类Line,它有3个私有数据成员a,b和c,表示直线方程ax+by+c=0。这两个类中都说明了一个友元函数dist,用于计算一个点到直线的距离。点(x.y)到直线ax+by+c=0的距离d的计算......