• python用最小二乘法实现平面拟合


    数学原理

    平面方程可写为

    A x + B y + C z + D = 0 Ax+By+Cz+D=0 Ax+By+Cz+D=0

    假设 C C C不为0,则上式可以改写为

    z = a x + b y + d z=ax+by+d z=ax+by+d

    则现有一组点 { p i } \{p_i\} {pi},则根据 x i , y i x_i,y_i xi,yi以及平面方程,可以得到其对应的 z ^ i \hat z_i z^i

    z ^ i = a x i + b y i + d \hat z_i=ax_i+by_i+d z^i=axi+byi+d

    从而平面拟合就转换为了最小二乘问题

    arg min ⁡ ∑ ∣ z i − z ^ i ∣ \argmin \sum \vert z_i-\hat z_i\vert argminziz^i

    将其转换为矩阵形式,记

    A = [ x 1 y 1 1 x 2 y 2 1 ⋮ ⋮ x n y n 1 ] , x = [ a b d ] , b = [ z 1 z 2 ⋮ z n ] A=[x1y11x2y21xnyn1], x=[abd], b=[z1z2zn] A= x1x2xny1y2yn111 ,x= abd ,b= z1z2zn

    则拟合方程变为

    A x = b Ax=b Ax=b

    相应地 x x x可写为

    x = ( A T A ) − 1 A T b x=(A^TA)^{-1}A^Tb x=(ATA)1ATb

    最小二乘法的原理可见:python实现最小二乘法

    代码实现

    其代码实现如下

    import numpy as np
    def planefit(points):
        xs, ys, zs = list(zip(*points))
        A = np.vstack([xs,ys,np.ones_like(xs)]).T
        b = np.reshape(zs, [-1, 1])
        abd = np.linalg.inv(A.T @ A) @ A.T @ b
        return abd.reshape(-1)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    其中输入参数points为一组点。第一步将这些点进行坐标拆分,得到一一对应的xs, ys, zs。然后通过这些点,构造矩阵A和向量b,最后输出 ( A T A ) − 1 A T b (A^TA)^{-1}A^Tb (ATA)1ATb

    测试

    首先做一个初始化平面的函数,其功能是随机生成一组在平面中的点,并且为其添加一些噪声。

    # 初始化平面
    def initPlane(a, b, d, N, err=0.1):
        xs,ys = np.random.rand(2, N)
        zs = a*xs + b*ys + d + np.random.rand(N)*err
        return list(zip(xs, ys, zs))
    
    • 1
    • 2
    • 3
    • 4
    • 5

    然后用planefit函数对这些点进行拟合,通过对比二者之间的差异,来证实算法的有效性

    import matplotlib.pyplot as plt
    
    pts = initPlane(2,3,4,100,1)
    a,b,d = planefit(pts)
    
    xs, ys = np.indices([100,100])/100
    zs = a*xs + b*ys + d
    
    ax = plt.subplot(projection='3d')
    ax.plot_surface(xs, ys, zs, cmap='jet')
    ax.scatter(*np.array(pts).T, marker='*')
    plt.show()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    随着加入的噪声逐渐变大,拟合误差也越来越大

    errs = [0.01, 0.1, 0.2, 0.5, 1, 3, 5]
    fits = []
    for err in errs:
        pts = initPlane(2,3,4,100,1)
        a,b,d = planefit(pts)
        fits.append([abs(a-2),abs(b-3),abs(d-4)])
    
    import pprint
    pprint.pprint(fits)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    [[0.09377971025135245, 0.023025216275622373, 0.4933931906466551],
    [0.044310965250572654, 0.05681830483294226, 0.47952260969370997],
    [0.051813469166934745, 0.017914573861143257, 0.47553046120193176],
    [0.08578595894551588, 0.0464898508775029, 0.42791269232718054],
    [0.011569662177250528, 0.15976404558136714, 0.4886516489062753],
    [0.006829071411009302, 0.04832062421804073, 0.5193494695593301],
    [0.1651263679674586, 0.0736367910618192, 0.44103226768552073]]


  • 相关阅读:
    使用Speech to Text API进行语音到文本转换
    小谈设计模式(16)—抽象工厂模式
    HTML期末学生大作业:基于html+css+javascript+jquery企业餐厅11页 企业网站制作
    Linux下安装Mysql【详细】
    插图精美的html & css教程
    C语言---指针
    JavaScript 14 JavaScript 数据类型
    C++/QT + Mysql + Tcp 企业协作管理系统
    VisionPro学习笔记(7)——FitLineTool
    笔试算法题ACM模式输入输出处理
  • 原文地址:https://blog.csdn.net/m0_37816922/article/details/134390163