在进行点云匹配时,常用的方法有ICP配准算法以及NDT匹配算法,下面总结一下NDT的一些基本知识。

NDT算法原理:

    NDT算法的基本思想是先根据参考数据(reference scan)来构建多维变量的正态分布, 如果变换参数能使得两幅激光数据匹配的很好,那么变换点在参考系中的概率密度将会很大。

因此,可以考虑用优化的方法求出使得概率密度之和最大的变换参数,此时两幅激光点云数 据将匹配的最好。

NDT算法关键点:

1、将二维空间划分为固定大小网格,每个网格至少包括3个点(一般5个)

2、计算网格中点集的均值μ

3、计算网格中点集的协方差矩阵Σ

4、网格中的观测到点x的概率p(x)服从正态分布N( μ,Σ)。

NDT代码实现的基本思路总结~

1、加载目标点云,这里以PCD文件的形式进行加载

2、加载需要配准的点云,这里以PCD文件的形式进行加载

3、去除二者周边的点云,这里用最近距离以及最低距离两个阈值进行挑选,类似于点云的裁剪

4、将输入的扫描过滤到原始点云的10%,这里主要使用体素滤波器,主要进行点云的下采样工作

5、初始化正态分布NDT对象

6、设置NDT的依赖参数以及迭代终止条件

7、设置NDT的初始化矩阵参数

8、将降采样后的点云与初始化矩阵进行相乘

9、得到NDT的标准正态分布与分数

10、使用创建的变换对未过滤的点云进行变换

11、保存转换后的输入点云

12、初始化点云可视化界面

13、加载点云

实现代码如下:

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/ndt.h>
#include <pcl/filters/approximate_voxel_grid.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>void range_filter(pcl::PointCloud<pcl::PointXYZ> & input_cloud, pcl::PointCloud<pcl::PointXYZ> & output_cloud,const float & min_scan_range_, const float min_z){double r;pcl::PointXYZ p ;for (pcl::PointCloud<pcl::PointXYZ>::const_iterator item = input_cloud.begin();item != input_cloud.end(); item++){p.x = (double) item->x;p.y = (double) item->y;p.z = (double) item->z;r = p.x * p.x + p.y * p.y;if (r > min_scan_range_&&p.z >min_z) //filter the point distance lager than min_scan_range and height lower than min_z{output_cloud.push_back(p);}}}
int
main (int argc, char** argv)
{//加载目标点云pcdpcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud (new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile<pcl::PointXYZ> ("test1.pcd", *target_cloud) == -1){PCL_ERROR ("Couldn't read file test1.pcd \n");return (-1);}std::cout << "Loaded " << target_cloud->size () << " data points from room_scan1.pcd" << std::endl;//加载需要配准点云pcdpcl::PointCloud<pcl::PointXYZ>::Ptr input_cloud (new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile<pcl::PointXYZ> ("test2.pcd", *input_cloud) == -1){PCL_ERROR ("Couldn't read file test2.pcd\n");return (-1);}std::cout << "Loaded " << input_cloud->size () << " data points from room_scan2.pcd" << std::endl;
//range filter,去除周围点云pcl::PointCloud<pcl::PointXYZ>::Ptr output_cloud1 (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr output_cloud2 (new pcl::PointCloud<pcl::PointXYZ>);
range_filter(*input_cloud,*output_cloud1,4,0.1);
range_filter(*target_cloud,*output_cloud2,4,0.1);//将输入的扫描过滤到原始尺寸的大概10%以提高匹配的速度。pcl::PointCloud<pcl::PointXYZ>::Ptr filtered_cloud (new pcl::PointCloud<pcl::PointXYZ>);pcl::ApproximateVoxelGrid<pcl::PointXYZ> approximate_voxel_filter;approximate_voxel_filter.setLeafSize (0.09, 0.09, 0.09);approximate_voxel_filter.setInputCloud (output_cloud1);approximate_voxel_filter.filter (*filtered_cloud);std::cout << "Filtered cloud contains " << filtered_cloud->size ()<< " data points from test2.pcd" << std::endl;//初始化正态分布变换(NDT)pcl::NormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ> ndt;//设置依赖尺度NDT参数//为终止条件设置最小转换差异ndt.setTransformationEpsilon (0.001);//定义了[x,y,z,roll,pitch,yaw]在配准中的最小递增量,一旦递增量小于此限制,配准终止//为More-Thuente线搜索设置最大步长,步长越大迭代越快,但也容易导致错误ndt.setStepSize (0.1);//设置NDT网格结构的分辨率(VoxelGridCovariance)ndt.setResolution (0.8);//ND体素的大小,单位为m,越小越准确,但占用内存越多//设置匹配迭代的最大次数ndt.setMaximumIterations (1000);// 设置要配准的点云ndt.setInputCloud (filtered_cloud);//设置点云配准目标ndt.setInputTarget (output_cloud2);//设置使用机器人测距法得到的初始对准估计结果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);//这一步是将降采样之后的点云经过变换后的到output_cloudstd::cout << "Normal Distributions Transform has converged:" << ndt.hasConverged ()<< " score: " << ndt.getFitnessScore () << std::endl;//欧式适合度评分//使用创建的变换对未过滤的输入点云进行变换//ndt.getFinalTransformation ()即最终变换pcl::transformPointCloud (*output_cloud1, *output_cloud, ndt.getFinalTransformation ());//保存转换的输入点云pcl::io::savePCDFileASCII ("test_transformed.pcd", *output_cloud);// 初始化点云可视化界面boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer_final (new pcl::visualization::PCLVisualizer ("3D Viewer"));viewer_final->setBackgroundColor (0, 0, 0);//对目标点云着色(红色)并可视化pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>target_color (output_cloud2, 255, 0, 0);viewer_final->addPointCloud<pcl::PointXYZ> (output_cloud2, target_color, "target cloud");viewer_final->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE,1, "target cloud");//对转换后的目标点云着色(绿色)并可视化pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>output_color (output_cloud, 0, 255, 0);viewer_final->addPointCloud<pcl::PointXYZ> (output_cloud, output_color, "output cloud");viewer_final->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE,1, "output cloud");// 启动可视化viewer_final->addCoordinateSystem (1.0);viewer_final->initCameraParameters ();//等待直到可视化窗口关闭。while (!viewer_final->wasStopped ()){viewer_final->spinOnce (100);boost::this_thread::sleep (boost::posix_time::microseconds (100000));}return (0);
}

NDT算法的匹配流程相关推荐

  1. 一文详解NDT算法实现

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 作者丨paopaoslam 来源丨 泡泡机器人SLAM .PCL源码 编辑丨玉玺.lionheart ...

  2. 点云配准之NDT算法

    1.算法原理 已知有两幅点云,分别为源点云P和目标云Q. 1)将源点云P所在空间划分为一个一个的单元网格,(即三维空间在二维空间上的投影). 2)根据所划分单元网格内点的分布情况,计算单元网格的正态分 ...

  3. 激光SLAM之NDT算法(1)算法原理

    /在激光SLAM之NDT算法(2)-建图中我会给出实测可用的建图代码,并予以解释代码结构,这里就先讲讲原理吧!!!/ 无人车激光SLAM系统简单可以分为建图和定位两部分,无人车的定位问题,实际上就是要 ...

  4. 操作系统之银行家算法—详解流程及案例数据

    操作系统之进程调度--优先权法和轮转法(附上样例讲解) 操作系统之银行家算法-详解流程及案例数据 操作系统之多线程编程-读者优先/写者优先详解 操作系统之存储管理--FIFO算法和LRU算法 操作系统 ...

  5. 若S作主串,P作模式串,试分别写出利用BF算法和KMP算法的匹配过程。

    目   录 题目: 百度文库-答案: (1) (2) MOOC标准答案: (1) (2) mooc答案-截图: 数据结构(C语言版)-严蔚敏2007 题目: 设字符串S='aabaabaabaac', ...

  6. 【HDU - 5943】Kingdom of Obsession(数论,素数间隔结论,构造,思维,匈牙利算法,匹配问题)

    题干: There is a kindom of obsession, so people in this kingdom do things very strictly. They name the ...

  7. 字符串算法——KMP匹配及Next数组

    KMP是单模匹配算法,即在一段长度为n的文本串中搜索一个长度为m的模式串,算法复杂度为O(n+m),差不多是这类算法能达到的最优复杂度. 朴素的模式匹配算法 在处理这类问题时,最简单的方法便是暴力匹配 ...

  8. linux设备驱动——bus、device、driver加载顺序与匹配流程

    文章目录 1. 前言 2. 概念 2.1. 数据结构 2.2. probe函数 3. bus.device.driver加载顺序 3.1. 加载方式 3.2. 加载顺序 4. device.drive ...

  9. 关于国密算法SM4的流程

    关于国密算法SM4的流程 原来用于无线局域网的国密算法SMS4被定义为SM4作为密码行业标准发布.SM4是一个分组对称密钥算法,明文.密钥.密文都是16字节,加密和解密密钥相同.通过32次循环的非线性 ...

  10. open-match匹配流程

    open-match匹配流程 (金庆的专栏 2019.1) https://github.com/GoogleCloudPlatform/open-match open-match 是一个通用的游戏匹 ...

最新文章

  1. 仿夸克浏览器底部工具栏
  2. SCF: 简单配置门面
  3. java session 同步_session同步
  4. 数据分析工具篇——HQL原理及函数逻辑
  5. WINCE BSP中source文件中的宏定义
  6. factorymenu什么意思_宏基20lsquo;显示屏AUTO和MENU是什么意思,在什么位置_已解决 - 阿里巴巴生意经...
  7. openwrt系统的无线WiFi配置文件
  8. loss函数之KLDivLoss
  9. arm体系结构与编程_ARM体系结构基础(1)
  10. 文章中的代码添加语法高亮
  11. matlab 梁代码,方舟生存进化梁龙鞍怎么做 梁龙鞍代码材料一览
  12. 超表面透镜相位matlab,基于超透镜的小F数大景深镜头的设计方法及应用与流程...
  13. Emmagee——开源Android性能测试工具
  14. 的计算机基本操作知识,电脑的基本操作知识有哪些
  15. linux 内存取证_内存取证工具volatility
  16. 算法问题——(树问题集合)
  17. Ubuntu 之 Audacity踩坑之旅
  18. 无情链表的创建,,插入,,删除第一个位
  19. Cognos Analytics教程之为什么我喜欢 Cognos Analytics:IBM Cognos Analytics 的 15 个特性
  20. 阿里云南京云栖大会举行 给制造业升级下猛药

热门文章

  1. pycharm复制代码出现空格
  2. 用友T+改成IIS-网站报500.19错误代码0x8007000d问题解决
  3. java FreeMarker模板路径问题
  4. Fragment和Activity之间的通信
  5. 群晖如何建php网站_群晖建博客详细教程
  6. 浅谈使用postman的CryptoJS.MD5加密带有中文(已进行unicode编码)以及url的字符串与md5在线加密工具加密不一致的原因,附加解决方法。
  7. 对封装、继承、多态的简单理解
  8. 班级网站的设计与实现
  9. Pytorch中pack_padded_sequence和pad_packed_sequence的理解
  10. ACM中关于Output Limit Exceeded和Time Limit Exceeded