0、背景
有段时间,采集了个数据,里面包含多个激光雷达的数据,具体为顶装的40线激光雷达,侧装的32线激光雷达。但是激光雷达间并没有对齐,为了使用上数据,想了一些办法将数据对齐,即转换到同一个坐标系下。
1、思路
-
一开始使用ICP算法进行对齐,但是效果很差,弃之。
-
使用手动标点,即在不同的雷达点云中,找到表征同一个位置的点的坐标,选取几十个点,最后计算外参矩阵。缺点是手动找点工作量大,且找的对应点不准确,误差大。尝试后效果也不行,但是比ICP好一些,亦弃之。
-
NDT算法对齐。我发现这个算法真的厉害,在X、Y轴对的很准,z轴对的不是很准,可能是数据在z轴没有什么区分度,但是也可以用了,具体采用PCL点云库实现。
2、数据介绍
(1)坐标系介绍
如下图,X轴指向车辆右方,Y轴指向车辆前方,Z轴指向车顶,遵循右手坐标系。
3个激光雷达的位置如图,1个绿色方框圈住的是顶装的40线激光雷达,2个红色方框圈住的侧装的32线激光雷达。
采集的点云数据都是以各自的激光雷达为坐标系,目的是将侧装的32线数据对齐到40线激光雷达的坐标系中,进行多传感器融合。
(2)数据展示
使用matlab展示了3个激光雷达的点云数据,每幅图上的标题显示了对应的传感器。
将3个点云画在一个坐标系中,发现根本没有对齐。
3、NDT算法
(1)头文件
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h> //点类型定义头文件
#include<pcl/point_cloud.h>
#include<pcl/visualization/cloud_viewer.h>
#include <pcl/registration/icp.h> //ICP配准类相关头文件
#include <pcl/filters/approximate_voxel_grid.h>
#include <boost/thread/thread.hpp>
#include <pcl/registration/ndt.h>
(2)NDT代码
int NDT(pcl::PointCloud<pcl::PointXYZ>::Ptr input_cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr target_cloud) //normal distribution transform
{
std::cout << "Loaded " << target_cloud->size() << " data points from target_cloud" << std::endl;
std::cout << "Loaded " << input_cloud->size() << " data points from input_cloud" << std::endl;
//将输入的扫描过滤到原始尺寸的大概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.2, 0.2, 0.2);
approximate_voxel_filter.setInputCloud(input_cloud);
approximate_voxel_filter.filter(*filtered_cloud);
std::cout << "Filtered cloud contains " << filtered_cloud->size()
<< " data points from input_cloud" << std::endl;
//初始化正态分布变换(NDT)
pcl::NormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ> ndt;
//设置依赖尺度NDT参数
//为终止条件设置最小转换差异
ndt.setTransformationEpsilon(0.01);
//为More-Thuente线搜索设置最大步长
ndt.setStepSize(0.1);
//设置NDT网格结构的分辨率(VoxelGridCovariance)
ndt.setResolution(1.0);
//设置匹配迭代的最大次数
ndt.setMaximumIterations(35);
// 设置要配准的点云
ndt.setInputCloud(filtered_cloud);
//设置点云配准目标
ndt.setInputTarget(target_cloud);
//设置使用ICP得到的初始对准估计结果
Eigen::AngleAxisf init_rotation(0, Eigen::Vector3f::UnitZ()); //左雷达0 右雷达 0
// (3)NDT函数中左/右雷达相应的初始估计
Eigen::Translation3f init_translation(-0.704139, -0.0467357, -0.243794); //左雷达初始估计值
//Eigen::Translation3f init_translation(0.674899, -0.014631, -0.231773); //右雷达初始估计值
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);
std::cout << "Normal Distributions Transform has converged:" << ndt.hasConverged()
<< " score: " << ndt.getFitnessScore() << std::endl;
std::cout << ndt.getFinalTransformation() << std::endl;
//使用创建的变换对未过滤的输入点云进行变换
pcl::transformPointCloud(*input_cloud, *output_cloud, ndt.getFinalTransformation());
//保存转换的输入点云
pcl::io::savePCDFileASCII("room_scan2_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(target_cloud, 255, 0, 0);
viewer_final->addPointCloud<pcl::PointXYZ>(target_cloud, 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);
}
(3)计算出的矩阵
(4)对齐效果
使用matlab将数据进行坐标转换后,可视化。
可以看到,结果非常优秀!