(8)点云数据处理学习——ICP registration(迭代最近点)

news2024/11/17 8:26:14

1、主要参考

(1)官方介绍地址

ICP registration — Open3D 0.16.0 documentation

2、介绍

2.1 原理

(1)关于ICP registration

本教程演示ICP(迭代最近点)配准算法。多年来,它一直是研究和工业中几何配准的支柱。输入是两个点云和一个初始转换,该转换大致将源点云与目标点云对齐。输出是一个精细化的转换,它将两个点云紧密对齐。一个助手函数draw_registration_result可视化注册过程中的对齐情况。在本教程中,我们展示了两种ICP变体,点到点ICP和点到面ICP [Rusinkiewicz2001]。

2.2 辅助可视化函数

(2)采用的辅助可视化函数

下面的函数可视化了一个目标点云和一个经过对齐转换的源点云。目标点云和源点云分别绘以青色和黄色。两点云重叠越紧密,对准效果越好。

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])

 注意:由于函数transform和paint_uniform_color改变了点云,我们调用copy.deepcopy(深度复制,即重新拷贝一份全新的对象)来复制和保护原始的点云。

2.3 输入

下面的代码从两个文件读取一个源点云和一个目标点云。给出了一个粗略的变换。

注意:初始对准通常采用全局配准算法。有关示例,请参见全局注册 Global registration例子。

2.3 .1 两个原始输入

(1)先看看两个原始点云的分别

import open3d as o3d
import numpy as np
from copy import deepcopy

#(一)先简单看看
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])

o3d.visualization.draw_geometries([source,target])

(2)可以看到两个模型一开始没有对准,可以理解成在两个角度采集的

2.3.2两个输入粗略配准

(1)下面是 

import open3d as o3d
import numpy as np
from copy import deepcopy

def draw_registration_result(source, target, transformation):
    # source_temp = copy.deepcopy(source)
    # target_temp = copy.deepcopy(target)
    source_temp = deepcopy(source)
    target_temp = 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])


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)

(2)配准后的两种颜色,对应两个输入,看看是真的粗略配准了

 2.4 初始化注册函数evaluate_registration

(1)说明

evaluate_registration函数计算两个主要指标:
fitness, 适应度,衡量重叠区域(内部对应的# /目标点的#)。越高越好
inlier_rmse,它计算所有内部(inlier)匹配的RMSE。越低越好

(2)代码测试一下

import open3d as o3d
import numpy as np
from copy import deepcopy

# #(一)先简单看看
# 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])

# o3d.visualization.draw_geometries([source,target])


#(二)粗略配准
def draw_registration_result(source, target, transformation):
    # source_temp = copy.deepcopy(source)
    # target_temp = copy.deepcopy(target)
    source_temp = deepcopy(source)
    target_temp = 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])


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)

print("Initial alignment")
evaluation = o3d.pipelines.registration.evaluate_registration(
    source, target, threshold, trans_init)
print(evaluation)

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

3点对点ICP(Point-to-point ICP )

3.1原理

通常情况下,ICP算法迭代两个步骤:
(1)从目标点云P中找对应集K={(p,q)},用当前变换矩阵T变换源点云Q。
(2)通过对应集合K上定义的,最小化目标函数E(T),来更新变换矩阵T。

Different variants of ICP use different objective functions E(T)E(T) [BeslAndMcKay1992] [ChenAndMedioni1992] [Park2017].

我们首先展示了使用目标的点对点ICP算法[BeslAndMcKay1992]

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

 3.2 代码测试

(1)测试代码

import open3d as o3d
import numpy as np
from copy import deepcopy

# #(一)先简单看看
# 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])

# o3d.visualization.draw_geometries([source,target])


#(二)粗略配准
def draw_registration_result(source, target, transformation):
    # source_temp = copy.deepcopy(source)
    # target_temp = copy.deepcopy(target)
    source_temp = deepcopy(source)
    target_temp = 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])


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)

print("Initial alignment")
evaluation = o3d.pipelines.registration.evaluate_registration(
    source, target, threshold, trans_init)
print(evaluation)

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)

(2)展示的结果

 (3)改进

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

(4)改进的参数设置

 o3d.pipelines.registration.ICPConvergenceCriteria(max_iteration=2000)

(5)测试代码

import open3d as o3d
import numpy as np
from copy import deepcopy

# #(一)先简单看看
# 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])

# o3d.visualization.draw_geometries([source,target])


#(二)粗略配准
def draw_registration_result(source, target, transformation):
    # source_temp = copy.deepcopy(source)
    # target_temp = copy.deepcopy(target)
    source_temp = deepcopy(source)
    target_temp = 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])


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)

print("Initial alignment")
evaluation = o3d.pipelines.registration.evaluate_registration(
    source, target, threshold, trans_init)
print(evaluation)

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)

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)

果然,2000步迭代后,果然匹配的漂亮了很多

 计算得到的变换矩阵也更精确了

 4、点对面ICP(Point-to-plane ICP )

4.1原理

点到平面的ICP算法[ChenAndMedioni1992]使用了不同的目标函数

 

其中np为点p的法线。[Rusinkiewicz2001]证明了点到面ICP算法比点到点ICP算法具有更快的收敛速度

registration_icp调用了使用不同的参数TransformationEstimationPointToPlane。在内部,这个类实现函数来计算残差和点到平面的ICP目标的雅可比矩阵。

 4.2 测试代码

(1)代码

import open3d as o3d
import numpy as np
from copy import deepcopy

# #(一)先简单看看
# 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])

# o3d.visualization.draw_geometries([source,target])


#(二)粗略配准
def draw_registration_result(source, target, transformation):
    # source_temp = copy.deepcopy(source)
    # target_temp = copy.deepcopy(target)
    source_temp = deepcopy(source)
    target_temp = 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])


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)

# print("Initial alignment")
# evaluation = o3d.pipelines.registration.evaluate_registration(
#     source, target, threshold, trans_init)
# print(evaluation)

#(三)点对点配准
# 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)

# 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)



#(四)平面配准
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)

(2)测试结果图

点到平面的ICP在30次迭代中达到紧密对齐(适合度评分为0.620972,inlier_rmse评分为0.006581)。效果还很不错 

Apply point-to-plane ICP
RegistrationResult with fitness=6.209722e-01, inlier_rmse=6.581453e-03, and correspondence_set size of 123471

 注意:点到平面的ICP算法使用点法线。在本教程中,我们从文件加载法线。如果没有给出法线,可以用顶点法线估计来计算。

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

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

相关文章

股票接口怎么解析股票历史数据?

最近有很多投资者在研究股票接口怎么解析股票历史数据,然后执行自动交易等方面对开发股票数据接口的深入思考。其实在小编看来,这就需要先获取股票的每日数据,那么就会使用Python来解析股票历史数据,下面小编就简要介绍使用Python…

Java8-Stream流详细教程

前言 1、什么是Stream 前面我们讲了Lambda表达式与Optional类,下面我们将会使用这两个新特性,特别是Lambda。 Stream 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列 集合讲的是数据,Stream讲的是计算! 注…

Java 守护线程

✨✨hello,愿意点进来的小伙伴们,你们好呐! 🐻🐻系列专栏:【JavaEE初阶】 🐲🐲本篇内容:详解守护线程 🐯🐯作者简介:一名现大二的三非编程小白&am…

什么是云计算?什么是边缘计算?为什么需要云边协同?

一、云计算的发展有哪些弊端? **云计算(cloud computing)**是分布式计算的一种,指的是通过网络“云”将巨大的数据计算处理程序分解成无数个小程序,然后,通过多部服务器组成的系统进行处理和分析这些小程序…

Android 启动流程梳理

前言 什么是Android启动流程呢?其实指的就是我们Android系统从按下电源到显示界面的整个过程。 当我们把手机充好电,按下电源,手机会弹出相应启动界面,在等了一段时间之后,会弹出我们熟悉的主界面,这其实就…

开源数据备份工具 Duplicati

使用 Duplicati 腾讯云 COS,完美备份我的服务器数据。 文件备份需求 我有两台腾讯云的服务器,一台部署了博客,一台部署了一些个人项目,虽说云服务器很稳定,基本不会发生丢失数据的问题,但我个人之前经历过…

ThreeJs学习

1 基本使用 //1、创建场景 const scene new THREE.Scene() //2、创建网格模型 const geometry new THREE.BoxGeometry(100,100,100) const matrial new THREE.MeshLambertMaterial({color: #0000ff }) const mesh new THREE.Mesh(geometry,matrial) scene.add(mesh) //3、…

Redis之String类型和Hash类型的介绍和案例应用

一. String类型基础 1.类型介绍 典型的Key-Value集合,如果要存实体,需要序列化成字符串,获取的时候需要反序列化一下。 2. 指令Api说明 ​ 编辑3.常用Api说明 (1).StringSet:写入数据,如果数据已经存在,则覆盖;可以一次性存入1…

B2B电子商务策略[在2022年发展您的业务]

常规的电子商务商店向消费者(B2C 或企业对消费者)销售产品。B2B(企业对企业)电子商务不同于常规电子商务,因为 B2B电子商务的商业模式是让一家企业在线向另一家公司销售产品。 您可能会想:如何向企业销售比…

Windows OpenGL 图像色调

目录 一.OpenGL 图像色调调节 1.原始图片2.效果演示 二.OpenGL 图像色调调节源码下载三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 特效 零基础 OpenGL…

Ubuntu 20.04 server永久关闭swap

方法一 编辑/etc/fstab ,sudo vim /etc/fstab,找到如下行 找到/dev/disk/by-uuid/28b306c5-92e4-4180-966d-cdedfbce3a4d /boot ext4 defaults 0 1 修改为如下图,并(/swap.img none swap sw 0 0) 将如下行注释&#…

Yolo算法检测之Anchor Boxes原理详解

刚开始yolo系列的目标检测算法,在一个网格中只能检测一个对象,但是我们在实验中发现,一个网格中很多时候存在不仅一个目标,可能存在多个目标,类似如下图所示,下面中间的网格中就存在人和车辆两个目标的中心…

嵌入式开发学习之--Git管理代码

本章主要介绍一下代码管理,在最后有常用的git指令,可以档资料收藏一下。 文章目录前言一、Github是什么二、Github的简单应用1.新建库 git init2. 添加文件 git add .2. 提交到本地仓库 git commit -m "注释"3. 创建分支 Git checkout -b [分支…

IPython工作原理

IPython工作原理 文章目录IPython是什么?IPython工作原理IPython控制台IPython内核实现一个简单的包装内核代码在IPython内核中的执行流程IPython是什么? Python最有用的功能之一就是它的交互式解释器。交互式编程允许我们非常快速地执行代码片段、测试…

[附源码]计算机毕业设计在线教育系统Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

详解 Intersection Observer API ( 交叉观察器 )

文章目录一、介绍二、兼容性三、内置方法/属性四、使用五、相关链接一、介绍 Intersection Observer API 提供了一种方法可以监听目标元素是否展示到视口(viewport),常见的需求场景: 图片懒加载滚动动画… 上述的需求&#xff…

基于PHP+MySQL医院门诊缴费系统的设计与实现

本医院门诊缴费系统可以说是一个综合性的医院门诊缴费系统,这它包含了挂号管理,医生信息管理,药品信息管理,患者信息管理,住院信息挂了,收费信息管理等多种功能,因而具有一定的实用性。本站是一个B/S模式系统,开发采用了目前流行的PHP技术。系统界面友好,操作简单,比较实用。 本…

浅谈小程序开源业务架构建设之路

一、业务介绍 1.1 小程序开源整体介绍 百度从做智能小程序的第一天开始就打造真正开源开放的生态,我们的愿景是:定义移动时代最佳体验,建设智能小程序行业标准,打破孤岛,共建开源、开放、繁荣的小程序行业生态。百度…

element-ui实现一个动态布局的对话框

前言:在工作中有各种各样的对话框,最多就是填写信息这些的,一般这样的内容都是el-input输入框,el-select选择框等等之内的,这时我们就可以封装成一个组件,想要什么内容就传一个json配置,像其他组…

适合Python初学者阅读的Github开源代码

程序员宝藏库:https://gitee.com/sharetech_lee/CS-Books-Store 你想要的,这里都有! Python作为一门热门的编程语言,在Github上想要找Python项目可以说是「多如牛毛」。 无论是Star数量还是项目数量,都稳居前3名。 项…