ICP已经成为点云配准的主流算法,因此,这两天测试了PCL库中的两个ICP函数:
pcl::GeneralizedIterativeClosestPoint< PointSource, PointTarget >
pcl::IterativeClosestPoint< PointSource, PointTarget >
GICP的用法和ICP类似,照葫芦画瓢即可。为了加快配准速度,程序中对点云做了半径和体素滤波处理。
经过多次实验,可以得出如下结论:
程序如下:
#include
#include
#include
#include
#include //可视化头文件
#include
#include
#include
#include
#include
#include
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud PointCloudT;
int main(int argc, char** argv)
{
// 创建点云指针
PointCloudT::Ptr cloud_in(new PointCloudT); // 需要转换的点云
PointCloudT::Ptr cloud_tr(new PointCloudT); // 转换后的点云
PointCloudT::Ptr cloud_icped(new PointCloudT); // ICP后输出点云
PointCloudT::Ptr cloud_icped1(new PointCloudT); // ICP后输出点云
PointCloudT::Ptr cloud_aim(new PointCloudT); // 向其转换的目标点云
PointCloudT::Ptr cloud_in_src(new PointCloudT);
PointCloudT::Ptr cloud_aim_src(new PointCloudT);
PointCloudT::Ptr cloud_in_rad(new PointCloudT);
PointCloudT::Ptr cloud_aim_rad(new PointCloudT);
pcl::StopWatch timeer;
//读取pcd文件
if (pcl::io::loadPCDFile("test_pcd_seg_0.pcd", *cloud_aim_src) == -1)
{
PCL_ERROR("Couldn't read file1 \n");
return (-1);
}
std::cout << "Loaded " << cloud_aim_src->size() << " data points from file1" << std::endl;
if (pcl::io::loadPCDFile("test_pcd_seg_1.pcd", *cloud_in_src) == -1)
{
PCL_ERROR("Couldn't read file2 \n");
return (-1);
}
std::cout << "Loaded " << cloud_in_src->size() << " data points from file2" << std::endl;
std::vector mapping_in;
std::vector mapping_out;
pcl::removeNaNFromPointCloud(*cloud_in_src, *cloud_in_src, mapping_in);
pcl::removeNaNFromPointCloud(*cloud_aim_src, *cloud_aim_src, mapping_out);
// Perform the actual filtering
pcl::RadiusOutlierRemoval outrem;
// build the filter
outrem.setInputCloud(cloud_in_src);
outrem.setRadiusSearch(0.04);
outrem.setMinNeighborsInRadius(80);
// apply filter
outrem.filter(*cloud_in_rad);
// build the filter
outrem.setInputCloud(cloud_aim_src);
outrem.setRadiusSearch(0.04);
outrem.setMinNeighborsInRadius(80);
// apply filter
outrem.filter(*cloud_aim_rad);
// downsample clouds
pcl::VoxelGrid vg;
vg.setInputCloud(cloud_in_rad);
vg.setLeafSize(0.01f, 0.01f, 0.01f);
vg.filter(*cloud_in);
vg.setInputCloud(cloud_aim_rad);
vg.setLeafSize(0.01f, 0.01f, 0.01f);
vg.filter(*cloud_aim);
timeer.reset();
//icp配准
//pcl::IterativeClosestPoint icp; //创建ICP对象,用于ICP配准
//pcl::GeneralizedIterativeClosestPoint icp;
//icp.setMaximumIterations(500); //设置最大迭代次数iterations=true
//icp.setMaxCorrespondenceDistance(0.5);
//icp.setTransformationEpsilon(1e-6);
//icp.setEuclideanFitnessEpsilon(1);
//icp.setInputCloud(cloud_in); //设置输入点云
//icp.setInputTarget(cloud_aim); //设置目标点云(输入点云进行仿射变换,得到目标点云)
//icp.align(*cloud_icped1); //匹配后源点云
pcl::IterativeClosestPoint icp2; //创建ICP对象,用于ICP配准
//icp2.setEuclideanFitnessEpsilon(1);
icp2.setMaximumIterations(200);
icp2.setInputCloud(cloud_in); //设置输入点云
icp2.setInputTarget(cloud_aim); //设置目标点云(输入点云进行仿射变换,得到目标点云)
icp2.align(*cloud_icped); //匹配后源点云
//icp.setMaximumIterations(1); // 设置为1以便下次调用
//std::cout << "Applied " << iterations << " ICP iteration(s)" << std::endl;
if (icp2.hasConverged())//icp.hasConverged ()=1(true)输出变换矩阵的适合性评估
{
std::cout << "\nICP has converged, score is: " << icp2.getFitnessScore() << std::endl;
std::cout << "\nICP has converged, Epsilon is: " << icp2.getEuclideanFitnessEpsilon() << std::endl;
//std::cout << "\nICP transformation " << iterations << " : cloud_in -> cloud_aim" << std::endl;
std::cout << "\nICP transformation is \n " << icp2.getFinalTransformation() << std::endl;
//transformation_matrix = icp.getFinalTransformation().cast();
//print4x4Matrix(transformation_matrix);
}
else
{
PCL_ERROR("\nICP has not converged.\n");
return (-1);
}
std::cout << "ICP run time: " << timeer.getTimeSeconds() << " s" << std::endl;
//可视化
pcl::visualization::PCLVisualizer viewer("ICP demo");
// 创建两个观察视点
int v1(0);
int v2(1);
viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v1);
viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2);
// 定义显示的颜色信息
float bckgr_gray_level = 0.0; // Black
float txt_gray_lvl = 1.0 - bckgr_gray_level;
// 原始的点云设置为白色的
pcl::visualization::PointCloudColorHandlerCustom cloud_aim_color_h(cloud_aim, (int)255 * txt_gray_lvl, (int)255 * txt_gray_lvl,
(int)255 * txt_gray_lvl);
viewer.addPointCloud(cloud_aim, cloud_aim_color_h, "cloud_aim_v1", v1);//设置原始的点云都是显示为白色
viewer.addPointCloud(cloud_aim, cloud_aim_color_h, "cloud_aim_v2", v2);
// 需要被转换的点云显示为绿色
pcl::visualization::PointCloudColorHandlerCustom cloud_in_color_h(cloud_in, 20, 180, 20);
viewer.addPointCloud(cloud_in, cloud_in_color_h, "cloud_in_v1", v1);
// ICP配准后的点云为红色
pcl::visualization::PointCloudColorHandlerCustom cloud_icped_color_h(cloud_icped, 180, 20, 20);
viewer.addPointCloud(cloud_icped, cloud_icped_color_h, "cloud_icped_v2", v2);
// 加入文本的描述在各自的视口界面
//在指定视口viewport=v1添加字符串“white 。。。”其中"icp_info_1"是添加字符串的ID标志,(10,15)为坐标16为字符大小 后面分别是RGB值
viewer.addText("White: Original point cloud\nGreen: Matrix transformed point cloud", 10, 15, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "icp_info_1", v1);
viewer.addText("White: Original point cloud\nRed: ICP aligned point cloud", 10, 15, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "icp_info_2", v2);
// 设置背景颜色
viewer.setBackgroundColor(bckgr_gray_level, bckgr_gray_level, bckgr_gray_level, v1);
viewer.setBackgroundColor(bckgr_gray_level, bckgr_gray_level, bckgr_gray_level, v2);
// 设置相机的坐标和方向
viewer.setCameraPosition(-3.68332, 2.94092, 5.71266, 0.289847, 0.921947, -0.256907, 0);
viewer.setSize(1280, 1024); // 可视化窗口的大小
//显示
while (!viewer.wasStopped())
{
viewer.spinOnce();
}
return 0;
}