[无人驾驶]无外参矩阵下的多激光雷达对齐

0、背景

有段时间,采集了个数据,里面包含多个激光雷达的数据,具体为顶装的40线激光雷达,侧装的32线激光雷达。但是激光雷达间并没有对齐,为了使用上数据,想了一些办法将数据对齐,即转换到同一个坐标系下。

1、思路

  1. 一开始使用ICP算法进行对齐,但是效果很差,弃之。

  2. 使用手动标点,即在不同的雷达点云中,找到表征同一个位置的点的坐标,选取几十个点,最后计算外参矩阵。缺点是手动找点工作量大,且找的对应点不准确,误差大。尝试后效果也不行,但是比ICP好一些,亦弃之。

  3. 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将数据进行坐标转换后,可视化。

可以看到,结果非常优秀!
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值