3D Least Squares Plane

后端 未结 9 2224
遥遥无期
遥遥无期 2020-11-27 13:56

What\'s the algorithm for computing a least squares plane in (x, y, z) space, given a set of 3D data points? In other words, if I had a bunch of points like (1, 2, 3), (4, 5

相关标签:
9条回答
  • 2020-11-27 14:40

    If you have n data points (x[i], y[i], z[i]), compute the 3x3 symmetric matrix A whose entries are:

    sum_i x[i]*x[i],    sum_i x[i]*y[i],    sum_i x[i]
    sum_i x[i]*y[i],    sum_i y[i]*y[i],    sum_i y[i]
    sum_i x[i],         sum_i y[i],         n
    

    Also compute the 3 element vector b:

    {sum_i x[i]*z[i],   sum_i y[i]*z[i],    sum_i z[i]}
    

    Then solve Ax = b for the given A and b. The three components of the solution vector are the coefficients to the least-square fit plane {a,b,c}.

    Note that this is the "ordinary least squares" fit, which is appropriate only when z is expected to be a linear function of x and y. If you are looking more generally for a "best fit plane" in 3-space, you may want to learn about "geometric" least squares.

    Note also that this will fail if your points are in a line, as your example points are.

    0 讨论(0)
  • 2020-11-27 14:44

    The equation for a plane is: ax + by + c = z. So set up matrices like this with all your data:

        x_0   y_0   1  
    A = x_1   y_1   1  
              ... 
        x_n   y_n   1  
    

    And

        a  
    x = b  
        c
    

    And

        z_0   
    B = z_1   
        ...   
        z_n
    

    In other words: Ax = B. Now solve for x which are your coefficients. But since (I assume) you have more than 3 points, the system is over-determined so you need to use the left pseudo inverse. So the answer is:

    a 
    b = (A^T A)^-1 A^T B
    c
    

    And here is some simple Python code with an example:

    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    import numpy as np
    
    N_POINTS = 10
    TARGET_X_SLOPE = 2
    TARGET_y_SLOPE = 3
    TARGET_OFFSET  = 5
    EXTENTS = 5
    NOISE = 5
    
    # create random data
    xs = [np.random.uniform(2*EXTENTS)-EXTENTS for i in range(N_POINTS)]
    ys = [np.random.uniform(2*EXTENTS)-EXTENTS for i in range(N_POINTS)]
    zs = []
    for i in range(N_POINTS):
        zs.append(xs[i]*TARGET_X_SLOPE + \
                  ys[i]*TARGET_y_SLOPE + \
                  TARGET_OFFSET + np.random.normal(scale=NOISE))
    
    # plot raw data
    plt.figure()
    ax = plt.subplot(111, projection='3d')
    ax.scatter(xs, ys, zs, color='b')
    
    # do fit
    tmp_A = []
    tmp_b = []
    for i in range(len(xs)):
        tmp_A.append([xs[i], ys[i], 1])
        tmp_b.append(zs[i])
    b = np.matrix(tmp_b).T
    A = np.matrix(tmp_A)
    fit = (A.T * A).I * A.T * b
    errors = b - A * fit
    residual = np.linalg.norm(errors)
    
    print "solution:"
    print "%f x + %f y + %f = z" % (fit[0], fit[1], fit[2])
    print "errors:"
    print errors
    print "residual:"
    print residual
    
    # plot plane
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()
    X,Y = np.meshgrid(np.arange(xlim[0], xlim[1]),
                      np.arange(ylim[0], ylim[1]))
    Z = np.zeros(X.shape)
    for r in range(X.shape[0]):
        for c in range(X.shape[1]):
            Z[r,c] = fit[0] * X[r,c] + fit[1] * Y[r,c] + fit[2]
    ax.plot_wireframe(X,Y,Z, color='k')
    
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    plt.show()
    

    0 讨论(0)
  • 2020-11-27 14:46
    CGAL::linear_least_squares_fitting_3
    

    Function linear_least_squares_fitting_3 computes the best fitting 3D line or plane (in the least squares sense) of a set of 3D objects such as points, segments, triangles, spheres, balls, cuboids or tetrahedra.

    http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Principal_component_analysis_ref/Function_linear_least_squares_fitting_3.html

    0 讨论(0)
提交回复
热议问题