计算两组点之间的三维变换

7
使用Microsoft Kinect,我正在收集有关对象的深度数据。从这些数据中,我创建了一个“点云”,当绘制时,它允许我查看使用Kinect扫描的对象。
然而,我想能够从不同的“视图”收集多个点云并对齐它们。更具体地说,我想使用诸如Iterative Closest Point (ICP)之类的算法来完成此操作,通过计算每个我收集的云和先前收集的云之间的旋转和平移来转换我的点云中的每个点。
然而,虽然我理解ICP背后的过程,但我不知道如何在3D中实现它。也许是我缺乏数学经验或缺乏OpenCV等框架的经验,但我找不到解决方案。我想避免使用像Point Cloud Library这样为我执行此类操作的库,因为我想自己完成它。
任何建议都将不胜感激(如果有涉及OpenCV / python的解决方案,那就更好了!)
4个回答

11
我自己也在苦苦挣扎ICP。到目前为止,这是我收集到的信息:
ICP包括三个步骤:
1. 给定两个点云A和B,找到在A和B之间可能代表同一空间点的点对。通常,这可以通过将每个点与另一个云中的最近邻匹配来完成,但您可以使用其他特征(如颜色、纹理或表面法线)来改善匹配。然后,可选择性地丢弃最差的匹配项。
2. 在给定的对应点列表中,找到从A到B的最佳变换。
3. 将此变换应用于A中的所有点。
4. 重复这三个步骤,直到达到可接受的解决方案。
第一步很容易,虽然有很多方法可以优化其速度,因为这是ICP的主要性能瓶颈;并且为了提高准确性,因为这是错误的主要来源。OpenCV可以通过FLANN库帮助您。
我假设您的困难在于第二步,即在给定的对应关系列表中找到最佳变换。

一种常见的方法是使用奇异值分解 (SVD)。以下是该算法的大致草图。搜索ICP和SVD将提供更多参考资料。

  • 从第一步中取出对应点A1..An和B1..Bn的列表
  • 计算所有A点的质心Ca和所有B点的质心Cb
  • 计算3x3协方差矩阵M
    M = (A1 - Ca)* (B1 - Cb)T + ... + (An - Ca)* (Bn - Cb)T
  • 使用SVD计算M的3x3矩阵U和V
    (OpenCV有一个执行SVD的函数)
  • 计算R = U * VT.
    这是您所需的最佳旋转矩阵。
  • 将最佳平移计算为Cb - R*Ca
  • 最佳变换是R和该平移的组合
请注意,我自己尚未实现此算法,因此我只是在转述我所读到的内容。

我很感激你与我分享了你的发现 - 也许我很快就可以实施这种方法并告诉你结果。 - nmagerko
我确实会在假期后尝试将这种方法应用到我的项目中。非常感谢您的见解。 - nmagerko
1
请注意,应该是 R = V * U^T。 - Pierluigi
你应该对找到的对应关系进行一些异常值过滤,以提高收敛性。例如,在修剪ICP中的方法适用于部分重叠点云。libpointmatcher是一个相当不错的开源C++实现,也许你可以查看源代码以获取一些想法。 - PSchn

4
您可以在Rusinkievicz的旧论文这里中找到ICP的非常好的介绍,包括加速变体。

2

我尝试了你的ICP方法的Matlab实现。我有几个问题: 1- 源点和映射点的数量是否有限制?点的数量应该相同吗? 2- 我注意到算法需要点云的网格。当点的数量不太多且聚类具有凹面特征时,这变成了一个挑战。你会推荐哪种网格生成器用于具有凹面特征的点云? - Arash_D_B
  1. 根据本质,不应期望点数相等。
  2. 不需要网格。这是不必要的。
- Tolga Birdal
我没有足够的空间,所以我不得不在下面继续我们的对话。 - Arash_D_B
第一个链接(OpenCV的)已经失效。 - trox

0

@tdirdal:

好的,那么我可能没有看到正确的代码。我的意思是关于这个包link: 代码从构造变换矩阵开始,然后加载一个包含网格(面和顶点)的*.ply文件。剩下的代码取决于已加载的网格。

我有一个非常简单的问题,并且如果您可以告诉我如何使用ICP方法解决此问题,我将不胜感激。我有以下两个点云。P2是P39的子集,我想找到P2在P39中的位置。请让我知道如何使用您的matlab包解决此问题。

P2:

11.2706 -5.3392 1.1903

13.6194 -4.8500 2.6222

8.8809 -3.8407 1.1903

10.7704 -2.1800 2.6222

8.5570 -1.0346 1.1903

13.1808 -2.5632 1.1903

P39:

-1.9977 -4.1434 -1.6750

-4.3982 -3.5743 -3.1069

-6.8065 -3.0071 -1.6751

-9.2169 -2.4386 -3.1070

-11.6285 -1.8696 -1.6751

-16.4505 -0.7305 -1.6751

-14.0401 -1.3001 -3.1070

-18.8577 -0.1608 -3.1070

-25.9398 -0.8647 -3.1070

-30.1972 -4.6857 -3.1069

-28.2349 -2.5200 -3.1069

-29.5843 -0.2496 -1.6751

-31.1688 -2.0974 -3.1070

-21.2580 0.4093 -1.6751

-23.6450 0.9838 -3.1070

-26.0636 1.5073 -1.6751

-28.4357 1.9258 -3.1070


1
Ply 不一定是一个网格。它也可以是一个点云。因此,如果您有一个网格,请使用加载的网格的顶点。否则,仅加载顶点。 - Tolga Birdal
对于这个简单的问题,你可以使用一些RANSAC方案来找到最佳的对齐方式(只需随机抽取一些样本集并尝试进行注册,如果在1000次迭代中无法得到合理的结果,则非常不幸)。然而,对于真实场景,请查看我描述的表面匹配模块。它可以完美地解决这个问题。 - Tolga Birdal
好的,你在这里犯了一个基本错误。只有当点云被初始化为粗略对准时,ICP才能工作。也就是说,它们应该在某种意义上重叠。ICP只是一种梯度下降优化方法。你应该阅读更多相关链接中的内容。 - Tolga Birdal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接