点云中ICP算法的详解
ICP(Iterative Closest Point)算法是一种用于刚性点云配准的经典算法。其核心思想是通过迭代地寻找两个点云之间的最近点对,并计算最优的刚性变换(包括旋转和平移),使得源点云在目标点云的坐标系下对齐。ICP算法广泛应用于计算机视觉、机器人导航、3D建模等领域。
一、发展历史
ICP算法最早由 Besl 和 McKay 于1992年在论文《A Method for Registration of 3-D Shapes》中提出。几乎在同一时间,Chen 和 Medioni 也独立地提出了类似的算法。自提出以来,ICP算法经历了多次改进和扩展,以提高其收敛速度、精度和鲁棒性。以下是ICP算法的发展历程:
-
基础ICP算法(1992):最初的ICP算法采用点到点的距离度量,通过迭代最近点匹配和最小化均方误差实现点云配准。
-
改进的ICP变体:
- 点到平面ICP:考虑点与对应平面的距离,提高了在具有平面特征的场景中的收敛速度。
- 点到曲面ICP:用于处理更复杂的曲面模型。
- 加权ICP:为不同的点对赋予不同的权重,以提高配准精度。
-
全局优化和鲁棒性增强:
- 采用k-d树加速最近邻搜索:提高算法的效率。
- 引入鲁棒估计器:如RANSAC、M-estimators,减少异常值对配准的影响。
- 多尺度ICP:通过从粗到精的多尺度策略,提高算法的全局收敛性。
二、数学原理
1. 问题定义
给定两个点云:源点云 ( $ P = { \mathbf{p}_i } $) 和目标点云 ( $Q = { \mathbf{q}_j } $),目标是找到一个刚性变换(旋转矩阵 ( $ \mathbf{R} $ ) 和平移向量 ( $\mathbf{t} $ )),使得变换后的源点云与目标点云尽可能地对齐。
2. 算法流程
步骤1:初始化
- 设置初始变换矩阵 ( $\mathbf{T}_0 $ )(通常为单位矩阵)。
步骤2:迭代过程
对于每次迭代 ( $ k $):
-
最近点匹配
- 对于源点云中的每个点 ( $ \mathbf{p}_i $),在目标点云 ( $Q $ ) 中找到最近邻点 ( $ \mathbf{q}_j $ )。
- 建立对应点对集合 ( $C = { (\mathbf{p}_i, \mathbf{q}_j) } $ )。
-
变换估计
-
通过最小化以下目标函数,计算最优的刚性变换 ( $(\mathbf{R}, \mathbf{t}) $ ):
$[E(\mathbf{R}, \mathbf{t}) = \sum_{(\mathbf{p}_i, \mathbf{q}_i) \in C} | \mathbf{q}_i - (\mathbf{R}\mathbf{p}_i + \mathbf{t}) |^2
] $ -
该问题等价于 Procrustes 分析,有解析解。
-
-
应用变换
-
更新源点云:
$[
\mathbf{p}_i \leftarrow \mathbf{R}\mathbf{p}_i + \mathbf{t}
] $
-
-
检查收敛
- 如果变换矩阵的变化量或误差函数的变化量小于预设的阈值,或者达到最大迭代次数,则停止迭代。
步骤3:输出结果
- 最终的变换矩阵 ( $ \mathbf{T} = (\mathbf{R}, \mathbf{t}) $) 将源点云配准到目标点云。
3. 数学推导
最小化目标函数
目标是找到 ( $ \mathbf{R} $) 和 ( $\mathbf{t} $),使得:
$[
E(\mathbf{R}, \mathbf{t}) = \sum_{i} | \mathbf{q}_i - (\mathbf{R}\mathbf{p}_i + \mathbf{t}) |^2
] $
计算质心
-
计算源点云和目标点云对应点对的质心:
$[
\mathbf{\bar{p}} = \frac{1}{N} \sum_{i} \mathbf{p}i, \quad \mathbf{\bar{q}} = \frac{1}{N} \sum{i} \mathbf{q}_i
] $
去中心化点云
-
去除质心影响:
$[
\mathbf{\tilde{p}}_i = \mathbf{p}_i - \mathbf{\bar{p}}, \quad \mathbf{\tilde{q}}_i = \mathbf{q}_i - \mathbf{\bar{q}}
] $
计算协方差矩阵
-
计算协方差矩阵:
$[
\mathbf{H} = \sum_{i} \mathbf{\tilde{p}}_i \mathbf{\tilde{q}}_i^\top
] $
奇异值分解
-
对协方差矩阵进行奇异值分解:
$[
\mathbf{H} = \mathbf{U} \mathbf{\Sigma} \mathbf{V}^\top
] $
计算旋转矩阵
-
计算旋转矩阵 ( $ \mathbf{R} $):
$[
\mathbf{R} = \mathbf{V} \mathbf{U}^\top
] $- 为了确保 ( $ \mathbf{R} $) 是一个合法的旋转矩阵,需要处理 ( $ \det(\mathbf{R}) = -1 $ ) 的情况。
计算平移向量
-
计算平移向量 ( t \mathbf{t} t ):
[ t = q ˉ − R p ˉ ] [ \mathbf{t} = \mathbf{\bar{q}} - \mathbf{R} \mathbf{\bar{p}} ] [t=qˉ−Rpˉ]
三、应用领域与场景
1. 3D建模与重建
- 多视角扫描数据融合:在获取物体或场景的多视角点云数据后,使用ICP算法对不同视角的数据进行配准,生成完整的三维模型。
2. 机器人导航与定位
- SLAM(Simultaneous Localization and Mapping):在未知环境中,机器人通过传感器获取环境的点云数据,利用ICP算法实现自身定位和地图构建。
3. 医学影像分析
- 三维医学图像配准:将不同时间、不同模态的医学图像进行配准,辅助诊断和手术规划。
4. 计算机视觉与图形学
- 物体识别与跟踪:通过将实时获取的点云与已知模型进行配准,实现物体的识别和姿态估计。
5. 质量检测与逆向工程
- 制造业中的误差分析:将实际产品的扫描点云与设计模型进行配准,分析制造误差和变形。
四、优缺点
优点
-
简单易实现:ICP算法思想直观,步骤简单,易于编码实现。
-
广泛适用性:适用于刚性物体的配准,且对不同类型的点云数据都能使用。
-
渐进式优化:通过迭代逐步逼近最优解,能够在一定程度上克服初始误差。
缺点
-
依赖初始位置:ICP算法对初始变换的依赖性较强,初始位置差异过大会导致算法收敛到局部最优解甚至不收敛。
-
容易陷入局部最优:由于采用最近邻匹配,可能在复杂场景下陷入局部最优,影响配准精度。
-
计算量较大:在大规模点云数据下,最近邻搜索和迭代过程计算量大,耗时长。
-
对噪声和异常值敏感:噪声点和异常值会影响最近邻匹配的准确性,导致配准误差。
五、算法实例
下面提供一个使用Python和Open3D库实现ICP算法的示例代码。

复制一份数据并错开,对两份数据进行ICP配准:

示例代码:
# ICP is only valid when two point cloud is coarse registration basically.
import numpy as np
import open3d as o3d# 读取点云数据
def read_txt_pointcloud(file_path):# 使用 numpy 加载数据,假设每行是 x y z,用空格或制表符分隔points = np.loadtxt(file_path)point_cloud = o3d.geometry.PointCloud()point_cloud.points = o3d.utility.Vector3dVector(points)return point_cloud# 执行 ICP 算法
def icp_registration(source_cloud, target_cloud, threshold=1.0):# 初始变换矩阵(单位矩阵)trans_init = np.identity(4)# 采用 Point-to-Point ICPreg_p2p = o3d.pipelines.registration.registration_icp(source_cloud, target_cloud, threshold, trans_init,o3d.pipelines.registration.TransformationEstimationPointToPoint())return reg_p2p# 可视化点云
def visualize_registration(source_cloud, target_cloud, transformation):# 变换源点云source_temp = source_cloud.transform(transformation)# 给点云上色source_temp.paint_uniform_color([1, 0, 0]) # 红色target_cloud.paint_uniform_color([0, 1, 0]) # 绿色# 显示o3d.visualization.draw_geometries([source_temp, target_cloud],window_name='ICP Point Cloud Registration',width=800, height=600)def main():# 读取源点云和目标点云source_cloud = read_txt_pointcloud('screen.txt') # 源点云target_cloud = read_txt_pointcloud('desk.txt') # 目标点云(BIM 模型)# 下采样(可选):加速计算,减少噪声voxel_size = 0.05 # 根据数据尺度调整source_down = source_cloud.voxel_down_sample(voxel_size)target_down = target_cloud.voxel_down_sample(voxel_size)# 计算法线(如果需要使用 Point-to-Plane ICP)source_down.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))target_down.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))# 配准阈值(根据数据尺度调整)threshold = 1000# 执行 ICP 配准reg_result = icp_registration(source_down, target_down, threshold)# 打印结果print("ICP 配准完成")print("匹配度 (fitness):", reg_result.fitness)print("均方根误差 (inlier_rmse):", reg_result.inlier_rmse)print("变换矩阵:")print(reg_result.transformation)# 可视化配准结果visualize_registration(source_cloud, target_cloud, reg_result.transformation)if __name__ == "__main__":main()
结果:


六、总结
ICP算法作为点云配准的基石算法,具有重要的理论意义和实用价值。通过不断的改进和优化,ICP算法在处理复杂的点云配准任务中依然发挥着重要作用。对于初学者,理解ICP的基本原理和实现方法,是深入学习点云处理和三维计算机视觉的关键一步。
相关文章:
点云中ICP算法的详解
ICP(Iterative Closest Point)算法是一种用于刚性点云配准的经典算法。其核心思想是通过迭代地寻找两个点云之间的最近点对,并计算最优的刚性变换(包括旋转和平移),使得源点云在目标点云的坐标系下对齐。IC…...
抽象类Abstart Class
抽象类其实就是一种不完全的设计图 必须用abstract修饰 模板方法:建议使用final修饰,不能被重写。...
Redis:通用命令 数据类型
Redis:通用命令 & 数据类型 通用命令SETGETKEYSEXISTSDELEXPIRETTLTYPEFLUSHALL 数据类型 Redis的客户端提供了很多命令用于操控Redis,在Redis中,key的类型都是字符串,而value有多种类型,每种类型都有自己的操作命…...
【Python高级编程】探索Python库:创建引人入胜的交互界面
1.制作交互界面常用到的库 在 Python 中,有多个库可以用于创建交互界面(GUI)。 以下是一些常用的 Python GUI 库: Tkinter: Python 的标准 GUI 库,通常随 Python 一起安装。简单易用,适合快速开发小型应用…...
OpenCV Canny()函数
OpenCV Canny()函数被用来检测图像物体的边缘。其算法原理如下: 高斯滤波:使用高斯滤波器平滑图像以减少噪声。高斯滤波器是一种线性滤波器,可以消除图像中的高频噪声,同时保留边缘信息。计算梯度强度和方向:使用Sobe…...
Java基础(3)
基本数据类型 Java 中的几种基本数据类型了解么? Java 中有 8 种基本数据类型,分别为: 6 种数字类型: 4 种整数型:byte、short、int、long2 种浮点型:float、double1 种字符类型:char1 种布尔…...
【C语言】VS调试技巧
文章目录 什么是bug什么是调试(debug)debug和releaseVS调试快捷键监视和内存观察编程常见错误归类 什么是bug bug本意是“昆虫”或“虫子”,现在一般是指在电脑系统或程序中,隐藏着的一些未被发现的缺陷或问题,简称程…...
【华为HCIP实战课程七】OSPF邻居关系排错MTU问题,网络工程师
一、MTU MUT默认1500,最大传输单元,一致性检测 [R3-GigabitEthernet0/0/1]mtu 1503//更改R3的MTU为1503 查看R3和SW1之间的OSPF邻居关系正常: 默认华为设备没有开启MTU一致性检测! [R3-GigabitEthernet0/0/1]ospf mtu-enable //手动开启MTU检测 [SW1-Vlanif30]ospf mtu…...
速盾:休闲类游戏如何选择高防cdn?
休闲类游戏的流行度日益增长,越来越多的玩家在业余时间里选择放松自己,享受游戏带来的乐趣。然而,在休闲类游戏中,网络延迟和游戏载入速度的问题常常会影响到玩家的游戏体验。为了解决这些问题,选择一个高防CDN&#x…...
电脑插上U盘不显示怎么回事?怎么解决?
平时使用电脑的时候经常会使用U盘来传输数据或是备份文件,有时候会遇到一个令头疼的问题,比如,将U盘插入电脑的USB口后,设备却显示不出来。电脑上插入U盘后却不显示会影响我们的正常工作。接下来,我们一起分析一下故障…...
Python 如何使用 SQLAlchemy 进行复杂查询
Python 如何使用 SQLAlchemy 进行复杂查询 一、引言 SQLAlchemy 是 Python 生态系统中非常流行的数据库处理库,它提供了一种高效、简洁的方式与数据库进行交互。SQLAlchemy 是一个功能强大的数据库工具,支持结构化查询语言(SQL)…...
nginx主配置文件
Nginx的主配置文件nginx.conf,一般定义了Nginx的基本设置和全局配置。下面是对这个配置文件的详细解释: 文件结构 #user nobody; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log …...
使用数据库:
数据库: 1.为何需要数据库? 存储数据方法 第一种:用大脑记住数据, 第二种:写纸上, 第三种:写在计算机的内存中, 第四种:写出磁盘文件 2.数据库能做什么࿱…...
python list, tuple dict,set的区别 以及**kwargs 的基本用法
在python中, list, tuple, dict, set有什么区别, 主要应用在什么样的场景? 定义: list:链表,有序的项目, 通过索引进行查找,使用方括号”[]”; tuple:元组,元组将多样的对象集合到一起,不能修改,通过索引进行查找, 使用括号”()”; dict:字典,字典是一组键(key)和值(value…...
实用生活英语口语学习成人零基础入门柯桥专业外语培训
“秋裤”的英语表达 首先,秋裤肯定不是autumn pants,chill cool就更离谱了! 最地道的美语说法一定会用到“thermal”这个单词: ▼ “thermal”的意思是“热的、保温的”,由此延伸出“秋裤、保暖内衣”的表达ÿ…...
FLINK SQL数据类型
Flink SQL支持非常完善的数据类型,以满足不同的数据处理需求。以下是对Flink SQL数据类型的详细归纳: 一、原子数据类型 字符串类型 CHAR、CHAR(n):定长字符串,n代表字符的定长,取值范围为[1, 2147483647]。如果不指…...
汇编语言教程:打造你的第一款汇编语言小游戏 汇编语言教程攻略
目录 游戏详细简介 完整代码示例(不少于70行) 如何自学汇编语言游戏开发攻略及功能 游戏详细简介 游戏名称:“太空探险” 游戏简介:这是一款基于x86汇编语言开发的简单2D游戏。在游戏中,玩家扮演一名宇航员&#…...
白色简洁大方公司企业网站源码 WordPress主题2款
WordPress白色简洁大方公司企业网站主题2款 白色整洁风格wordpress主题是一款比较新颖的国际设计范风格 简洁而大方的 WordPress 主题,适合个人博客、企业和工作室用。 完美支持下拉菜单的wordpress企业主题。 wordpress简白企业模板是一款适合企业站以及工作室…...
MinIO分片上传超大文件(纯服务端)
目录 一、MinIO快速搭建1.1、拉取docker镜像1.2、启动docker容器 二、分片上传大文件到MinIO2.1、添加依赖2.2、实现MinioClient2.3、实现分片上传2.3.0、初始化MinioClient2.3.1、准备分片上传2.3.2、分片并上传2.3.2.1、设置分片大小2.3.2.2、分片 2.3.3、分片合并 三、测试3…...
leetcode链表(一)-移除链表元素
题目 t. - 力扣(LeetCode) 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val val 的节点,并返回 新的头节点 。 例1 输入:head [1,2,6,3,4,5,6], val 6 输出:[1,2,3,4,5]…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
