@[TOC]PCL中点云配准模块的学习
学习背景
参考书籍:《点云库PCL从入门到精通》以及官方代码PCL官方代码链接,,PCL版本为1.10.0,CMake版本为3.16,可用点云下载地址
学习内容
在代码中使用ICP迭代最近点算法,程序随机生成一个点与作为源点云,并将其沿x轴平移后作为目标点云,然后利用ICP估计源到目标的刚体变换橘子,中间对所有信息都打印出来。在 ICP 配准过程中,算法会迭代地寻找源点云和目标点云之间的最佳变换矩阵,使得两个点云之间的距离最小化。
源代码及所用函数
源代码
//迭代最近点算法
#include<iostream>//标准输入输出头文件
#include<pcl/io/pcd_io.h>//PCD输入输出头文件
#include<pcl/point_types.h>//点类型定义头文件
#include<pcl/registration/icp.h>//ICP(迭代最近点)配准算法头文件。
int main()
{
//**********************************************初始化点云并填充打印***************************************//
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>(5,1));
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out (new pcl::PointCloud<pcl::PointXYZ>);
//*******************填充点云第一种写法**************************//
// // 随机填充点云
// cloud_in->width = 5; //设置点云宽度
// cloud_in->height = 1; //设置点云为无序点
// cloud_in->is_dense = false;
// cloud_in->points.resize (cloud_in->width * cloud_in->height);
// for (size_t i = 0; i < cloud_in->points.size(); i++)
// {
// cloud_in->points[i].x = 1024.0f*rand()/(RAND_MAX +1.0f);
// cloud_in->points[i].y = 1024.0f*rand()/(RAND_MAX +1.0f);
// cloud_in->points[i].z = 1024.0f*rand()/(RAND_MAX +1.0f);
// }
//*********************填充点云第二种方法**********************//
for (auto& point : *cloud_in)
{
point.x = 1024 * rand() / (RAND_MAX + 1.0f);
point.y = 1024 * rand() / (RAND_MAX + 1.0f);
point.z = 1024 * rand() / (RAND_MAX + 1.0f);
}
//打印点云
std::cout << "已保存:" << cloud_in->points.size () << "个点,其坐标为:" << std::endl;
//*******************打印点云第一种方法************************//
// for (size_t i = 0; i < cloud_in->points.size (); ++i)
// {
// std::cout << " " << cloud_in->points[i].x << " " << cloud_in->points[i].y << " " << cloud_in->points[i].z << std::endl;
// }
//******************打印点云的第二种方法***********************//
for (auto& point : *cloud_in)
{
std::cout << point << std::endl;
}
//****************************************实现一个简单的点云刚体变换,以构造目标点云******************************//
*cloud_out = *cloud_in;
std::cout << "点云大小:" << cloud_out->size() << std::endl;
for (auto& point : *cloud_out)
{
point.x += 0.7f;
}
std::cout << "转移了 " << cloud_in->size () << "个点" << std::endl;
for(auto& point : *cloud_out)
{
std::cout << point << std::endl;
}
pcl::IterativeClosestPoint<pcl::PointXYZ,pcl::PointXYZ> icp;//创建IterativeClosestPoint的对象
icp.setInputSource(cloud_in); //cloud_in设置为点云的源点
icp.setInputTarget(cloud_out);//cloud_out设置为与cloud_in对应的匹配目标
pcl::PointCloud<pcl::PointXYZ> Final;//存储经过配准变换点云后的点云
icp.align(Final);//打印配准相关输入信息
std::cout << "已收敛" << icp.hasConverged() << "总共" << icp.getFitnessScore() << std::endl;
std::cout << icp.getFinalTransformation() << std::endl;
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)#指定CMake的最低版本要求为3.16
project(project)#设置项目名称
find_package(PCL 1.10 REQUIRED)#查找PCL库,要求版本为1.10或更高。
include_directories(${PCL_INCLUDE_DIRS})#将PCL库的头文件目录添加到包含路径中
link_directories(${PCL_LIBRARY_DIRS})#将PCL库的库文件目录添加到链接器搜索路径中。
add_definitions(${PCL_DEFINITIONS})#添加PCL库的编译器定义
add_executable (iterative_closest_point iterative_closest_point.cpp)
target_link_libraries (iterative_closest_point ${PCL_LIBRARIES})#将PCL库链接到可执行文件目标。
运行结果
红色是随机生成点云,绿色是ICP配准后的点云
函数
-
icp.hasConverged()
是 PCL 库中 IterativeClosestPoint 类的一个成员函数,用于检查 ICP 配准算法是否收敛。hasConverged() 函数返回一个布尔值,表示 ICP 算法是否达到了收敛条件。当 ICP 算法满足收敛条件时,hasConverged()
函数将返回 true,表示配准过程已经完成,得到了最佳的变换矩阵。 -
icp.getFitnessScore()
是ICP(迭代最近点)算法中的一个函数,用于计算当前变换矩阵的适应度得分(Fitness Score)用来评估当前变换矩阵的性能。具体来说,getFitnessScore()通常会计算以下指标:
对应点之间的欧氏距离之和或均值。距离越小,说明对齐效果越好。
内点(Inlier)的数量或比例。内点指的是在一定误差范围内匹配的点对。内点越多,说明对齐效果越好。
误差的标准差。误差越集中,说明对齐更加一致。关于返回值的大小通常有两种常见的情况:
得分越小越好:如果getFitnessScore()返回的是误差或距离的度量,如对应点之间的欧氏距离之和或均值,则得分越小表示对齐效果越好。在这种情况下,ICP算法的目标是最小化getFitnessScore()的返回值。
得分越大越好:如果getFitnessScore()返回的是内点的数量、比例或其他表示对齐质量的指标,则得分越大表示对齐效果越好。在这种情况下,ICP算法的目标是最大化getFitnessScore()的返回值。
在大多数实现中,这个分数通常是平均平方误差,所以较低的分数意味着两个点云之间的对应点的距离较近,表明配准的质量较高。