open3d ICP 配准

news2024/9/22 7:34:50

文章目录

  • Three common registration techniques
    • Point-to-point technique
    • Point-to-plane registration
  • ICP registration
    • Helper visualization function
    • Input
    • Global registration
      • Extract geometric feature
      • Input
      • RANSAC
    • Point-to-point ICP
    • Point-to-plane ICP
  • References

Three common registration techniques

假设有一个点集 P \boldsymbol{P} P 在源表面 S P \mathcal{S}_P SP,另一个点集 Q \boldsymbol{Q} Q 在目的表面 S Q \mathcal{S}_Q SQ。如果在每个表面都有 K K K 个点,那么配准问题可以看作一个刚体变换 T = [ R ∣ t ] \boldsymbol{T}=[\boldsymbol{R}|\boldsymbol{t}] T=[Rt],最小化下面的对准误差: ϵ = ∑ k = 1 K ∥ Q k − ( R P k + t ) ∥ 2 \epsilon=\sum_{k=1}^K \| \boldsymbol{Q}_k-(\boldsymbol{R}\boldsymbol{P}_k+\boldsymbol{t})\|^2 ϵ=k=1KQk(RPk+t)2

在这里插入图片描述

Point-to-point technique

从源表面的一点 p \boldsymbol{p} p 出发,p2p 寻找目的表面上最近的点 q \boldsymbol{q} q d s d_s ds 代表两点之间的距离。为了找到最近点,通常会采用 kd-tree 来进行搜索。

Point-to-plane registration

从源点的法向量寻找目的表面的交叉点。如上图 (b) 所示,点 q ′ \boldsymbol{q}' q 是点 p \boldsymbol{p} p 在点 q \boldsymbol{q} q正切平面上的投影。

ICP registration

输入:两个点云及一个初始的可以大致对准两个点云的变换矩阵;

输出:可以准确对准两个点云的变换矩阵。

Helper visualization function

下面的函数可视化目标点云和经过变换后的源点云:

def draw_registration_result(source, target, transformation):
    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_geometries([source_temp, target_temp],
                                      zoom=0.4459,
                                      front=[0.9288, -0.2951, -0.2242],
                                      lookat=[1.6784, 2.0612, 1.4451],
                                      up=[-0.3402, -0.9189, -0.1996])

因为函数 transformpaint_uniform_color 会改变原始点云,因此这里用深拷贝 copy.deepcopy 来“保护”原始点云。

Input

下面的代码从两个文件中分别读入源点云和目标点云,并给出了一个初始变换矩阵。

demo_icp_pcds = o3d.data.DemoICPPointClouds()
source = o3d.io.read_point_cloud(demo_icp_pcds.paths[0])
target = o3d.io.read_point_cloud(demo_icp_pcds.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)

下面的函数 evaluate_registration 主要计算两个指标:

  • fitness:衡量重叠区域的大小(# of inlier correspondences / # of points in target),越大越好
  • inlier_rmse:计算所有 inlier correspondences 的 RMSE,越小越好

初始的变换矩阵通常通过一个全局的配准算法得到。

Global registration

Extract geometric feature

下采样点云,估计法向量,然后对每个点计算 FPFH 特征。FPFH 特征是一个 33 维的向量,它可以描述一个点的局部几何性质。

def preprocess_point_cloud(pcd, voxel_size):
    print(":: Downsample with a voxel size %.3f." % voxel_size)
    pcd_down = pcd.voxel_down_sample(voxel_size)

    radius_normal = voxel_size * 2
    print(":: Estimate normal with search radius %.3f." % radius_normal)
    pcd_down.estimate_normals(
        o3d.geometry.KDTreeSearchParamHybrid(radius=radius_normal, max_nn=30))

    radius_feature = voxel_size * 5
    print(":: Compute FPFH feature with search radius %.3f." % radius_feature)
    pcd_fpfh = o3d.pipelines.registration.compute_fpfh_feature(
        pcd_down,
        o3d.geometry.KDTreeSearchParamHybrid(radius=radius_feature, max_nn=100))
    return pcd_down, pcd_fpfh

Input

def prepare_dataset(voxel_size):
    print(":: Load two point clouds and disturb initial pose.")

    demo_icp_pcds = o3d.data.DemoICPPointClouds()
    source = o3d.io.read_point_cloud(demo_icp_pcds.paths[0])
    target = o3d.io.read_point_cloud(demo_icp_pcds.paths[1])
    trans_init = np.asarray([[0.0, 0.0, 1.0, 0.0], [1.0, 0.0, 0.0, 0.0],
                             [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0]])
    source.transform(trans_init)
    draw_registration_result(source, target, np.identity(4))

    source_down, source_fpfh = preprocess_point_cloud(source, voxel_size)
    target_down, target_fpfh = preprocess_point_cloud(target, voxel_size)
    return source, target, source_down, target_down, source_fpfh, target_fpfh

RANSAC

在每个 RANSAC 的迭代中,ransac_n 个随机点从源点云中被选出。它们在目标点云中的对应点通过查询 33 维的 FPFH 特征空间得到。

def execute_global_registration(source_down, target_down, source_fpfh,
                                target_fpfh, voxel_size):
    distance_threshold = voxel_size * 1.5
    print(":: RANSAC registration on downsampled point clouds.")
    print("   Since the downsampling voxel size is %.3f," % voxel_size)
    print("   we use a liberal distance threshold %.3f." % distance_threshold)
    result = o3d.pipelines.registration.registration_ransac_based_on_feature_matching(
        source_down, target_down, source_fpfh, target_fpfh, True,
        distance_threshold,
        o3d.pipelines.registration.TransformationEstimationPointToPoint(False),
        3, [
            o3d.pipelines.registration.CorrespondenceCheckerBasedOnEdgeLength(
                0.9),
            o3d.pipelines.registration.CorrespondenceCheckerBasedOnDistance(
                distance_threshold)
        ], o3d.pipelines.registration.RANSACConvergenceCriteria(100000, 0.999))
    return result
result_ransac = execute_global_registration(source_down, target_down,
                                            source_fpfh, target_fpfh,
                                            voxel_size)
print(result_ransac)
draw_registration_result(source_down, target_down, result_ransac.transformation)

之后我们就需要用点到点的 ICP 或者点到面的 ICP 来进一步提升配准精度。

Point-to-point ICP

从以下两步骤中进行迭代:

  1. 从目标点云 P \boldsymbol{P} P 中寻找对应点集 K = { ( p , q ) } \mathcal{K}=\{(\boldsymbol{p},\boldsymbol{q})\} K={(p,q)},源点云通过现有的变换矩阵 T \boldsymbol{T} T 进行变换;
  2. 通过最小化目标函数 E ( T ) E(\boldsymbol{T}) E(T) 来更新变换矩阵 T \boldsymbol{T} T。不同的 ICP 变体会采用不同的目标函数 E ( T ) E(\boldsymbol{T}) E(T),这里使用如下的目标函数 E ( T ) = ∑ ( p , q ) ∈ K ∥ p − T q ∥ 2 E(\boldsymbol{T})=\sum_{(\boldsymbol{p},\boldsymbol{q})\in \mathcal{K}} \|\boldsymbol{p}-\boldsymbol{T}\boldsymbol{q} \|^2 E(T)=(p,q)KpTq2
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)
draw_registration_result(source, target, reg_p2p.transformation)

默认情况下,registration_icp 会运行直到收敛或者达到了默认最大迭代次数(30)。 也可以指定最大的迭代次数:

reg_p2p = o3d.pipelines.registration.registration_icp(
    source, target, threshold, trans_init,
    o3d.pipelines.registration.TransformationEstimationPointToPoint(),
    o3d.pipelines.registration.ICPConvergenceCriteria(max_iteration=2000))
print(reg_p2p)
print("Transformation is:")
print(reg_p2p.transformation)
draw_registration_result(source, target, reg_p2p.transformation)

Point-to-plane ICP

点到面的 ICP 采用下面的目标函数:
E ( T ) = ∑ ( p , q ) ∈ K ( ( p − T q ) ⋅ n p ) 2 E(\boldsymbol{T})=\sum_{(\boldsymbol{p},\boldsymbol{q})\in \mathcal{K}} ((\boldsymbol{p}-\boldsymbol{T}\boldsymbol{q})\cdot \boldsymbol{n}_p)^2 E(T)=(p,q)K((pTq)np)2
n p \boldsymbol{n}_p np 代表每个点 p \boldsymbol{p} p 的法向量。点到面 ICP 比点到点 ICP 有更快的收敛速度。

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)
draw_registration_result(source, target, reg_p2l.transformation)

References

[1] open3d 官方文档,http://www.open3d.org/docs/release/tutorial/pipelines/icp_registration.html

[2] Park, S.-Y & Subbarao, M… (2003). A fast Point-to-Tangent Plane technique for multi-view registration. Fourth IEEE International Conference on 3-D Digital Imaging and Modeling. 500. 276- 283. 10.1109/IM.2003.1240260.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1230701.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年Java核心技术大会(Core Java Week 2023)-核心PPT资料下载

一、峰会简介 人工智能在22年、23年的再次爆发让Python成为编程语言里最大的赢家;云原生的持续普及令Go、Rust等新生的语言有了进一步叫板传统技术体系的资本与底气。我们必须承认在近几年里,Java阵营的确受到了前所未有的挑战,出现了更多更…

解决 Python requests 库中 SSL 错误转换为 Timeouts 问题

解决 Python requests 库中 SSL 错误转换为 Timeouts 问题:理解和处理 SSL 错误的关键 在使用Python的requests库进行HTTPS请求时,可能会遇到SSL错误,这些错误包括但不限于证书不匹配、SSL层出现问题等。如果在requests库中设置verifyFalse&…

RAID技术复习笔记

Raid(Redundant Array of independent Disks)独立磁盘冗余阵列:磁盘阵列 Raid 分为:软raid、硬raid、软硬混合三种。 软Raid:所有的功能均有操作系统和CPU来完成,没有独立的raid控制、处理芯片和IO处理处理芯片。 硬R…

5.1异常处理

5.1异常处理 1. 什么是异常2. 异常分类2.1 Error2.2 Exception 3. 异常处理3.1 try-catch-finally终止finally执行的方法return关键字在异常处理的作用 1. 什么是异常 2. 异常分类 2.1 Error 2.2 Exception 2.2.1 非检查异常 2.2.2 检查异常 3. 异常处理 3.1 try-catch-fina…

R语言:利用biomod2进行生态位建模

在这里主要是分享一个不错的代码,喜欢的可以慢慢研究。我看了一遍,觉得里面有很多有意思的东西,供大家学习和参考。 利用PCA轴总结的70个环境变量,利用biomod2进行生态位建模: #------------------------------------…

旋极携手西班牙SoC-e公司,为中国客户提供高效可靠TSN通讯解决方案

2023年2月,旋极信息与西班牙SoC-e公司正式签订战略合作协议,成为其在中国区重要合作伙伴。 SoC-e是一家世界领先的基于FPGA技术的以太网通讯解决方案供应商,是一系列IP核开发领域的先锋,为关键任务实施网络化、同步性和安全性提供…

2023年【高处安装、维护、拆除】模拟考试题及高处安装、维护、拆除模拟考试题库

题库来源:安全生产模拟考试一点通公众号小程序 2023年【高处安装、维护、拆除】模拟考试题及高处安装、维护、拆除模拟考试题库,包含高处安装、维护、拆除模拟考试题答案和解析及高处安装、维护、拆除模拟考试题库练习。安全生产模拟考试一点通结合国家…

客户管理系统大盘点!推荐这五款

客户管理系统大盘点!推荐这五款。 客户管理系统也就是CRM,可以说是企业刚需,国内外的客户管理系统也是数不胜数,到底有哪些是真正好用,值得推荐的呢?本文将为大家推荐这5款好用的客户管理系统:…

nvm:轻松管理多个 Node 版本 | 开源日报 No.80

nvm-sh/nvm Stars: 67.6k License: MIT Node Version Manager,是一个 POSIX 兼容的 bash 脚本,用于管理多个活动 node.js 版本。nvm 可以让你通过命令行快速安装和使用不同版本的 Node。它可以在任何符合 POSIX 标准的 shell(sh、dash、ksh…

城市生命线丨市政综合管廊监测系统的效果

市政综合管廊,又被称为城市生命线,是我们在地下建造的一个智慧而高效的空间。它把市政、电力、通讯、燃气、给排水等各种管线集于一体,解决了城市中反复开挖路面、架空线网密集、管线事故频发等问题,为城市运行提供了重要的基础设…

python_面向对象中的特殊成员

一、几个常见的特殊成员 # 都只是语法,无特殊意义 class Foo(object):def __init__(self,a1,a2):self.a1 a1self.a2 a2def __call__(self,*args,**kwargs):print(11111,args,kwargs)return 123def __getitem__(self, item):print(item)return 8def __setitem__(s…

DGL创建异构图

利用DGL创建具有3种节点类型和3种边类型的异构图 graph_data {# (src_type, edge_type, dst_type)(drug, interacts, drug): (th.tensor([0, 1]), th.tensor([1, 2])),(drug, interacts,, disease): (th.tensor([1]), th.tensor([2])) }g dgl.heterograph(graph_data)上述代…

C编译环境和预处理(非常详细,建议收藏)

C编译环境和预处理(非常详细,建议收藏) 一、程序的翻译环境和执行环境二、 详解编译链接2.1 翻译环境2.2 编译本身的几个阶段符号汇总、符号表、合并段表、符号表的合并和重定位分别是什么? 2.2 运行环境 三、预处理详解3.1 预定义…

C语言--每日五道选择题--Day19

第一题 1. 为了避免在嵌套的条件语句if-else中产生二义性,C语言规定else子句总是与( )配对。 A:缩排位置相同的if B:之前最近的未匹配的if配对 C:其之后最近的if D:同一行上的if 答案及解析 B e…

一图多码如何分解?快速做二维码解码的方法

当遇到一张图片里面有多个二维码时,想要将图片中的二维码分解成链接或者文本,该如何来操作呢?一般解决这个问题的方法多会通过使用二维码解码器来完成操作,那么对于还不知道的怎么操作的小伙伴,下面的方法可以来学习一…

Linux:安装IDEA开发工具

1、下载 下载地址:https://www.jetbrains.com/idea/download/?sectionlinux 2、上传及解压 将安装包上传到虚拟机,我建的目录是/opt/idea 解压:tar -zxvf ideaIU-2023.2.5.tar.gz 3、启动 启动IDEA需要登陆桌面系统,不能在…

剪辑视频怎么把说话声音转成文字?

短视频已然成为了一种生活潮流,我们每天都在浏览各种短视频,或者用视频的形式记录生活,在制作视频的时候,字幕是一个很大的问题,给视频添加字幕可以更直观、更方便浏览。手动添加太费时间,下面就给大家分享…

bitmap实践-留存计算

目录 1. 介绍2. 留存问题3. 思路解析4. 逻辑4.1 b表建设4.2 留存计算4.3 近X天的访问天数 5.分析 1. 介绍 bitmap方法是数据压缩使用的常用算法,当字段有明确上下界的时候,使用位图模式来减少存储。在业务指标体系中特别适合通用型留存指标的计算。 2.…

数智赋能,众创众治|易知微为“浙江省数字监管应用建模技能竞赛”提供技术支撑!

11月6日至8日,2023年浙江省数字监管应用建模技能竞赛在省金华监狱举行。浙江省监狱管理局党委书记、局长王争,司法部监狱管理局规划科技处处长常家瑛,浙江省监狱管理局党委委员、副局长朱永忠出席本次活动。 本次建模大赛共有来自全省监狱系…

MODBUS转PROFINET网关TS-180连接西门子PLC和工业称重仪表

项目 随着科技的高速发展,工业自动化行业对日益多样的称重需求越来越高,上海某公司在国内的一个 工业自动化项目中,监控中心系统需要远程实时采集工业称重仪表测量的各种称重参数。该系统使用的是 西门子 S7-300 PLC,支持 PROFINE…