简体   繁体   English

3D 平面拟合方法(C++ 与 Python)

[英]3D Plane Fitting Approach (C++ vs Python)

Given :鉴于:

I have a set of 3D points in a csv file.我在 csv 文件中有一组 3D 点。

   X,  Y,  Z
  x0, y0, z0
  x1, y1, z1
     ...
  xn, yn, zn

Problem Statement : The objective is to fit a plane based on the Least square error.问题陈述:目标是根据最小二乘误差拟合平面。 Get the Error distance between the point and the plane.获取点与平面之间的误差距离。 I have freedom to choose python or C++.我可以自由选择 python 或 C++。 I prefer c++ but python is fine too.我更喜欢 c++,但 python 也很好。

Equation of the Plane is:平面方程为:

                         Ax + By + Cz + D = 0                            -- Equation 1

Option 1 : C++ Way选项 1:C++ 方式

I found this link online, describing a c++ way to solve the plane fitting http://www.janssenprecisionengineering.com/downloads/Fit-plane-through-data-points.pdf But here instead of using the equation 1, they use equation2我在网上找到了这个链接,描述了一种解决平面拟合的 C++ 方法http://www.janssenprecisionengineering.com/downloads/Fit-plane-through-data-points.pdf但这里不是使用等式 1,而是使用等式 2

                         Z = A'x + B'y + C'                               -- Equation 2

                        where,  A' = -A/C
                                B' = -B/C
                                C' = -D/C

计算

Once I know the A' B' C', I will be able to calculate the distance from each point to the plane based on equation 3 (Reference from -> Math Insight ):一旦我知道 A' B' C',我将能够根据等式 3(参考 -> Math Insight )计算每个点到平面的距离:

                   Error = abs(A * x + B * y - z + C) / sqrt(pow(A, 2) + pow(B, 2) + 1);   -- Equation 3

I started to implement it with C++我开始用 C++ 实现它

    std::ofstream abc;
    abc.open("Logs\\abc.csv"); 

    cv::Mat Plane;
    double Xi = 0;
    double Yi = 0;
    double Zi = 0;

    double X2i = 0;
    double Y2i = 0;

    double XiYi = 0;
    double XiZi = 0;
    double YiZi = 0;

    for (int o = 0; o < GL.PointX.size(); ++o) {

        std::cout << "POINT X : " << GL.PointX[o] << std::endl;
        std::cout << "POINT Y : " << GL.PointY[o] << std::endl;
        std::cout << "POINT Z : " << GL.PointZ[o] << std::endl;

        Xi = Xi + GL.PointX[o];
        Yi = Yi + GL.PointY[o];
        Zi = Zi + GL.PointZ[o];

        X2i = X2i + (GL.PointX[o] * GL.PointX[o]);
        Y2i = Y2i + (GL.PointY[o] * GL.PointY[o]);

        XiYi = XiYi + (GL.PointX[o] * GL.PointY[o]);
        XiZi = XiZi + (GL.PointX[o] * GL.PointZ[o]);
        YiZi = YiZi + (GL.PointY[o] * GL.PointZ[o]);

    }

    cv::Mat PlaneA_Mat = (cv::Mat_<double>(3, 3) << X2i, XiYi, Xi, XiYi, Y2i, Yi, Xi, Yi, 1);
    cv::Mat PlaneB_Mat(3, 1, CV_64FC1);
    double R = 0, R2 = 0, FR2=0;
    int Observation = 70;
    PlaneB_Mat.at<double>(0, 0) = XiZi;
    PlaneB_Mat.at<double>(1, 0) = YiZi;
    PlaneB_Mat.at<double>(2, 0) = Zi;

    Plane = PlaneA_Mat.inv() * PlaneB_Mat;



    double A = Plane.at<double>(0, 0); //-A/C
    double B = Plane.at<double>(1, 0); //-B/C
    double C = Plane.at<double>(2, 0); //-D/C


    abc << A << "," << B << "," << "-1" << "," << C;
    abc <<"\n";


    double Dsum = 0;
    for (int o = 0; o < GL.PointX.size(); ++o) {
        double Error = abs(A * GL.PointX[o] + B * GL.PointY[o] - GL.PointZ[o] + C) / sqrt(pow(A, 2) + pow(B, 2) + 1);
        std::cout << "Error : " << Error << std::endl;
        Error_projection << Error ;
        Error_projection << "\n";
        Dsum = Dsum + Error;
        GL.D.push_back(Error);
    }
    R = (Observation * XiYi - Xi * Yi) / sqrt((Observation * X2i - Xi * Xi) * (Observation * Y2i - Yi * Yi));
R2 = pow(R, 2);

FR2 = pow(Zi - Dsum, 2) / pow(Zi - (1 / Observation)*Zi, 2);


std::cout << "PlaneA_Mat : " << PlaneA_Mat << std::endl;
std::cout << "PlaneB_Mat: " << PlaneB_Mat << std::endl;
std::cout << "FINAL PLANE: " << Plane << std::endl;
std::cout << "R: " << R << std::endl;
std::cout << " Correlation coefficient (R^2) : " << R2 << std::endl;
std::cout << " Final Correlation coefficient (FR^2) : " << FR2 << std::endl;

The result I get is :我得到的结果是:

  A : 12.36346708893272
  B : 0.07867292340114898
  C : -3.714791111490779

And also got the errors for each point relative to the plane.并且还得到了相对于平面的每个点的误差。 The Error values are very big . Error 值非常大

*Option 2 : Python Way * *选项2:Python方式*

Then I started to look into web to find some code and found this --> 3D Plane Fit code.然后我开始查看网络以找到一些代码并找到了这个 --> 3D Plane Fit代码。 I modified according to my needs and this works perfectly.我根据自己的需要进行了修改,效果很好。

import numpy as np
import scipy.optimize

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pandas



fig = plt.figure()
ax = fig.gca(projection='3d')

def fitPlaneLTSQ(XYZ):
    (rows, cols) = XYZ.shape
    print(rows, cols)
    G = np.ones((rows, 3))
    print(XYZ)
    print(XYZ[0])
    G[:, 0] = XYZ[0]  # X
    G[:, 1] = XYZ[1]  # Y
    print(G)
    Z = XYZ[2]
    (a, b, c), resid, rank, s = np.linalg.lstsq(G, Z)
    print("a : ", a )
    print("b : ", b )
    print("c : ", c)
    print("Residual : ", resid)
    print("Rank : ", rank)
    print("Singular Value", s)

    normal = (a, b, -1)                                             # I Don't Know WHY ?
    print("normal : ", normal)

    '''
    normala = abs(pow(a,2)+pow(b,2)+pow(-1,2))
    np.sqrt(normala)
    abb=normal/normala
    print("Normala : ",normala)
    print("Normala : ", abb)

    '''

    nn = np.linalg.norm(normal)                                       # I Don't Know WHY ?
    print("nn : ", nn)
    normal = normal/nn                                                # I Don't Know WHY ?

    print("Normal : ", normal)

    return (c, normal)


#Import Data from CSV
result = pandas.read_csv("C:/Users/Logs/points_L.csv", header=None) # , names=['X', 'Y','Z']
#result =result.head(5)
print(result)

normal1 = pandas.read_csv("C:/Users/Logs/pose_left.csv", header=None) # , names=['X', 'Y','Z']
print(normal1)

abc = pandas.read_csv("C:/Users/Logs/abc.csv", header=None) # , names=['X', 'Y','Z']
print(abc)

#standard normal distribution / Bell.
#np.random.seed(seed=1)

data = result
#print(data)
print("NEW : ")
print(data)

c, normal = fitPlaneLTSQ(data)
print(c, normal)

# plot fitted plane
maxx = np.max(data[0])
maxy = np.max(data[1])
minx = np.min(data[0])
miny = np.min(data[1])
print(maxx,maxy, minx, miny)

point = np.array([0.0, 0.0, c])                                             # I Don't Know WHY ?
print("Point : ", point)
d = -point.dot(normal)                                                      # I Don't Know WHY ?
print("D : ",  d)

# plot original points
ax.scatter(data[0], data[1], data[2])
ax.quiver(data[0], data[1], data[2], normal1[0], normal1[1], normal1[2], length=0.2)
# compute needed points for plane plotting
xx, yy = np.meshgrid([minx, maxx], [miny, maxy])                           


print(xx)
print(yy)

print("minx : ", minx)
print("maxx : ", maxx)
print("miny : ", miny)
print("maxy : ", maxy)


print("xx : ", xx)
print("yy : ", yy)
z = (-normal[0]*xx - normal[1]*yy - d)*1. / normal[2]                   # I Don't Know WHY ?


unit1 = np.sqrt(pow(normal[0], 2) + pow(normal[1],2) + pow(normal[2],2))
print("Unit 1 : ", unit1)
Error = abs(normal[0]*data[0] + normal[1]*data[1] + normal[2]*data[2] + d)/unit1
print("Error", Error)
Error_F = pandas.DataFrame(Error)
print("Print : ", Error_F)
Error_F.to_csv("C:/Users/Logs/Py_Error.csv")


print("Z : ", z)
# plot plane
ax.plot_surface(xx, yy, z, alpha=0.2)
ax.set_xlim(-1, 1)
ax.set_ylim(-1,1)
ax.set_zlim(1,2)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.show()

3D 绘图

It would be really helpful if you could answer the following :如果您能回答以下问题,那将非常有帮助:

  1. In the Option 2 python code, I have commented # I Don't Know WHY ?在选项 2 python 代码中,我评论了# I Don't Know WHY ? could you provide the Mathematical reasoning behind why they have used it.你能提供他们为什么使用它背后的数学推理吗? Please care to explain it as if you are explaining to noob.请注意解释,就像你在向菜鸟解释一样。
  2. What is the problem with my C++ code?我的 C++ 代码有什么问题? how can I get it to produce the same results as the python code?我怎样才能让它产生与python代码相同的结果?
  3. Why my Final Correlation coefficient R^2 provides strange results?为什么我的最终相关系数 R^2 提供了奇怪的结果?

     Thank You Very Much !

Well, this isn't an answer but it's too long for a comment.好吧,这不是答案,但评论太长了。 Another interpretation of 'distance between the point and the plane' is, for a point p “点与平面之间的距离”的另一种解释是,对于点 p

n.p + d

where the plane has equation其中平面有方程

n.p + d = 0

and we assume我们假设

|n| = l

So if we have a collection of N points p[], we seek real d and a unit vector n to minimise所以如果我们有 N 个点 p[] 的集合,我们寻找实数 d 和一个单位向量 n 来最小化

S = Sum{ i | (n.P[i] + d)*(n.P[i] + d) }

Some rather algebra derives the following method for computing this:一些相当的代数推导出以下计算方法:

a/ compute Pbar, the mean point and Q, the 'covariance' of the P[] via a/ 计算 Pbar、均值点和 Q、P[] 的“协方差”通过

Pbar = Sum{ i | P[i]}/N
Q = Sum{ i | (P[i]-Pbar)*(P[i]-Pbar)' } / N

b/ compute n, and eigenvector of Q corresponding to a minimal eigenvalue. b/ 计算 n 和 Q 的特征向量对应于最小特征值。

c/ compute c/ 计算

d = -n'*Pbar

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM