草庐IT

Python Open3D点云配准点对点,点对面ICP(Iterative Closest Point)

程序媛一枚~ 2023-04-13 原文

Python Open3D点云配准 ICP(Iterative Closest Point)

这篇博客将介绍 迭代最近点配准算法(Iterative Closest Point, ICP) 。多年来,它一直是研究和工业中几何注册的支柱。输入是两个点云和一个初始变换,该变换大致将源点云与目标点云对齐。输出是一个精确的变换,它将两个点云紧密对齐。

  • 将展示俩种ICP:点对点ICP(PointToPoint)和点对面ICP(PointToPlane)。
  • 函数 draw_registration_result 在icp过程中可视化对齐效果。目标点云和源点云分别用青色和黄色绘制。两个点云彼此重叠得越多越紧密,对齐结果越好。
  • 函数 evaluate_registration 计算两个主要指标:
    • fitness:其测量重叠区域(内部对应的数量/目标中的点的数量),越高越好。
    • inlier_rmse,其测量所有inlier对应的rmse相似性,越低越好。

1. 效果图

原始点云黄色 VS 原始点云青色:

初始对齐 Point to Point ICP 匹配74056个点,效果图如下:

Apply point-to-point ICP
RegistrationResult with fitness=3.724495e-01, inlier_rmse=7.760179e-03, and correspondence_set size of 74056
Access transformation to get result.
Transformation is:
[[ 0.83924644 0.01006041 -0.54390867 0.64639961]
[-0.15102344 0.9
6521988 -0.21491604 0.75166079]
[ 0.52191123 0.2616952 0.81146378 -1.50303533]
[ 0. 0. 0. 1. ]]

Point to Plane ICP 匹配123471个点效果图如下:
可以看到点对面ICP更快达到收敛。fitness更高更好,inlier_rmse也小一些。

Apply point-to-plane ICP
RegistrationResult with fitness=6.209722e-01, inlier_rmse=6.581453e-03, and correspondence_set size of 123471
Access transformation to get result.
Transformation is:
[[ 0.84023324 0.00618369 -0.54244126 0.64720943]
[-0.14752342 0.96523919 -0.21724508 0.81018928]
[ 0.52132423 0.26174429 0.81182576 -1.48366001]
[ 0. 0. 0. 1. ]]

Initial alignment
RegistrationResult with fitness=1.747228e-01, inlier_rmse=1.177106e-02, and correspondence_set size of 34741
Access transformation to get result. 

Apply point-to-point ICP
RegistrationResult with fitness=3.724495e-01, inlier_rmse=7.760179e-03, and correspondence_set size of 74056
Access transformation to get result.
Transformation is:
[[ 0.83924644  0.01006041 -0.54390867  0.64639961]
 [-0.15102344  0.9
 6521988 -0.21491604  0.75166079]
 [ 0.52191123  0.2616952   0.81146378 -1.50303533]
 [ 0.          0.          0.          1.        ]] 

Apply point-to-plane ICP
RegistrationResult with fitness=6.209722e-01, inlier_rmse=6.581453e-03, and correspondence_set size of 123471
Access transformation to get result.
Transformation is:
[[ 0.84023324  0.00618369 -0.54244126  0.64720943]
 [-0.14752342  0.96523919 -0.21724508  0.81018928]
 [ 0.52132423  0.26174429  0.81182576 -1.48366001]
 [ 0.          0.          0.          1.        ]] 

2. 安装及原理

pip install open3d -i http://mirrors.aliyun.com/pypi/simple/

点云配准本质上是将点云从一个坐标系变换到另一个坐标系。通常会需要用到两个点云数据,第一类点云数据称为原始点云,用S(source)来表示,黄色。第二类点云数据称为目标点云,用T(Target)来表示,青色。

点云配准的主要任务是计算出旋转矩阵R和平移矩阵T。

2.1 点对点ICP

通常,ICP算法迭代两个步骤:

  • 查找对应集K={(p,q)} 从目标点云P和用当前变换矩阵T变换的源点云Q中提取并更新转换T
  • 通过最小化在对应集K上定义的目标函数E(T)
    ICP的不同变体使用不同的目标函数E(T):

E ( T ) = ∑ ( p , q ) ϵ κ ∣ ∣ p − T q ∣ ∣ 2 \bold {E(T)=\sum_{(p,q)\epsilon\kappa} \mid\mid p-T_q \mid \mid ^2 } E(T)=(p,q)ϵκpTq2

TransformationEstimationPointToPoint类提供了计算点对点ICP目标的残差和转换矩阵的函数。函数registration_icp将其作为参数并运行点对点icp以获得结果。

fitness分数从0.174723增加到0.372450。inlier_rmse从0.011771减少到0.007760。默认情况下,registration_icp 运行直到收敛或达到最大迭代次数(默认情况下为30)。它可以被改变以允许更多的计算时间并进一步改进结果。

最终对准是紧密的。fitness分数提高到0.621123。inlier_rmse降低到0.006583。

2.2 点对面ICP

点对面ICP使用不同的目标函数E(T):
E ( T ) = ∑ ( p , q ) ϵ κ ( ( p − T q ) ⋅ n p ) 2 \bold {E(T)=\sum_{(p,q)\epsilon\kappa} ((p-T_q) \cdot n_p)^2} E(T)=(p,q)ϵκ((pTq)np)2

其中 n p n_p np 是点p的法线,表明点对平面ICP算法比点对点ICP算法具有更快的收敛速度。
使用不同的参数TransformationEstimationPointToPlane调用registration_icp。在内部,此类实现了计算点到平面ICP目标的残差和转换矩阵的函数。

3. 源码

# 使用官方demo点云对俩个原始点云进行点对点icp,点对面icp配准,并进行可视化,原始点云黄色,目标点云青色。
# python icp_registration.py
import copy

import numpy as np
import open3d as o3d


def draw_registration_result(source, target, transformation, title):
    source_temp = copy.deepcopy(source) # 制作点云深度拷贝保护原始点云
    target_temp = copy.deepcopy(target)
    source_temp.paint_uniform_color([1, 0.706, 0]) # 黄色
    target_temp.paint_uniform_color([0, 0.651, 0.929]) # 青色
    source_temp.transform(transformation)
    o3d.visualization.draw([source_temp, target_temp], title="Open3D " + title)


def point_to_point_icp(source, target, threshold, trans_init):
    print("Apply point-to-point ICP")
    reg_p2p = o3d.pipelines.registration.registration_icp(
        source, target, threshold, trans_init,
        o3d.pipelines.registration.TransformationEstimationPointToPoint())
    print(reg_p2p)
    print("Transformation is:")
    print(reg_p2p.transformation, "\n")
    draw_registration_result(source, target, reg_p2p.transformation, 'point-to-point ICP')


def point_to_plane_icp(source, target, threshold, trans_init):
    print("Apply point-to-plane ICP")
    reg_p2l = o3d.pipelines.registration.registration_icp(
        source, target, threshold, trans_init,
        o3d.pipelines.registration.TransformationEstimationPointToPlane())
    print(reg_p2l)
    print("Transformation is:")
    print(reg_p2l.transformation, "\n")
    draw_registration_result(source, target, reg_p2l.transformation, 'point-to-plane ICP')


if __name__ == "__main__":
    # 本地没有会自动下载demo点云数据 https://github.com/isl-org/open3d_downloads/releases/download/20220301-data/DemoICPPointClouds.zip
    pcd_data = o3d.data.DemoICPPointClouds()
    source = o3d.io.read_point_cloud(pcd_data.paths[0])
    target = o3d.io.read_point_cloud(pcd_data.paths[1])
    threshold = 0.02
    trans_init = np.asarray([[0.862, 0.011, -0.507, 0.5],
                             [-0.139, 0.967, -0.215, 0.7],
                             [0.487, 0.255, 0.835, -1.4], [0.0, 0.0, 0.0, 1.0]])
    draw_registration_result(source, target, trans_init, 'origin')

    print("Initial alignment")
    # 函数evaluate_registration计算两个主要指标:
    # fitness:其测量重叠区域(内部对应的数量/目标中的点的数量),越高越好。
    # inlier_rmse,其测量所有inlier对应的rmse相似性,越低越好。
    evaluation = o3d.pipelines.registration.evaluate_registration(
        source, target, threshold, trans_init)
    print(evaluation, "\n")

    point_to_point_icp(source, target, threshold, trans_init)
    point_to_plane_icp(source, target, threshold, trans_init)

参考

有关Python Open3D点云配准点对点,点对面ICP(Iterative Closest Point)的更多相关文章

  1. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  2. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  3. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  4. [Vuforia]二.3D物体识别 - 2

    之前说过10之后的版本没有3dScan了,所以还是9.8的版本或者之前更早的版本。 3d物体扫描需要先下载扫描的APK进行扫面。首先要在手机上装一个扫描程序,扫描现实中的三维物体,然后上传高通官网,在下载成UnityPackage类型让Unity能够使用这个扫描程序可以从高通官网上进行下载,是一个安卓程序。点到Tools往下滑,找到VuforiaObjectScanner下载后解压数据线连接手机,将apk文件拷入手机安装然后刚才解压文件中的Media文件夹打开,两个PDF图打印第一张A4-ObjectScanningTarget.pdf,主要是用来辅助扫描的。好了,接下来就是扫描三维物体。将瓶

  5. python - Ruby 或 Python 的 3d 游戏引擎? - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于StackOverflow来说是偏离主题的,因为它们往往会吸引自以为是的答案和垃圾邮件。相反,describetheproblem以及迄今为止为解决该问题所做的工作。关闭9年前。Improvethisquestion是否有适用于这些的3d游戏引擎?

  6. 【自动驾驶环境感知项目】——基于Paddle3D的点云障碍物检测 - 2

    文章目录1.自动驾驶实战:基于Paddle3D的点云障碍物检测1.1环境信息1.2准备点云数据1.3安装Paddle3D1.4模型训练1.5模型评估1.6模型导出1.7模型部署效果附录show_lidar_pred_on_image.py1.自动驾驶实战:基于Paddle3D的点云障碍物检测项目地址——自动驾驶实战:基于Paddle3D的点云障碍物检测课程地址——自动驾驶感知系统揭秘1.1环境信息硬件信息CPU:2核AI加速卡:v100总显存:16GB总内存:16GB总硬盘:100GB环境配置Python:3.7.4框架信息框架版本:PaddlePaddle2.4.0(项目默认框架版本为2.3

  7. Unity3D : 本地坐标系,世界坐标系,和TransformPoint,TransformVector,TransformDirection的区别 - 2

    目录一、世界坐标系与本地坐标系二、srcGameObject.transform.TransformPoint(Vector3 vec)三、srcGameObject.transform.TransformVector(Vector3 vec)四、srcGameObject.transform.TransformDirection(Vector3 vec)五:示例一、世界坐标系与本地坐标系    世界坐标很好理解,就是模型的transform.position,通常在无父物体的情况下,创建出来的模型默认位置就是世界坐标系的原点。    每个物体都有自身的坐标系,此坐标系就是本地坐标系。本地坐标

  8. ruby - ruby 的 3D 引擎 - 2

    我正在寻找用于开发ruby​​游戏的3D引擎。我找到了一些类似G3Druby或ogreb的东西。哪个更好用,功能更好?还有比这些更好的引擎吗? 最佳答案 两者似乎都是G3D和Ogre的包装器,因此您实际上应该比较G3D或Ogre是否更适合您的需求。通过包装器的大部分ruby​​外访问将在设置场景时进行,因此繁重的工作(每一帧)仍然在C/C++库和图形硬件上完成。因此,您应该比较这两个库。我不知道G3D,但它似乎提供了Ogre所缺乏的离线渲染功能。如果您需要专业游戏渲染引擎的广泛功能,Ogre通常是首选,并且您会发现几乎所有您会遇到的

  9. U3D游戏开发工程师正确入行姿势指南 - 2

    2021年,游戏圈上演了一场精彩绝伦的抢人大战。在上海游戏圈,年薪百万的人越来越多了。据多名HR估算,在上海,过去一年TA、引擎、美术等稀缺岗位拟的薪资涨幅大概在20%-30%左右。某位圈内知名资深游戏猎头对此发出感叹:“50K的数值策划、角色原画;70K的技术美术;80K的技术总监...他们的年薪总包都接近百万,就连应届生入行的薪资也水涨船高,这要是放在以往都是不敢想象的”。以往含年薪、期权等的年总包收入上百万元,起码得是总监级别。如今工作五六年的人从广深跳到上海游戏公司,年薪能从50-70万跃上100万元,拿百万年薪的游戏从业者越来越多了上海游戏圈近年发展迅速,既有颇具发展潜力的中生代F4

  10. 如何使用open3d合并多组mesh并输出结果 - 2

    关注公众号,发现CV技术之美最近在学习open3d的相关应用,然后遇到了一个很有趣的问题。给定多个mesh,我们可能会需要把他们全部合并到一个文件并使用。但是这并不好实现,因为open3d自己不支持这样的操作。相比之下,其他一些集成度非常高的软件,是可以实现这样的操作的,例如meshlab通过交互栏中的“flattenvisiblelayer”指令来实现。唯一的缺点是,你每次都需要手动操作才行,这对于需要高度自动化的使用场景,就不是很合适了。因此,如何可以实现一个自动化的脚本,支持直接合并多个可染色的mesh,并输出带有纹理的最终结果,是一个非常重要的功能。遗憾的是度娘和谷歌目前没有相关的教程

随机推荐