3D点云的平面拟合算法

拥有n个3D点的集合,并希望为这些点拟合一个平面。本文将介绍一种简单且数值稳定的方法,并附带其源代码。听起来很有趣?那就让我们开始吧!

NSDT工具推荐:Three.js AI纹理开发包、YOLO合成数据生成器、GLTF/GLB在线编辑、3D模型格式在线转换、可编程3D场景编辑器、REVIT导出3D模型插件、3D模型语义搜索引擎

在网上寻找答案,你可能会得到关于对协方差矩阵进行奇异值分解以找到最小特征值的特征向量的答案。然而,实际上这个过程比所需更加复杂。让我们从基础开始:

平面通常由法向量n = [a, b, c]ᵀ和距离d描述,对于平面n · p + d = 0上的点p = [x, y, z]ᵀ,我们可以将其写为:

但请注意,这是超定的 - 解空间(平面)是三维的,但上面的描述使用了四个值。因此,让我们首先通过限制解决方案空间来删除一个组件。我们通过任意指定c = 1来实现这一点,即平面法线的z分量始终为1(请注意,法线的长度不需要为1)。如果你认为这是一个潜在有问题的假设,那么你是对的——我们稍后会再讨论这个问题。现在,让我们定义:

并求解a、b、d。矩阵形式:

接下来,我们将这个矩阵转置,然后从左侧相乘以执行线性最小二乘:

转置后相乘:

其中N是点数。现在这是聪明的部分:让我们定义上面的x、y、z相对于点云的质心(平均值)。现在Σx = Σy = Σz = 0,所以我们可以简化为:

从最后一行(N·d = 0)我们可以得出d = 0。这意味着如果所有点都相对于点云的质心,则平面穿过原点。换句话说:平面始终穿过输入点的平均值。我们现在可以去掉一个维度:

克莱默规则告诉我们:

我们可以通过将n乘以D来简化它(无论如何我们都需要对n进行归一化),这给我们:

就是这样!但请记住我们的假设:平面法线的z分量不为零。如果为零怎么办?那么可以证明上面的行列式D变为零并且我们可以除以零。即使它不完全为零,但很接近,我们仍然会得到不好的条件,从而得到不好的结果。所以,我们能做些什么?好吧,如果这些点跨越一个平面,则法线的至少一个分量必须非零。因此,让我们对三个单独的假设进行上述计算,其中哪个分量不为零。然后我们简单地选择表现最好的一个,即具有最大行列式的那个。

注意:此方法将最小化垂直于主轴的残差的平方,而不是垂直于平面的残差的平方。如果残差很小(即你的点都靠近生成的平面),那么这种方法可能就足够了。但是,如果你的点分布比较分散,那么此方法可能不是最合适的。

这是Rust代码:

原文链接:3D点云平面拟合 - BimAnt