利用点到直线距离 最小二乘法拟合直线 非矩阵算法
-学习了几天最小二乘法拟合直线,总结一下主要有两种方式:
- 直线方程Y=kX+b, 利用Y轴方向距离 最小来拟合直线Σ(Yi-kXi-b)²--------[c++]两分钟弄懂"最小二乘法拟合直线
- 直线方程AX+BY+C=0,利用点到直线的距离最小来拟合直线Σ(AXi+BYi+C)²/(A²+B²)------最小二乘拟合直线真的没问题么
今天主要记录一下第二中方式利用点到直线的距离最小来拟合直线
,由于Σ(AXi+BYi+C)²/(A²+B²)这中式子求偏导后太复杂,网上大神们主要都是用矩阵运算来求解,知乎大神Dr.Sheng的文章,我用了他的方法,核心是SVD算法opencv里也有,达到了预期的效果,但是矩阵运算比较耗时间,我测了一下大概 (拟合800个点,执行100次需60ms)。我在想能否用普通计算的方式实现。知乎大神的的文章给了我灵感。结果和SVD算法完全一致。
下面说一下计算过程
- 拟合的直线必然过所有点的中心(Xavr,Yavr),即(X平均,Y平均)
- 将所有点的的坐标减去中心坐标(Xavr,Yavr),将直线移动到原点位置,直线过原点直线公式简化为y=kx,即kx-y=0
- 点到直线的距离公式:绝对值|AXi+BYi+C|/√(A²+B²);带入A=k,B=-1,C=0;简化为|AXi-Yi|/√(A²+1)
- 利用公式|AXi-Yi|/√(AA+1),最小二乘法求出A; ∑(AXi-Yi)²/(A²+1)最小,其对A的导数为0,导数化简后 ∑ XiYi*A²+(Xi²-Yi²)A-XiYi =0
- 令K=∑ XiYi; L=∑(Xi²-Yi²); M=∑ -XiYi(程序中用的A=∑ XiYi;B=∑(Xi²-Yi²);C=∑ -XiYi)
- 利用二次方程求根公式x=[-b±√(b²-4ac)]/2a,可以求出A=[-L±√(L²-4KM)]/2K,取加号A=[-L+√(L²-4KM)]/2K
- k=A
- n=Yavr - Xavr * k
- 直线公式即为y=kx+n
下面给出代码
public static bool LineFitPCA(List<Point2d> Points