PCL 使用ICP点云拼接

一、简介

ICP算法详解——我见过最清晰的解释_负壹的博客-CSDN博客

两个点集,source和target,target不变,source经过旋转(Rotation)和平移(Translation)甚至加上尺度(Scale)变换,使得变换后的source点集尽量和target点集重合,这个变换的过程就叫点集配准。

  但是ICP的使用方法精度比较差,假如将一个原始点云在X方向上移动一定的距离(或者对原始点云进行降采样),然后进行配准分数也会有很大的差异,并且得到的旋转平移矩阵也差异比较大。

二、基本原理

假设用Qi,i=1,2,3,⋯Qi,i=1,2,3,⋯表示第一个点集,Pi,i=1,2,3,⋯Pi,i=1,2,3,⋯表示第二个点集。

ICP配准过程:


1.计算原始点云P中的每个点对于在匹配点云Q的最近点

2、 计算对应点的平均最小距离,计算R T 矩阵

3、对原始点云P进行RT转换得到P2

4、计算P2与Q之间的平均最小距离,继续迭代。

提示:这里的目标函数的要求,也可以是迭代次数
 

 20130518113251019 (752×606)

 

识别步骤:

1、分别找到两个点云数集中的兴趣点或者关键点

2、计算特征描述符

3、分别计算p1(x,y,z) p2(x,y,z)计算特征和位置之间的相关性,通过迭代测试来计算

4、计算之前一定要去除掉点云上面的噪声,ICP是暴力迭代的方法,计算内容是全部点云中的点

5、从特征点总找到一个匹配最好的特征计算出旋转平移矩阵


迭代最近点 Iterative Closest Point (ICP)

PCL学习笔记二:Registration (ICP算法)_rabbif的博客-CSDN博客

 ICP采用最小二乘法的最优配准方法,此算法重复进行点之间的对应关系,计算出一个刚性变换,知道满足收敛的精度。

	// ICP配准
	pcl::IterativeClosestPoint<pcl::PointXYZ,pcl::PointXYZ>icp; // 创建ICP对象  用来ICP配准
	//icp.setMaxCorrespondenceDistance(0.1);  // 
	icp.setTransformationEpsilon(0.1);  // 前一个变换矩阵和当前变换矩阵的差异小于阈值时,就认为已经收敛了,是一条收敛条件
	icp.setEuclideanFitnessEpsilon(0.01);  // 还有一条收敛条件是均方误差和小于阈值, 停止迭代
	icp.setMaximumIterations(10);  // 最大迭代次数
	icp.setInputCloud(cloud_tr);
	icp.setInputTarget(cloud_in);  // 输入目标点云
	icp.align(*cloud_icp);  //配准后的点云

transformation estimation是基于SVD的, SVD是奇异值分解 

基本过程


对于目标点云中的每个点,匹配参考点云(或选定集合)中的最近点。
求得使上述对应点对计算均方根(root mean square,RMS)最小的刚体变换,求得平移参数和旋转参数。
使用获得的转换矩阵来转换目标点云。
迭代(重新关联点),直到满足终止迭代的条件(迭代次数或误差小于阈值)。这里的误差最小,可以是相邻两次均方根差的绝对值小于某一限差。
 

三、代码:

添加头文件

#define BOOST_TYPEOF_EMULATION  //要加在#include <pcl/registration/icp.h>前
#include <pcl/registration/icp.h>   //ICP配准类相关头文件

 

	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);// 原始点云
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_icp(new pcl::PointCloud<pcl::PointXYZ>);  // ICP 输出点云
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_tr(new pcl::PointCloud<pcl::PointXYZ>);   // 匹配点云
	string strfilepath = "C:\\Users\\Albert\\Desktop\\Binary.pcd";
	if (-1 == pcl::io::loadPCDFile(strfilepath, *cloud_in)) {
		cout << "error input!" << endl;
		return -1;
	}
	cout << cloud_in->points.size() << endl;


	string strfilepath2 = "C:\\Users\\Albert\\Desktop\\Binary2.pcd";
	//if (-1 == pcl::io::loadPCDFile(strfilepath2, *cloud_icp)) {
	//	cout << "error input!" << endl;
	//	return -1;
	//}

	pcl::PointXYZ point;
	for (int i = 0; i < cloud_in->size();i++)
	{
		 point.x= cloud_in->points[i].x + 10;
		 point.y = cloud_in->points[i].y;
		 point.z = cloud_in->points[i].z;
		 cloud_icp->push_back(point);
	}
	cout << cloud_icp->points.size() << endl;

	pcl::io::savePCDFileBinaryCompressed(strfilepath2,*cloud_icp);

	int  iterations = 3;// 默认的ICP的迭代次数
	*cloud_tr = *cloud_icp;

	// ICP配准
	pcl::IterativeClosestPoint<pcl::PointXYZ,pcl::PointXYZ>icp; // 创建ICP对象  用来ICP配准
	//icp.setMaxCorrespondenceDistance(0.1);  // 
	icp.setTransformationEpsilon(0.1);  // 前一个变换矩阵和当前变换矩阵的差异小于阈值时,就认为已经收敛了,是一条收敛条件
	icp.setEuclideanFitnessEpsilon(0.01);  // 还有一条收敛条件是均方误差和小于阈值, 停止迭代
	icp.setMaximumIterations(10);  // 最大迭代次数
	icp.setInputCloud(cloud_tr);
	icp.setInputTarget(cloud_in);  // 输入目标点云
	icp.align(*cloud_icp);  //配准后的点云




	
	if (icp.hasConverged())//icp.hasConverged ()=1(true)输出变换矩阵的适合性评估
	{
		std::cout << "\nICP has converged, score is " << icp.getFitnessScore() << std::endl;
	}
	else
	{
		PCL_ERROR("\nICP has not converged.\n");
		return (-1);
	}

	cout<<icp.getFinalTransformation();

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大聪明教你学Java | 深入浅出聊 SpringBoot 中的 starter 机制

前言 &#x1f34a;作者简介&#xff1a; 不肯过江东丶&#xff0c;一个来自二线城市的程序员&#xff0c;致力于用“猥琐”办法解决繁琐问题&#xff0c;让复杂的问题变得通俗易懂。 &#x1f34a;支持作者&#xff1a; 点赞&#x1f44d;、关注&#x1f496;、留言&#x1f4…

网络安全横向移动指南

在网络安全方面&#xff0c;了解威胁参与者的工具、技术和思维过程非常重要。 一旦对手获得对网络的初始访问权限&#xff0c;横向移动允许他们通过破坏目标组织网络中的其他主机来扩展访问权限并保持持久性。 威胁行为者可以收集有关公司用户活动和凭据、重要数据位置的信息…

Spark - 继承 FileOutputFormat 实现向 HDFS 地址追加文件

目录 一.引言 二.源码浅析 1.RDD.saveAsTextFile 2.TextOutputFormat 3.FileOutputFormat 三.源码修改 1.修改文件生成逻辑 - getRecordWriter 2.允许目录存在 - checkoutputSpecs 3.全部代码 - TextOutputFormatV2 四.追加存储代码实战 五.总结 一.引言 Output d…

关于STM32用DMA传输UART空闲中断中接收的数据时无法接收数据问题以及解决办法

一、stm32 cube ide 配置 1、DMA串口接收数据的ide配置如下图所示 串口1相关的设置及printf函数的使用&#xff0c;这里没放&#xff0c;建议先实现串口打印功能 2、相关的知识点 普通模式和循环模式的区别在于&#xff0c;普通模式下&#xff0c;DMA只会接收一次数据&#x…

微前端(无界)

前言&#xff1a;微前端已经是一个非常成熟的领域了&#xff0c;但开发者不管采用哪个现有方案&#xff0c;在适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等用户核心诉求都或存在问题&#xff0c;或无法提供支持。本…

DS18B20温度传感器简介和1-Wire驱动程序

目录DS18B20简介DS18B20的两种供电方式64位ROM温度传感器1-Wire Bus简介DS18B20通信时序初始化ROM相关命令(后续包含任何数据交换的操作)功能相关命令(后续包含任何数据交换的操作)单个DS18B20读取温度值驱动多个DS18B20读取温度值驱动DS18B20简介 DS18B20数字温度计提供9位到…

学习系统编程No.7【进程替换】

引言&#xff1a; 北京时间&#xff1a;2023/3/21/7:17&#xff0c;这篇博客本来昨天晚上就能开始写的&#xff0c;但是由于笔试强训的原因&#xff0c;导致时间用在了做题上&#xff0c;通过快2个小时的垂死挣扎&#xff0c;我充分意识到了自己做题能力的缺陷和运用新知识的缺…

致远OA敏感信息泄露漏洞合集(含批量检测POC)

文章目录前言敏感信息泄露A6 status.jsp 信息泄露漏洞漏洞描述漏洞影响网络测绘漏洞复现POC 批量检测getSessionList.jsp Session泄漏漏洞漏洞描述网络测绘批量检测POC致远OA 帆软组件 ReportServer 目录遍历漏洞漏洞描述漏洞影响网络测绘POC(批量检测)A6 createMysql.jsp 数据…

Java stream性能比较

环境 Ubuntu 22.04IntelliJ IDEA 2022.1.3JDK 17CPU&#xff1a;8核 ➜ ~ cat /proc/cpuinfo | egrep -ie physical id|cpu cores physical id : 0 cpu cores : 1 physical id : 2 cpu cores : 1 physical id : 4 cpu cores : 1 physical id : 6 cpu cores : 1 physical id …

浏览器工作原理

一、JavaScript 的历史 JavaScript&#xff08;简称JS&#xff09;Web前端开发的脚本语言。 它诞生1995年&#xff0c;由网景公司的 Brendan Eich 开发。最初&#xff0c;JavaScript 被设计用于在网页上嵌入动态内容和交互式功能。 1996年&#xff0c;JavaScript 1.1 成为国…

C++虚函数与多态

C虚函数与多态虚函数抽象类纯虚函数虚析构函数多态虚函数的几个问题纯虚函数和ADT虚函数 virtual修饰的成员函数就是虚函数&#xff0c; 1.虚函数对类的内存影响&#xff1a;增加一个指针类型大小&#xff08;32位和64位&#xff09; 2.无论有多少个虚函数&#xff0c;只增加一…

【ansible】模块介绍超详解(下)

目录 六&#xff0c;软件包管理 1&#xff0c;yum_repository模块 &#xff08;1&#xff09;yum_repository模块常用选项 &#xff08;2&#xff09;yum_repository模块案例 2&#xff0c;mount模块 &#xff08;1&#xff09;mount模块选项 &#xff08;2&#xff09;mount模…

大数据简介

大数据概论和职业规划Linux服务器系统Hadoop概论HDFS分布式文件系统Hive数据仓库SparSQL指令Zepplin框架Sqoop框架Superset数据可视化大数据数仓实战-didi出行大数据概念大数据特点大数据应用场景大数据分析业务步骤大数据职业规划大数据学习路线。大数据概念数据&#xff1a;世…

基于YOLOv5的舰船检测与识别系统(Python+清新界面+数据集)

摘要&#xff1a;基于YOLOv5的舰船检测与识别系统用于识别包括渔船、游轮等多种海上船只类型&#xff0c;检测船舰目标并进行识别计数&#xff0c;以提供海洋船只的自动化监测和管理。本文详细介绍船舰类型识别系统&#xff0c;在介绍算法原理的同时&#xff0c;给出Python的实…

【系统开发】WebSocket + SpringBoot + Vue 搭建简易网页聊天室

文章目录一、数据库搭建二、后端搭建2.1 引入关键依赖2.2 WebSocket配置类2.3 配置跨域2.4 发送消息的控制类三、前端搭建3.1 自定义文件websocket.js3.2 main.js中全局引入websocket3.3 App.vue中声明websocket对象3.4 聊天室界面.vue3.5 最终效果一、数据库搭建 很简单的一个…

数据结构与算法——二叉树+带你实现表达式树(附源码)

&#x1f4d6;作者介绍&#xff1a;22级树莓人&#xff08;计算机专业&#xff09;&#xff0c;热爱编程&#xff1c;目前在c&#xff0b;&#xff0b;阶段&#xff0c;因为最近参加新星计划算法赛道(白佬)&#xff0c;所以加快了脚步&#xff0c;果然急迫感会增加动力>——…

ThreadLocal详解

一、什么是ThreadLocal 1、什么是ThreadLocal&为什么用ThreadLocal ThreadLocal&#xff0c;即线程本地变量&#xff0c;在类定义中的注释如此写This class provides thread-local variables。如果创建了一个ThreadLocal变量&#xff0c;那么访问这个变量的每个线程都会有…

C++基础算法④——排序算法(插入、桶附完整代码)

排序算法 1.插入排序 2.桶排序 1.插入排序 基本思想&#xff1a;将初始数据分为有序部分和无序部分&#xff1b;每一步将无序部分的第一个值插入到前面已经排好序的有序部分中&#xff0c;直到插完所有元素为止。步骤如下&#xff1a; 每次从无序部分中取出第一个值&#x…

图像分类卷积神经网络模型综述

图像分类卷积神经网络模型综述遇到问题 图像分类&#xff1a;核心任务是从给定的分类集合中给图像分配一个标签任务。 输入&#xff1a;图片 输出&#xff1a;类别。 数据集MNIST数据集 MNIST数据集是用来识别手写数字&#xff0c;由0~9共10类别组成。 从MNIST数据集的SD-1和…

在Clion开发工具上使用NDK编译可以在安卓上执行的程序

1. 前言 因为工作需要&#xff0c;我要将一份C语言代码编译成可执行文件传送到某安卓系统里执行。 众所周知&#xff0c;使用ndk编译代码有三种使用方式&#xff0c;分别是基于 Make 的 ndk-build、CMake以及独立工具链。以前进行ndk编程都是使用ndk-build进行的&#xff0c;新…
最新文章