NDT和ICP构建点云地图 |【点云建图、Ubuntu、ROS】

###

本博客记录学习NDT,ICP构建点云地图的实验过程,参考的以下两篇博客:

无人驾驶汽车系统入门(十三)——正态分布变换(NDT)配准与无人车定位_settransformationepsilon-CSDN博客

PCL中点云配准(非常详细,建议收藏)_pcl点云配准-CSDN博客

代码可自取:Xz/NDT构建点云地图 - Gitee.com

###

一、bag包点云数据处理

1.1 首先查看bag包的信息

rosbag info <包名>

通过rosbag info 可以查看bag数据包的信息,主要是一些话题名称和消息类型。

1.2 对点云数据转化为pcd格式保存

        PCD(Point Cloud Data)是专为点云设计的文件格式,支持存储多维数据(如坐标、颜色、强度、法向量、时间戳等)。其核心优势在于:

  • 标准化
  • 高效存储
  • 完整保留属性
  • 生态支持广泛
rosrun pcl_ros bag_to_pcd <bag数据包名称>.bag <点云话题名称> <保存的文件夹名>.pcd

随后,在同目录下生成data.pcd文件夹,存放点云数据数据:

这样,点云数据处理完成。

二、NDT构建点云地图

2.1 NDT介绍

        正态分布变换(Normal Distributions Transform,NDT)是一种依赖于高精地图和激光雷达的定位技术。是一类利用已有的高精度地图和激光雷达实时测量数据实现高精度定位的技术。其核心思想是将点云空间划分为多个 网格(Cell),对每个网格中的点云拟合一个 正态分布(高斯分布),然后用概率模型描述整个点云。通过优化匹配概率,找到两个点云之间的最佳变换(旋转和平移)。

2.2 NDT算法步骤

2.2.1 划分体素网格

        将参考点云划分为均匀的立方体网格(体素)。每个体素的大小需根据场景调整通常在0.1m到数米之间。对每个体素内的点云,计算均值向量\mu和协方差矩阵\sum

2.2.2 初始化变换参数

        给定初始猜测变换T_{init}(如里程计估计或前一帧位姿),将当前点云P_{current} 投影到参考坐标系。

2.2.3 构建目标函数

        对于变换后的当前点T_{init},找到其所在参考体素,计算其在该体素分布下的概率密度:

        其中k为维度(2D为3,3D为6)。

        目标函数:

2.2.4 优化求解变换参数

        在NDT(正态分布变换)算法中,构建完目标函数后,意味着将点云配准问题转化为一个数值优化问题,接下来需要通过优化算法求解最优的变换参数(旋转和平移),使得目标函数值最大化(或最小化,取决于定义)。这一步骤是NDT的核心,直接决定了配准的精度和效率。

        使用迭代优化,在每次迭代中,首先计算目标函数的梯度和Hessian矩阵以确定优化方向与步长,随后利用牛顿法或Levenberg-Marquardt等算法更新变换参数,并通过收敛条件(如梯度阈值、迭代次数或参数变化量)判断是否终止。这一过程逐步将当前点云对齐至参考点云的高概率区域,最终输出最优变换矩阵,完成配准。迭代优化的效率与精度高度依赖初始位姿、体素大小及优化算法的选择。

三、代码介绍

3.1 读取点云与NaN过滤

        从PCD文件加载点云,并移除无效点(NaN)

pcl::PointCloud<pcl::PointXYZ>::Ptr read_cloud_point(std::string const &file_path) {pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile<pcl::PointXYZ>(file_path, *cloud) == -1) {PCL_ERROR("Couldn't read the pcd file\n");return nullptr;}std::vector<int> indices;pcl::removeNaNFromPointCloud(*cloud, *cloud, indices);return cloud;
}

3.2 可视化函数

        显示目标点云(红色)和配准结果点云(绿色)。

void visualizer(pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr output_cloud) {// ...(颜色设置、坐标系、相机参数等)while (!viewer_final->wasStopped()) {viewer_final->spinOnce(100);std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}

3.3 主函数:数据加载与预处理

        加载目标点云和待配准点云。对输入点云进行体素滤波降采样(减少计算量)。

auto target_cloud = read_cloud_point(argv[1]);
auto input_cloud = read_cloud_point(argv[2]);
pcl::ApproximateVoxelGrid<pcl::PointXYZ> approximate_voxel_filter;
approximate_voxel_filter.setLeafSize(0.2, 0.2, 0.2);
approximate_voxel_filter.filter(*filtered_cloud);

3.4 主函数:NDT配准核心配置

        首先创建NDT配准对象并设置关键参数(包括收敛阈值0.01、优化步长0.05、网格分辨率0.5和最大迭代次数50),然后指定待配准的输入点云(降采样后的filtered_cloud)和目标点云(target_cloud);接着通过初始旋转(绕Z轴0.6931弧度)和平移(X=1.79387,Y=0.720047)构造初始位姿猜测init_guess,最后调用align方法执行配准,输出配准后的点云output_cloud,其中配准过程会不断优化变换矩阵直到满足收敛条件或达到最大迭代次数。

pcl::NormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ> ndt;
ndt.setTransformationEpsilon(0.01);  // 收敛阈值
ndt.setStepSize(0.05);              // 优化步长
ndt.setResolution(0.5);             // NDT网格分辨率
ndt.setMaximumIterations(50);       // 最大迭代次数
ndt.setInputSource(filtered_cloud); // 输入点云(降采样后)
ndt.setInputTarget(target_cloud);   // 目标点云// 初始位姿猜测
Eigen::AngleAxisf init_rotation(0.6931, Eigen::Vector3f::UnitZ());
Eigen::Translation3f init_translation(1.79387, 0.720047, 0);
Eigen::Matrix4f init_guess = (init_translation * init_rotation).matrix();// 执行配准
pcl::PointCloud<pcl::PointXYZ>::Ptr output_cloud(new pcl::PointCloud<pcl::PointXYZ>);
ndt.align(*output_cloud, init_guess);

四、操作步骤

        首先创建一个工作空间NDT_ws,并在该工作空间下创建src文件夹存放源码:

 mkdir -p NDT_ws/src

        然后再src文件夹下创建ndt_node.cpp文件,将代码写入改文件中,然后在NDT_ws目录下编写CMakeLists.txt文件:

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(ndt_node)set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)find_package(PCL 1.5 REQUIRED)
find_package(Boost REQUIRED COMPONENTS system)  include_directories(${PCL_INCLUDE_DIRS}${Boost_INCLUDE_DIRS} 
)link_directories(${PCL_LIBRARY_DIRS})add_executable(ndt src/ndt_node.cpp)target_link_libraries(ndt${PCL_LIBRARIES}${Boost_LIBRARIES} 
)

        在工作空间目录下创建build文件夹,存放编译过程文件,然后进行编译:

mkdir build
cd build
Cmake ..
make

        编译完成后生成可执行文件ndt,并将之前处理过的pcd文件放到该目录下:

        随后执行可执行文件即可:

        输出显示,从文件1.pcd加载了51574个数据点,从文件2.pcd加载了51626个数据点,原始点云可能经过体素网格滤波(Voxel Grid Filter)或统计离群值滤波(Statistical Outlier Removal)等处理,最终保留了 22,837 个数据点(减少约 55%)。滤波的目的是去除冗余或噪声数据,提升后续计算效率。

        NDT配准,NDT converged :1表示算法成功收敛,找到了最优变换矩阵。配准分数为56.2459。若是最终匹配的结果不准确,可调整NDT参数。

        通过匹配结果可知,其匹配的效果并不好。随后我也修改了NDT参数设置,但是最终的结果依旧不理想。然后我又利用ICP算法进行点云地图构建,如下图所示,为点云逐渐迭代的过程。其创建工作空间及操作过程与前面ICP操作相同。这里不在重复该过程,结果如下:

随着不断匹配新的点云,其点云范围逐渐增大。

        程序执行完之后,会在该目录下生成配准后的pcd文件,可用pcl_viewer命令查看pcd文件。取出其中一个pcd文件查看,左边为配准前的点云,右边为匹配了一个pcd文件后的点云,还是存在一些区别。

pcl_viewer <pcd文件名>.pcd

参考博客

无人驾驶汽车系统入门(十三)——正态分布变换(NDT)配准与无人车定位_settransformationepsilon-CSDN博客

PCL中点云配准(非常详细,建议收藏)_pcl点云配准-CSDN博客

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

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

相关文章

基于HTML + jQuery + Bootstrap 4实现(Web)地铁票价信息生成系统

地铁票价信息表生成系统 1. 需求分析 1.1 背景 地铁已经成为大多数人出行的首选,北京地铁有多条运营线路, 截至 2019 年 12 月,北京市轨道交通路网运营线路达 23 条、总里程 699.3 公里、车站 405 座。2019 年,北京地铁年乘客量达到 45.3 亿人次,日均客流为 1241.1 万人次…

EtherNet/IP 转 Modbus 协议网关

一、产品概述 1.1 产品用途 SG-EIP-MOD-210 网关可以实现将 Modbus 接口设备连接到 EtherNet/IP 网 络中。用户不需要了解具体的 Modbus 和 EtherNet/IP 协议即可实现将 Modbus 设 备挂载到 EtherNet/IP 接口的 PLC 上&#xff0c;并和 Modbus 设备进行数…

PostgreSQL:逻辑复制与物理复制

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

腾讯云COS与ZKmall 开源商城的存储集成方案

ZKmall 开源商城与腾讯云对象存储&#xff08;COS&#xff09;的集成&#xff0c;可通过云端资源托管、自动化数据同步、高性能存储架构实现本地存储负载降低与访问效率提升。以下是基于搜索结果的集成路径与核心优化点&#xff1a; 一、存储架构升级&#xff1a;本地与云端协同…

HTML — 浮动

浮动 HTML浮动&#xff08;Float&#xff09;是一种CSS布局技术&#xff0c;通过float: left或float: right使元素脱离常规文档流并向左/右对齐&#xff0c;常用于图文混排或横向排列内容。浮动元素会紧贴父容器或相邻浮动元素的边缘&#xff0c;但脱离文档流后可能导致父容器高…

【软件测试学习day1】软件测试概念

前言 本篇学习&#xff0c;测试相关基础概念、常见的开发模型测和测试模型&#xff0c;搞懂4个问题&#xff1a; 什么是需求什么是 bug什么是测试用例开发模型和测试模型 目录 1. 什么是需求 1.1 为什么要有需求 1.2 测试人员眼里的需求 1.3 如何深入了解需求 2. 测试用例…

Flutter常用组件实践

Flutter常用组件实践 1、MaterialApp 和 Center(组件居中)2、Scaffold3、Container(容器)4、BoxDecoration(装饰器)5、Column(纵向布局)及Icon(图标)6、Column/Row(横向/横向布局)+CloseButton/BackButton/IconButton(简单按钮)7、Expanded和Flexible8、Stack和Po…

刘火良FreeRTOS内核实现与应用学习之7——任务延时列表

在《刘火良FreeRTOS内核实现与应用学习之6——多优先级》的基础上&#xff1a;关键是添加了全局变量&#xff1a;xNextTaskUnblockTime &#xff0c;与延时列表&#xff08;xDelayedTaskList1、xDelayedTaskList2&#xff09;来高效率的实现延时。 以前需要在扫描就绪列表中所…

图像预处理-插值方法

一.插值方法 当我们对图像进行缩放或旋转等操作时&#xff0c;需要在新的像素位置上计算出对应的像素值。 而插值算法的作用就是根据已知的像素值来推测未知位置的像素值。 1.1 最近邻插值 CV2.INTER_NEAREST 其为 warpAffine() 函数的参数 flags 的其一&#xff0c;表示最近…

智能配电保护:公共建筑安全的新 “防火墙”

安科瑞刘鸿鹏 摘要 随着城市建筑体量的不断增长和电气设备的广泛使用&#xff0c;现代建筑大楼的用电安全问题日益突出。传统配电方式面临监测盲区多、响应滞后、火灾隐患难发现等问题。为提升建筑电气系统的安全性和智能化水平&#xff0c;智慧用电系统应运而生。本文结合安…

如何解决DDoS攻击问题 ?—专业解决方案深度分析

本文深入解析DDoS攻击面临的挑战与解决策略&#xff0c;提供了一系列防御技术和实践建议&#xff0c;帮助企业加强其网络安全架构&#xff0c;有效防御DDoS攻击。从攻击的识别、防范措施到应急响应&#xff0c;为网络安全工作者提供了详细的操作指引。 DDoS攻击概览&#xff1a…

构建灵活的接口抽象层:支持多种后端数据存取的实战指南

构建灵活的接口抽象层:支持多种后端数据存取的实战指南 引言 在现代软件开发中,数据存取成为业务逻辑的核心组成部分。然而,由于后端数据存储方式的多样性(如关系型数据库、NoSQL数据库和文件存储),如何设计一套能够适配多种后端数据存取的接口抽象层,成为技术团队关注…

OpenCV 图形API(23)图像和通道合成

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 1.算法描述 在OpenCV的G-API模块中&#xff0c;图像和通道合成&#xff08;composition&#xff09;函数允许用户对图像进行复杂的操作&#xff0c;如合并…

帝国cms导航淘客新闻下载多功能网站源码 二次元风格自适应附教程

一、本模板使用帝国cms7.5 utf8版本&#xff0c;二次元导航新闻下载工具淘客自适应响应式帝国cms模板。 1、网站后台有3个系统模型&#xff0c;新闻系统模型&#xff0c;下载系统模型&#xff0c;导航系统模型&#xff0c;商城系统模型&#xff0c;可以根据自己的需求不同&…

本地部署大模型(ollama模式)

分享记录一下本地部署大模型步骤。 大模型应用部署可以选择 ollama 或者 LM Studio。本文介绍ollama本地部署 ollama官网为&#xff1a;https://ollama.com/ 进入官网&#xff0c;下载ollama。 ollama是一个模型管理工具和平台&#xff0c;它提供了很多国内外常见的模型&…

C# virtual 和 abstract 详解

简介 在 C# 中&#xff0c;virtual 和 abstract 关键字都用于面向对象编程中的继承和多态&#xff0c;它们主要用于方法、属性和事件的定义&#xff0c;但在用法上存在一些重要的区别。 virtual 关键字 virtual 表示可重写的方法&#xff0c;但可以提供默认实现&#xff0c;…

自动驾驶的数据集以及yolov8和yolop

项目背景 网络全部是分割了没有检测。 自动驾驶的车道线和可行驶区域在数据集中的表示 自动驾驶系统中的车道线和可行驶区域的表示方式主要有以下几种&#xff1a; 基于几何模型&#xff1a;使用几何模型来描述车道线和可行驶区域的形状和位置&#xff0c;例如直线、曲线、多…

Oracle DROP、TRUNCATE 和 DELETE 原理

在 Oracle 11g 中&#xff0c;DROP、TRUNCATE 和 DELETE 是三种不同的数据清理操作&#xff0c;它们的底层原理和适用场景有显著差异 1. DELETE 的原理 类型&#xff1a;DML&#xff08;数据操作语言&#xff09; 功能&#xff1a;逐行删除表中符合条件的数据&#xff0c;保留…

PCIe 5.0光学SSD原型问世!

近日&#xff0c;Kioxia Corporation&#xff08;铠侠&#xff09;、AIO Core Co., Ltd. 和 Kyocera Corporation&#xff08;京瓷&#xff09;联合宣布成功开发了一款支持 PCIe 5.0 接口的光学 SSD 原型。该技术旨在通过光接口替换传统的电接口&#xff0c;从而显著增加计算设…

SQL 查询中涉及的表及其作用说明

SQL 查询中涉及的表及其作用说明&#xff1a; 涉及的数据库表 表名别名/用途关联关系dbo.s_orderSO&#xff08;主表&#xff09;存储订单主信息&#xff08;订单号、日期、客户等&#xff09;dbo.s_orderdetailSoD&#xff08;订单明细&#xff09;通过 billid SO.billid 关…