本文为转载文章,原创作者为blue同学,可关注他的博客:https://blog.csdn.net/io569417668

Open3D是一个开源库,支持快速开发和处理3D数据。Open3D在c++和Python中公开了一组精心选择的数据结构和算法。后端是高度优化的,并且是为并行化而设置的。

本系列学习计划有Blue同学作为发起人,主要以Open3D官方网站的教程为主进行翻译与实践的学习计划。点云PCL公众号作为免费的3D视觉,点云交流社区,期待有使用Open3D或者感兴趣的小伙伴能够加入我们的翻译计划,贡献免费交流社区,为使用Open3D提供中文的使用教程。

多视角配准是在全局空间中对齐多个几何形状的过程。比较有代表性的是,输入是一组几何形状Pi(可以是点云或者RGBD图像)。输出是一组刚性变换Ti,变换后的点云TiPi可以在全局空间中对齐。
Open3d通过姿态图估计提供了多视角配准的接口。具体的技术细节请参考[Choi2015].

输入

教程代码的第一部分是从三个文件中读取三个点云数据,这三个点云将被降采样和可视化,可以看出他们三个是不对齐的。

def load_point_clouds(voxel_size=0.0):pcds = []for i in range(3):pcd = o3d.io.read_point_cloud("../../TestData/ICP/cloud_bin_%d.pcd" % i)pcd_down = pcd.voxel_down_sample(voxel_size=voxel_size)pcds.append(pcd_down)return pcds
voxel_size = 0.02
pcds_down = load_point_clouds(voxel_size)
o3d.visualization.draw_geometries(pcds_down)

姿态图

姿态图有两个关键的基础:节点和边。节点是与姿态矩阵i关联的一组几何体Pi,通过该矩阵能够将Pi转换到全局空间。集和Ti是一组待优化的未知的变量。

PoseGraph.nodes是PoseGraphNode的列表。我们设P0的空间是全局空间。因此T0是单位矩阵。其他的姿态矩阵通过累加相邻节点之间的变换来初始化。相邻节点通常都有着大规模的重叠并且能够通过Point-to-plane ICP来配准。

姿态图的边连接着两个重叠的节点(几何形状)。每个边都包含着能够将源几何Pi 和目标几何Pj对齐的变换矩阵Ti,j。本教程使用Point-to-plane ICP来估计变换矩阵。在更复杂的情况中,成对的配准问题一般是通过全局配准来解决的。

[Choi2015] 观察到,成对的配准容易出错。甚至错误的匹配会大于正确的匹配,因此,他们将姿态图的边分为两类。Odometry edges连接着邻域节点,使用局部配准的方式比如ICP就可以对齐他们。Loop closure edges连接着非邻域的节点。该对齐是通过不太可靠的全局配准找到的。在Open3d中,这两类边缘通过PoseGraphEdge初始化程序中的uncertain参数来确定。

除了旋转矩阵Ti以外,用户也可以去设置每一条边的信息矩阵Ai。如果是通过
get_information_matrix_from_point_clouds设置的信息矩阵Ai,那么姿态图的边的损失将以 line process weight 近似于两组节点对应点集的RMSE。有关详细细节请参考[Choi2015] 和 the Redwood registration benchmark。

下面的脚本创造了具有三个节点和三个边的姿态图。这些边里,两个是odometry edges(uncertain = False),一个是loop closure edge(uncertain = True)。

def pairwise_registration(source, target):print("Apply point-to-plane ICP")icp_coarse = o3d.registration.registration_icp(source, target, max_correspondence_distance_coarse, np.identity(4),o3d.registration.TransformationEstimationPointToPlane())icp_fine = o3d.registration.registration_icp(source, target, max_correspondence_distance_fine,icp_coarse.transformation,o3d.registration.TransformationEstimationPointToPlane())transformation_icp = icp_fine.transformationinformation_icp = o3d.registration.get_information_matrix_from_point_clouds(source, target, max_correspondence_distance_fine,icp_fine.transformation)return transformation_icp, information_icpdef full_registration(pcds, max_correspondence_distance_coarse,max_correspondence_distance_fine):pose_graph = o3d.registration.PoseGraph()odometry = np.identity(4)pose_graph.nodes.append(o3d.registration.PoseGraphNode(odometry))n_pcds = len(pcds)for source_id in range(n_pcds):for target_id in range(source_id + 1, n_pcds):transformation_icp, information_icp = pairwise_registration(pcds[source_id], pcds[target_id])print("Build o3d.registration.PoseGraph")if target_id == source_id + 1:  # odometry caseodometry = np.dot(transformation_icp, odometry)pose_graph.nodes.append(o3d.registration.PoseGraphNode(np.linalg.inv(odometry)))pose_graph.edges.append(o3d.registration.PoseGraphEdge(source_id,target_id,transformation_icp,information_icp,uncertain=False))else:  # loop closure casepose_graph.edges.append(o3d.registration.PoseGraphEdge(source_id,target_id,transformation_icp,information_icp,uncertain=True))return pose_graphprint("Full registration ...")
max_correspondence_distance_coarse = voxel_size * 15
max_correspondence_distance_fine = voxel_size * 1.5
with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:pose_graph = full_registration(pcds_down,max_correspondence_distance_coarse,max_correspondence_distance_fine)

Open3d使用函数global_optimization进行姿态图估计,可以选择两种类型的优化算法,分别是GlobalOptimizationGaussNewto

和GlobalOptimizationLevenbergMarquardt。比较推荐后一种的原因是因为它具有比较好的收敛性。GlobalOptimizationConvergenceCriteria类可以用来设置最大迭代次数和别的优化参数。

GlobalOptimizationOption定于了两个参数。max_correspondence_distance定义了对应阈值。edge_prune_threshold是修剪异常边缘的阈值。reference_node是被视为全局空间的节点ID。

print("Optimizing PoseGraph ...")
option = o3d.registration.GlobalOptimizationOption(max_correspondence_distance=max_correspondence_distance_fine,edge_prune_threshold=0.25,reference_node=0)
with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:o3d.registration.global_optimization(pose_graph, o3d.registration.GlobalOptimizationLevenbergMarquardt(),o3d.registration.GlobalOptimizationConvergenceCriteria(), option)

全局优化在姿态图上执行两次。第一遍将考虑所有边缘的情况优化原始姿态图的姿态,并尽量区分不确定边缘之间的错误对齐。这些错误对齐将会产生小的 line process weights,他们将会在第一遍被剔除。第二遍将会在没有这些边的情况下运行,产生更紧密地全局对齐效果。在这个例子中,所有的边都将被考虑为真实的匹配,所以第二遍将会立即终止。

可视化操作

使用```draw_geometries``函数可视化变换点云。

print("Transform points and display")
for point_id in range(len(pcds_down)):print(pose_graph.nodes[point_id].pose)pcds_down[point_id].transform(pose_graph.nodes[point_id].pose)
o3d.visualization.draw_geometries(pcds_down)

Transform points and display
[[ 1.00000000e+00 -2.50509994e-19 0.00000000e+00 0.00000000e+00]
[-3.35636805e-20 1.00000000e+00 1.08420217e-19 -8.67361738e-19]
[-1.08420217e-19 -1.08420217e-19 1.00000000e+00 0.00000000e+00]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]]
[[ 0.8401689 -0.14645453 0.52217554 0.34785474]
[ 0.00617659 0.96536804 0.2608187 -0.39427149]
[-0.54228965 -0.2159065 0.81197679 1.7300472 ]
[ 0. 0. 0. 1. ]]
[[ 0.96271237 -0.07178412 0.2608293 0.3765243 ]
[-0.00196124 0.96227508 0.27207136 -0.48956598]
[-0.27051994 -0.26243801 0.92625334 1.29770817]
[ 0. 0. 0. 1. ]]

得到合并的点云

PointCloud是可以很方便的使用+来合并两组点云成为一个整体。合并之后,将会使用voxel_down_sample进行重新采样。建议在合并之后对点云进行后处理,因为这样可以减少重复的点后者较为密集的点。

pcds = load_point_clouds(voxel_size)
pcd_combined = o3d.geometry.PointCloud()
for point_id in range(len(pcds)):pcds[point_id].transform(pose_graph.nodes[point_id].pose)pcd_combined += pcds[point_id]
pcd_combined_down = pcd_combined.voxel_down_sample(voxel_size=voxel_size)
o3d.io.write_point_cloud("multiway_registration.pcd", pcd_combined_down)
o3d.visualization.draw_geometries([pcd_combined_down])

尽管这个教程展示的点云的多视角配准,但是相同的处理步骤可以应用于RGBD图像,请参看 Make fragments 示例。

资源

三维点云论文及相关应用分享

【点云论文速读】基于激光雷达的里程计及3D点云地图中的定位方法

3D目标检测:MV3D-Net

三维点云分割综述(上)

3D-MiniNet: 从点云中学习2D表示以实现快速有效的3D LIDAR语义分割(2020)

win下使用QT添加VTK插件实现点云可视化GUI

JSNet:3D点云的联合实例和语义分割

大场景三维点云的语义分割综述

PCL中outofcore模块---基于核外八叉树的大规模点云的显示

基于局部凹凸性进行目标分割

基于三维卷积神经网络的点云标记

点云的超体素(SuperVoxel)

基于超点图的大规模点云分割

更多文章可查看:点云学习历史文章大汇总

SLAM及AR相关分享

【开源方案共享】ORB-SLAM3开源啦!

【论文速读】AVP-SLAM:自动泊车系统中的语义SLAM

【点云论文速读】StructSLAM:结构化线特征SLAM

SLAM和AR综述

常用的3D深度相机

AR设备单目视觉惯导SLAM算法综述与评价

SLAM综述(4)激光与视觉融合SLAM

Kimera实时重建的语义SLAM系统

SLAM综述(3)-视觉与惯导,视觉与深度学习SLAM

易扩展的SLAM框架-OpenVSLAM

高翔:非结构化道路激光SLAM中的挑战

SLAM综述之Lidar SLAM

基于鱼眼相机的SLAM方法介绍

往期线上分享录播汇总

第一期B站录播之三维模型检索技术

第二期B站录播之深度学习在3D场景中的应用

第三期B站录播之CMake进阶学习

第四期B站录播之点云物体及六自由度姿态估计

第五期B站录播之点云深度学习语义分割拓展

第六期B站录播之Pointnetlk解读

[线上分享录播]点云配准概述及其在激光SLAM中的应用

[线上分享录播]cloudcompare插件开发

[线上分享录播]基于点云数据的 Mesh重建与处理

[线上分享录播]机器人力反馈遥操作技术及机器人视觉分享

[线上分享录播]地面点云配准与机载点云航带平差

点云PCL更多活动请查看:点云PCL活动之应届生校招群

扫描下方微信视频号二维码可查看最新研究成果及相关开源方案的演示:

如果你对Open3D感兴趣,或者正在使用该开源方案,就请加入我们,一起翻译,一起学习,贡献自己的力量,目前阶段主要以微信群为主,有意者发送“Open3D学习计划”到公众号后台,和更多热爱分享的小伙伴一起交流吧!如果翻译的有什么问题或者您有更好的意见,请评论交流!!!!

以上内容如有错误请留言评论,欢迎指正交流。如有侵权,请联系删除

扫描二维码

关注我们

让我们一起分享一起学习吧!期待有想法,乐于分享的小伙伴加入免费星球注入爱分享的新鲜活力。分享的主题包含但不限于三维视觉,点云,高精地图,自动驾驶,以及机器人等相关的领域。

分享及合作:微信“920177957”(需要按要求备注) 联系邮箱:dianyunpcl@163.com,欢迎企业来联系公众号展开合作。

点一下“在看”你会更好看耶

Open3d学习计划—高级篇 4(多视角点云配准)相关推荐

  1. Open3d学习计划—高级篇 2(彩色点云配准)

    Open3D是一个开源库,支持快速开发和处理3D数据.Open3D在c++和Python中公开了一组精心选择的数据结构和算法.后端是高度优化的,并且是为并行化而设置的. 本系列学习计划有Blue同学作 ...

  2. Open3d学习计划——高级篇 6(体素化)

    Open3d学习计划--高级篇 6(体素化) 点云和三角网格是一种十分灵活的,但是不规则的几何类型.体素网格是通过规则的3D网格来表示的另一种3D几何类型,并且它可以看作是2D像素在3D上的对照物.O ...

  3. Open3d学习计划——高级篇 9(表面重建)

    Open3d学习计划--高级篇 9(表面重建) 在许多场景下我们希望生成密集的3D几何形状,比如三角网格.然而从多视图立体算法和深度传感器中我们只能够获得非结构化的点云数据.我们需要使用表面重建算法来 ...

  4. Open3d学习计划—高级篇 3(点云全局配准)

    Open3D是一个开源库,支持快速开发和处理3D数据.Open3D在c++和Python中公开了一组精心选择的数据结构和算法.后端是高度优化的,并且是为并行化而设置的. 本系列学习计划有Blue同学作 ...

  5. Open3d学习计划—高级篇 8(网格变形)

    Open3D是一个开源库,支持快速开发和处理3D数据.Open3D在c++和Python中公开了一组精心选择的数据结构和算法.后端是高度优化的,并且是为并行化而设置的. 本系列学习计划有Blue同学作 ...

  6. Open3d学习计划—高级篇 7(颜色映射)

    Open3D是一个开源库,支持快速开发和处理3D数据.Open3D在c++和Python中公开了一组精心选择的数据结构和算法.后端是高度优化的,并且是为并行化而设置的. 本系列学习计划有Blue同学作 ...

  7. Open3d学习计划—高级篇 6(体素化)

    Open3D是一个开源库,支持快速开发和处理3D数据.Open3D在c++和Python中公开了一组精心选择的数据结构和算法.后端是高度优化的,并且是为并行化而设置的. 本系列学习计划有Blue同学作 ...

  8. Open3d学习计划—高级篇 5(RGBD融合)

    Open3D是一个开源库,支持快速开发和处理3D数据.Open3D在c++和Python中公开了一组精心选择的数据结构和算法.后端是高度优化的,并且是为并行化而设置的. 本系列学习计划有Blue同学作 ...

  9. Open3d 学习计划—12(Jupyter 可视化)

    Open3D是一个开源库,支持快速开发和处理3D数据.Open3D在c++和Python中公开了一组精心选择的数据结构和算法.后端是高度优化的,并且是为并行化而设置的. 本系列学习计划有Blue同学作 ...

最新文章

  1. python【力扣LeetCode算法题库】217-存在重复元素
  2. 【网址收藏】Porter:面向裸金属环境的 Kubernetes 开源负载均衡器
  3. junit rule_使用JUnit的ExpectedException和@Rule测试自定义异常
  4. java接口继承编程题_JavaSE习题 继承接口和泛型
  5. 95-120-046-源码-Cluster-YarnSessionClusterEntrypoint
  6. 谷歌开源Allstar 项目,保护GitHub 仓库安全
  7. Java开发命名规范
  8. 支付宝架构到底有多牛逼?看完这篇你就明白了!
  9. ssh访问限制 /etc/hosts.allow 和/etc/hosts.deny 详解
  10. Lasergene DNASTAR 8.1.3 特别版 Mac 专业的医学生物综合性序列分析工具
  11. 汉诺塔问题解析(C语言)
  12. 微信卡券开发-卡券核销
  13. SICP练习题1.14
  14. php 微信定位源码_微信活码模块源码 - WEB源码|PHP源码|源代码 - 源码中国
  15. 对this.name=name的理解
  16. python爬虫——正则表达式
  17. FFmpeg av_dump_format函数使用
  18. Azure China (11) 使用Azure China Storage Public Blob
  19. 吐血整理深度学习入门路线及导航【教学视频+大神博客+书籍整理】+【资源页】(2019年已经最后一个月了,你还不学深度学习吗???)
  20. filesystem判断文件或文件夹是否存在

热门文章

  1. 【Redfin SDE intern】跪经
  2. [转] PuTTY + Xming 远程使用 Linux GUI
  3. poj 2559 Largest Rectangle in a Histogram 栈
  4. 关于HTML代码的转义
  5. java.util.concurrent包API学习笔记
  6. Spring学习笔记_IOC
  7. Java学习笔记---字符类型
  8. js高级程序设计之跨浏览器事件处理
  9. [转]C#日期格式化 文档
  10. java 远程共享_【原创】(扫盲)远程共享对象SharedObject的用法