我正在尝试将一个平面拟合到 3D 空间中的一组点。我最初尝试了详尽的最小二乘拟合,但事实证明这太慢了。我读到最有效的解决方案是执行奇异值分解。
这方面的数学知识超出了我的能力范围,但我找到了很多资源来尝试让它发挥作用。
根据this post中的答案,我需要计算点的质心,从所有点中减去质心,将它们放入 3xN 矩阵并执行 SVD。然后,我将左奇异向量作为平面的法线。
到目前为止一切顺利。
我发现了一个名为 alglib 的 C# 数学库,它具有 SVD 函数。算法的定义可以参见here 。这就是我遇到问题的地方,因为除了数据点矩阵之外,它还需要两个矩阵作为输入,而且我真的不明白要在其中放入什么。不管怎样,我运行了这段代码:
Vector3 centroid = getCentroid(planeVerts);
double[,] dataMat = substractCentroid(planeVerts, centroid);
double[] w = new double[3];
double[,] u = new double[1,1];
double[,] t = new double[1, 1];
bool a = alglib.svd.rmatrixsvd(dataMat, 3, planeVerts.Length, 0, 0, 2, ref w, ref u, ref t);
Vector3 planeNorm = new Vector3((float) w[0], (float) w[1], (float) w[2]);
所以理论上我认为“w”会包含我的平面法线,但不幸的是它没有(我在Unity3D中可视化它并且它的角度是错误的)。 “u”和“t”矩阵让我感到困惑,我真的不知道应该将它们设置为什么。
rmatrixsvd函数的详细API可以参见here .
有数学或算法资深人士可以分享他们在这个问题上的知识吗?我需要使用 C#,因为我的项目是在 Unity3D 中。如果需要,我很乐意提供更多信息。
最佳答案
查看文档,看起来 w 将包含奇异值,U 将包含左奇异向量,V 将包含右奇异向量。由于 dataMat 是 3xN,因此 U 应该是 3x3,V 应该是 NxN。正如你所说,你需要左奇异向量,设置 UNeeded=1 并只取 U 的第一列。由于你不需要右奇异向量,你也可以设置 VNeeded=0。
关于c# - 使用奇异值分解将平面拟合到一组点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29356594/