最小二乘法拟合一些基本空间元素的C#实现 —— (二)直线与平面

本文讨论并实现的算法主要(99%)基于这篇文章,更多参考请阅读这里

大部分能搜索到的关于直线最小二乘拟合的资料是基于2维空间的\[y=ax+ b\]

而从三维空间的角度上来看,这只是一种特例。本文主要讨论三维空间上的直线拟合。

参数化

三维直线的表示如下。\[\left(x,y,z\right)=\left(x_0,y_0,z_0\right) + t\left(a,b,c\right)\]

其中\(\left(x_0,y_0,z_0\right)\)为直线上任一已知点,\(\left(a,b,c\right)\)为向量,所以所有直线都可以使用一个点坐标及一个向量来表示。

对于测量点\(P_i\left(x_i,y_i,z_i\right)\)与直线的距离为\[d_i=\sqrt{{u_i}^2+{v_i}^2+{w_i}^2}\]

其中:\[u_i=c\left(y_i-y_0\right)-b\left(z_i-z_0\right)\]\[v_i=a\left(z_i-z_0\right)-c\left(x_i-x_0\right)\]\[w_i=b\left(x_i-x_0\right)-a\left(y_i-y_0\right)\]

算法

根据原文:拟合的直线过所有点的平均值,没有证明……

所以未知量其实是3个,构建一个矩阵\[A=\begin{bmatrix}x_1-x_0&y_1-y_0&z_1-z_0\\x_2-x_0&y_2-y_0&z_2-z_0\\\vdots & \vdots & \vdots \\x_i-x_0&y_i-y_0&z_i-z_0\end{bmatrix}\]

将矩阵A做奇异值分解(SVD),令:\[A=U_1SV^T\]

矩阵\(V\)的第一列(Column)即是直线向量\(\left(a,b,c\right)\)。

代码实现:

 public override void Estimate(List<Point3D> datas)
        {
            double sum_x = 0;
            double sum_y = 0;
            double sum_z = 0;
            foreach (Point3D temp in datas)
            {
                sum_x += temp.x;
                sum_y += temp.y;
                sum_z += temp.z;
            }
            sum_x /= datas.Count;
            sum_y /= datas.Count;
            sum_z /= datas.Count;

            DenseMatrix jacobian = new DenseMatrix(datas.Count, 3);
            foreach (Point3D temp in datas)
            {
                Vector<double> gradient = new DenseVector(3);
                gradient[0] = temp.x - sum_x;
                gradient[1] = temp.y - sum_y;
                gradient[2] = temp.z - sum_z;
                jacobian.SetRow(datas.IndexOf(temp), gradient);
            }
            Svd svd = jacobian.Svd(true);
            // get matrix of left singular vectors with first n columns of U
            Matrix<double> U1 = svd.U().SubMatrix(0, datas.Count, 0, 3);
            // get matrix of singular values
            Matrix<double> S = new DiagonalMatrix(3, 3, svd.S().ToArray());
            // get matrix of right singular vectors
            Matrix<double> V = svd.VT().Transpose();

            Vector<double> parameters = new DenseVector(3);
            parameters = V.Column(0);
            x = sum_x;
            y = sum_y;
            z = sum_z;
            i = parameters[0];
            j = parameters[1];
            k = parameters[2];
        }

平面的最小二乘拟合

放在一起的原因是这两种元素的算法是完全一样的,直线拟合最后一步得到的矩阵V第一列是直线的向量,而第三列就是平面的向量。

参数化

平面同样可以用一个点\(\left(x_0,y_0,z_0\right)\)和一个向量\(\left(a,b,c\right)\)来表示,只是垂直与该向量。

平面的公式为\[a\left(x-x_0\right)+b\left(y-y_0\right)+c\left(z-z_0\right)=0\)

对于测量点\(P_i\left(x_i,y_i,z_i\right)\)直接的距离为\[d_i=a\left(x-x_0\right)+b\left(y-y_0\right)+c\left(z-z_0\right)\]

算法

与直线的算法完全相同。

包含直线、平面与圆柱算法的C#实例与说明

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注