Python-open3d点云配准

news2024/12/29 9:10:00

文章目录

    • ICP算法
    • 鲁棒核
    • ICP测试

ICP算法

ICP, 即Iterative Closest Point, 迭代点算法。

ICP算法有多种形式,其中最简单的思路就是比较点与点之间的距离,对于点云 P = { p i } , Q = { q i } P=\{p_i\}, Q=\{q_i\} P={pi},Q={qi}而言,如果二者是同一目标,通过旋转、平移等操作可以实现重合的话,那么只需要固定 Q Q Q而不断地旋转或平移 P P P,最终二者一定能最完美地重合。

R , t R, t R,t分别为旋转矩阵和平移矩阵,在完美匹配的情况下,必有 q i = R p i + t q_i = Rp_i + t qi=Rpi+t。但三维点云不具备栅格特征,故而很难保证 q i q_i qi p i p_i pi一一对应,所以求解问题变为优化问题,目标函数为

arg min ⁡ R , t 1 2 ∑ i = 1 n ∥ q i − R p i − t ∥ 2 \argmin_{R,t}\frac{1}{2}\sum^n_{i=1}\Vert q_i-Rp_i-t\Vert^2 R,targmin21i=1nqiRpit2

1992年Chen和Medioni对此方案进行了改进,提出了点对面的预估方法,其目标函数为

arg min ⁡ R , t 1 2 ∑ i = 1 n [ ( q i − R p i ) ⋅ n p ] 2 \argmin_{R,t}\frac{1}{2}\sum^n_{i=1}[(q_i-Rp_i)\cdot n_p]^2 R,targmin21i=1n[(qiRpi)np]2

其中 n p n_p np是点 p p p的法线,这种方案显然效率更高。

在使用ICP算法前后,两个点云的叠加图像变化如下

在这里插入图片描述

基于Open3d实现的代码如下

import numpy as np
import open3d as o3d

pipreg = o3d.pipelines.registration

pcd = o3d.data.DemoICPPointClouds()
src = o3d.io.read_point_cloud(pcd.paths[0])
tar = o3d.io.read_point_cloud(pcd.paths[1])
th = 0.02
trans_init = np.array([
    [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]])

reg = pipreg.registration_icp(
    src, tar, th, trans_init,
    pipreg.TransformationEstimationPointToPoint())

print(reg.transformation)   # 变换矩阵
print(reg)  # 表示点云配准的拟合程度
'''
fitness=3.724495e-01, inlier_rmse=7.760179e-03, and correspondence_set size of 74056 Access transformation to get result.
'''

【registration_icp】即为open3d实现的点云配准函数,在示例中,输入的5个参数分别为点云 P P P、目标点云 Q Q Q、同名点未匹配时的最大距离、初始变化矩阵、变换方法。

【TransformationEstimationPointToPoint】即点对点的目标函数。

匹配完成后,打印的变换矩阵为

[ 0.83924644 0.01006041 − 0.54390867 0.64639961 − 0.15102344 0.96521988 − 0.21491604 0.75166079 0.52191123 0.2616952 0.81146378 − 1.50303533 0. 0. 0. 1. ] ] \begin{bmatrix} 0.83924644&0.01006041&-0.54390867&0.64639961\\ -0.15102344&0.96521988&-0.21491604&0.75166079\\ 0.52191123&0.2616952& 0.81146378&-1.50303533\\ 0.& 0.&0.&1. ]\\ \end{bmatrix} 0.839246440.151023440.521911230.0.010060410.965219880.26169520.0.543908670.214916040.811463780.0.646399610.751660791.503035331.]

绘图代码如下

from copy import deepcopy
srcDraw = deepcopy(src)
tarDraw = deepcopy(tar)
srcDraw.paint_uniform_color([1, 1, 0])
tarDraw.paint_uniform_color([0, 1, 1])

srcDrawICP = deepcopy(src)
tarDrawICP = deepcopy(tarDraw)
srcDrawICP.transform(reg.transformation)

geo = [srcDraw, tarDraw,
       srcDrawICP.translate((4.5, 0, 0)),
       tarDrawICP.translate((4.5, 0, 0))]

o3d.visualization.draw_geometries(geo)

鲁棒核

现有点云 P , Q P,Q P,Q,若二者存在一一对应的点列 p i ∈ P , q i ∈ Q p_i\in P, q_i\in Q piP,qiQ,通过对 Q Q Q进行矩阵变换 T T T,以期二者完全配准,那么对于第 i i i个点而言,记 r i ( T ) = ( p i − T q i ) ⋅ n p i r_i(T)=(p_i-Tq_i)\cdot n_{p_i} ri(T)=(piTqi)npi n p i n_{p_i} npi为点 p i p_i pi的法向量,即 q i q_i qi在经过矩阵变换后与 p i p_i pi在其法向量方向的残差。

则点对面ICP的目的,就是让下面的函数取值最小

E ( T ) = ∑ i = 1 N r i ( T ) 2 E(T)=\sum_{i=1}^Nr_i(T)^2 E(T)=i=1Nri(T)2

在这个优化问题中, r i r_i ri的作用举足轻重,任何对 r i r_i ri的形式上的更改,都会直接影响优化结果,例如将这个优化问题改写成重复加权最小二乘法的形式

E ( T ) = ∑ i = 1 N w i r i ( T ) 2 E(T)=\sum_{i=1}^Nw_ir_i(T)^2 E(T)=i=1Nwiri(T)2

r i r_i ri乘上一个权重,那么在具体匹配的过程中,就可以降低某些特殊值的影响。如果这个权重本身就是 r i r_i ri的函数,那么加权过程可以写成更加抽象的形式

E ( T ) = ∑ i = 1 N ρ [ r i ( T ) ] E(T)=\sum_{i=1}^N\rho[r_i(T)] E(T)=i=1Nρ[ri(T)]

ρ \rho ρ可称为Robust核函数,open3d中封装了如下和函数

核函数封装
L1损失L1Loss ω ( r ) = 1 ∣ r ∣ → ρ ( r ) = ∣ r ∣ \omega(r)=\frac1{\vert r\vert }\to\rho(r)=\vert r\vert ω(r)=r1ρ(r)=r
L2损失L2Loss ω ( r ) = 1 → ρ ( r ) = r 2 2 \omega(r)=1\to\rho(r)=\frac{r^2}2 ω(r)=1ρ(r)=2r2
柯西核CauchyLoss ω ( r ) = 1 1 + ( r k ) 2 → ρ ( r ) = k 2 2 log ⁡ ( 1 + ( r k ) 2 ) \omega(r)=\frac1{1+(\frac r k)^2}\to \rho(r)=\frac{k^2}{2}\log(1+(\frac r k)^2) ω(r)=1+(kr)21ρ(r)=2k2log(1+(kr)2)
GM核GMLoss ω ( r ) = k ( k + r 2 ) 2 → ρ ( r ) = r 2 / 2 k + r 2 \omega(r)=\frac{k}{(k+r^2)^2}\to\rho(r)=\frac{r^2/2}{k+r^2} ω(r)=(k+r2)2kρ(r)=k+r2r2/2
Huber核HuberLoss
Tukey核TukeyLoss

Huber核以及Tukey核相对复杂,表示如下

  • Huber核

ω ( r ) = { 1 ∣ r ∣ ⩽ k k ∣ r ∣ otherwise ⁡ → ρ ( r ) = { r 2 2 ∣ r ∣ < k k ∣ r ∣ − k 2 2 otherwise ⁡ \omega(r)=\begin{cases} 1&|r|\leqslant k\\ \frac{k}{|r|}& \operatorname{otherwise} \end{cases}\to \rho(r)=\begin{cases} \frac{r^2}{2} & |r|<k \\ k|r|-\frac{k^2}{2} & \operatorname{otherwise} \end{cases} ω(r)={1rkrkotherwiseρ(r)={2r2kr2k2r<kotherwise

  • Tukey核

ω ( r ) = { [ 1 − ( r k ) 2 ] 2 ∣ r ∣ ⩽ k 0 otherwise ⁡ → ρ ( r ) = { k 2 { 1 − [ 1 − ( e k ) 2 ] 3 } 2 ∣ r ∣ < k r 2 2 otherwise ⁡ \omega(r)=\begin{cases} [1-(\frac r k)^2]^2 &|r|\leqslant k\\ 0 & \operatorname{otherwise} \end{cases}\to \rho(r)=\begin{cases} \frac{k^2\big\{1-[1-(\frac e k)^2]^3\big\}}{2}& |r|<k \\ \frac{r^2}{2} & \operatorname{otherwise} \end{cases} ω(r)={[1(kr)2]20rkotherwiseρ(r)= 2k2{1[1(ke)2]3}2r2r<kotherwise

除了L1Loss和L2Loss之外,其他损失函数均有参数 k k k,当 k k k设为0.5时,这四个和函数的图像为

在这里插入图片描述

绘图代码如下

import numpy as np
import matplotlib.pyplot as plt
import open3d as o3d

pipreg = o3d.pipelines.registration

kerrDct = {
"cuchy" : pipreg.CauchyLoss,
"GM"    : pipreg.GMLoss,
"huber" : pipreg.HuberLoss,
"tukey" : pipreg.TukeyLoss
}

fig = plt.figure()
xs = np.linspace(-2,2,1000)
for i,key in enumerate(kerrDct):
    kerr = kerrDct[key](0.5)
    ys = [kerr.weight(x) for x in xs]
    ax = fig.add_subplot(221+i)
    ax.plot(xs, ys)
    plt.title(key)

plt.show()

ICP测试

下面对鲁棒核的效果进行测试,首先打开测试点云,并添加一点噪声

demo = o3d.data.DemoICPPointClouds()
src = o3d.io.read_point_cloud(demo.paths[0])
tar = o3d.io.read_point_cloud(demo.paths[1])

pts = np.array(src.points)

# 添加正态分布的噪声
pts += np.random.normal(0, 0.1, size=pts.shape)
srcNoise = o3d.geometry.PointCloud()
srcNoise.points = o3d.utility.Vector3dVector(pts)

srcDraw = deepcopy(src)
o3d.visualization.draw_geometries([srcDraw.translate((-4.5,0,0)),
    srcNoise])

加完噪声前后的点云图如下,几乎连轮廓都看不出来了

在这里插入图片描述

所以问题就是,右边那一坨五颜六色的东西真的可以和左边的图匹配到一起去吗?如果仍然使用传统的ICP算法,结果如下,可见完全没有配准

在这里插入图片描述

代码为

p2L = pipreg.TransformationEstimationPointToPlane()
regP2L = pipreg.registration_icp(srcNoise, tar, 0.5, trans_init, p2L)

srcP2L = deepcopy(src)
srcP2L.transform(regP2L.transformation)
srcP2L.paint_uniform_color([0, 1, 1])
o3d.visualization.draw_geometries([srcP2L, tar])

接下来,则是见证奇迹的时刻,采用Turkey核来重新配准一下,考虑到核函数的权重会随着距离增大而减小,最后缩减至0,所以阈值在icp函数中显得就不那么重要了,下面随便选一个非常不靠谱的大数10,然后看一下配准结果

loss = o3d.pipelines.registration.TukeyLoss(k=0.1)
turkey = pipreg.TransformationEstimationPointToPlane(loss)
regTurkey = pipreg.registration_icp(srcNoise, tar, 10, trans_init, turkey)

srcTurkey = deepcopy(src)
srcTurkey.transform(regTurkey.transformation)
srcTurkey.paint_uniform_color([0, 1, 1])
o3d.visualization.draw_geometries([srcTurkey, tar])

结果如下,可以说相当靠谱了。

在这里插入图片描述

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

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

相关文章

《Mahjong Bump》

Mahjong Bump 类型&#xff1a;Tile 三消 视角&#xff1a;2d 乐趣点&#xff1a;清空杂乱快感&#xff0c;轻松的三合一休闲 平台&#xff1a;GP 时间&#xff1a;2021 个人职责&#xff1a; 所有程序部分开发 上架 GooglePlay 相关工做 针对游戏数据做出分析&#xff0c;讨论…

Keil5快速使用

注册机链接如下 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;xim0 --来自百度网盘超级会员V4的分享 ① 打开Keil5软件 ② 在打开的对话框中复制自己软件的ID&#xff0c;然后粘贴到注册机对应的位置。 ③ 复制到注册机中后点击Generate&#xff08;注意&…

keil:syntax error near?这个报错怎么改?

我第一次学的编程语言是java&#xff0c;当时用eclipse开发环境&#xff0c;后面没学成&#xff0c;转成单片机。 刚开始学51单片机的时候&#xff0c;从强大的开发工具eclipse转变到像远古石器一样的Keil&#xff0c;还是挺不习惯的。 除了不会自动补全之类的基础功能以外&…

PostgreSQL FDW(外部表) 简介

1、FDW: 外部表 背景 提供外部数据源的透明访问机制。PostgreSQL fdw(Foreign Data Wrapper)是一种外部访问接口,可以在PG数据库中创建外部表,用户访问的时候与访问本地表的方法一样,支持增删改查。 而数据则是存储在外部,外部可以是一个远程的pg数据库或者其他数据库(…

Linux基础IO(操作系统层面理解文件)

目录 一、认识 open 函数 1.1 理解文件 1.2 open 函数 1.3 函数选项和宏 二、 open 函数的返回值 三、 fd 的本质 3.1 各部分内容及关系 3.2 如何确定进程对应文件 四、Linux 一切皆文件&#xff1f; 一、认识 open 函数 在C语言中学习文件操作时&#xff0c;我们学…

基于java+springboot+vue实现的超市在线销售系统(文末源码+Lw+ppt)23-356

摘 要 当今社会已经步入了科学技术进步和经济社会快速发展的新时期&#xff0c;国际信息和学术交流也不断加强&#xff0c;计算机技术对经济社会发展和人民生活改善的影响也日益突出&#xff0c;人类的生存和思考方式也产生了变化。传统超市在线销售采取了人工的管理方法&a…

MYSQL8.0安装、配置、启动、登入与卸载详细步骤总结

文章目录 一.下载安装包1.方式一.官网下载方式二.网盘下载 二.解压安装三.配置1.添加环境变量 三.验证安装与配置成功四.初始化MYSQL五.注册MySQL服务六.启动与停止MYSQL服务七.修改账户默认密码八.登入MySQL九.卸载MySQL补充&#xff1a;彻底粉碎删除Mysql 一.下载安装包 1.方…

ZC706+AD9361 运行 open WiFi

先到github上下载img&#xff0c;网页链接如下&#xff1a; https://github.com/open-sdr/openwifi?tabreadme-ov-file 用win32 Disk lmager 把文件写入到SD卡中&#xff0c;这一步操作会把SD卡重新清空&#xff0c;注意保存数据。这个软件我会放在最后的网盘链接中 打开linu…

宁波IATF16949质量管理认证体系如何认证?

&#x1f436;在当今竞争激烈的&#x1f338;汽车市场中&#xff0c;质量已成为企业&#x1f469;‍❤️‍&#x1f48b;‍&#x1f468;生存和发展的关键。IATF16949质量管理认证体系&#x1f34e;作为国际汽车行业认可的&#x1f33a;质量管理标准&#xff0c;已成为企业&…

IDEA设置代码自动提示不区分大小写

1. 打开设置 在 IntelliJ IDEA 中&#xff0c;点击顶部菜单栏的 File–>Settings&#xff08;或者使用快捷键 Ctrl Alt S&#xff09;。 2. 进入设置&#xff1a; 在弹出窗口左侧导航栏中选择 Editor --> General --> Code Completion&#xff0c;取消勾选 “Mat…

机器学习中的 K-Means算法及其优缺点(包含Python代码样例)

目录 一、简介 二、优缺点介绍 三、Python代码示例 四、总结 一、简介 K-Means算法是一种经典的无监督学习算法&#xff0c;用于将数据集中的样本分为 K 个不同的类别。K-均值聚类算法的工作原理如下&#xff1a; 随机选择 K 个中心点作为初始聚类中心。将每个样本点分配…

AI 成足球比赛「关键先生」:DeepMind 发布 TacticAI,战术布局实用性高达 90%

在刚刚结束的世界杯预选赛中&#xff0c;国足在天津主场以 4:1 的得分大胜新加坡&#xff0c;一扫上一场在领先优势下被对方逼平的阴霾&#xff0c;也迎来了球队 2024 年的首场胜利。目前&#xff0c;中国队暂居 C 组第 2 位&#xff0c;保住了晋级 18 强赛的希望。 享受胜利喜…

人工智能(pytorch)搭建模型25-基于pytorch搭建FPN特征金字塔网络的应用场景,模型结构介绍

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能(pytorch)搭建模型25-基于pytorch搭建FPN特征金字塔网络的应用场景&#xff0c;模型结构介绍。特征金字塔网络&#xff08;FPN&#xff09;是一种深度学习模型结构&#xff0c;主要应用于目标检测任务中&am…

Linux 注入依赖环境

文章目录 配置依赖程序安装 JDK安装 Tomcat安装 mysql 配置依赖程序 下面配置依赖程序都以CentOS为例。 安装 JDK 可以直接使用 yum(CentOS) 直接进行安装。 先搜索&#xff0c;确定软件包的完整名称。 yum list | grep jdk再进行安装 进行安装的时候一定要先确保处在“管理…

《计算机工程与应用》投稿经验2024

要按照官网格式写论文&#xff0c;这会节省很多时间。审稿费120元&#xff0c;本人计算机视觉方向&#xff0c;9页&#xff0c;没有打折&#xff0c;版面费5000&#xff0c;彩图和表格过多的原因。版权协议等论文录用之后再交即可&#xff0c;一审二审的时候不用交&#xff0c;…

Python-VBA编程500例-022(入门级)

最长AB子串(Longest AB Alternating Substring)(或称为最长XY出现次数相同的子字符串)这个问题看似是一个比较抽象的编程问题&#xff0c;但在实际应用场景中&#xff0c;它可以用来解决一系列涉及平衡性和重复模式的实际问题。常见应用场景有&#xff1a; 1、DNA或RNA序列分析…

浅谈交直流混合微电网能量管理系统关键技术研究综述

摘要&#xff1a;为了提升交直流混合微电网健康有效发展&#xff0c;提高直流互联微电网中分布式电源的能源使用效率&#xff0c;提升区域微电网稳定发展&#xff0c;对交直流混合微电网能量管理系统关键技术进行分析和研究很有必要。文章主要从交直流混合微电网能量管理系统架…

JAVA的sort用法详解(二维数组排序,List<>排序,lambada表达式,自定义类型排序)

目录 前言&#xff1a; 一维数组降序&#xff1a; 方法1.Comparator接口&#xff1a; 代码实现&#xff1a; 方法2.Collections.reverseOrder()&#xff1a; 代码实现&#xff1a; 二维数组排序&#xff1a; 代码如下&#xff1a; List<>排序&#xff1a; 代码…

C++ 之多态虚函数原理及应用

文章目录 多态基本概念和原理虚函数的基本原理和概念虚析构和纯虚析构多重继承中的虚函数小结 多态基本概念和原理 多态的基本概念 **多态是C面向对象三大特性之一** 多态的定义 多态是一种面向对象编程概念&#xff0c;指同一个行为&#xff08;方法&#xff09;在不同的对象上…

Elastic 8.13:Elastic AI 助手中 Amazon Bedrock 的正式发布 (GA) 用于可观测性

作者&#xff1a;来自 Elastic Brian Bergholm 今天&#xff0c;我们很高兴地宣布 Elastic 8.13 的正式发布。 有什么新特性&#xff1f; 8.13 版本的三个最重要的组件包括 Elastic AI 助手中 Amazon Bedrock 支持的正式发布 (general availability - GA)&#xff0c;新的向量…