迭代最近点的使用方法(How to use iterative closest point) 迭代最近点的使用方法(How to use iterative closest point)
#如何使用迭代最近点
本文档旨在深入解析在编程环境中应用迭代最近点(ICP)算法的具体流程。该算法的核心机制在于通过最小化两个点云集合之间的几何距离,并执行严格的刚性变换操作,来判定一个PointCloud对象是否仅仅是另一个PointCloud经过旋转或平移后的结果。这种技术广泛应用于三维重建、机器人定位及物体识别领域,是处理无序点云数据对齐的关键手段。
#代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/icp.h>
int
main (int argc, char** argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out (new pcl::PointCloud<pcl::PointXYZ>);
// Fill in the CloudIn data
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 * rand () / (RAND_MAX + 1.0f);
cloud_in->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_in->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
std::cout << "Saved " << cloud_in->points.size () << " data points to input:"
<< 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;
*cloud_out = *cloud_in;
std::cout << "size:" << cloud_out->points.size() << std::endl;
for (size_t i = 0; i < cloud_in->points.size (); ++i)
cloud_out->points[i].x = cloud_in->points[i].x + 0.7f;
std::cout << "Transformed " << cloud_in->points.size () << " data points:"
<< std::endl;
for (size_t i = 0; i < cloud_out->points.size (); ++i)
std::cout << " " << cloud_out->points[i].x << " " <<
cloud_out->points[i].y << " " << cloud_out->points[i].z << std::endl;
pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
icp.setInputCloud(cloud_in);
icp.setInputTarget(cloud_out);
pcl::PointCloud<pcl::PointXYZ> Final;
icp.align(Final);
std::cout << "has converged:" << icp.hasConverged() << " score: " <<
icp.getFitnessScore() << std::endl;
std::cout << icp.getFinalTransformation() << std::endl;
return (0);
}
#说明
为了帮助开发者更好地理解上述代码的逻辑结构,我们将对各个关键步骤进行细致的拆解与分析。
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/registration/icp.h>
首先,代码引入了必要的头文件。这些文件定义了后续代码中将要使用的所有核心类及其接口,确保了编译器和链接器能够正确识别PCL库中的相关组件,为算法的实现奠定了基础。
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out (new pcl::PointCloud<pcl::PointXYZ>);
接下来,程序创建了两个指向pcl::PointCloud<pcl::PointXYZ>类型的Boost共享指针,并对其进行初始化。这里明确指定了每个点的坐标类型为PointXYZ,这意味着点云数据仅包含X、Y、Z三个维度的空间坐标信息,而不包含颜色或法向量等额外属性,这种设定简化了计算过程,适用于纯几何形状的对齐任务。
// \brief A point structure representing Euclidean xyz coordinates.
struct PointXYZ
{
float x;
float y;
float z;
};
The lines:
// Fill in the CloudIn data
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 * rand () / (RAND_MAX + 1.0f);
cloud_in->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud_in->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
std::cout << "Saved " << cloud_in->points.size () << " data points to input:"
<< 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;
*cloud_out = *cloud_in;
std::cout << "size:" << cloud_out->points.size() << std::endl;
随后,代码利用随机生成的数值填充点云结构体,并配置了关键的元数据参数,包括点云的宽度、高度以及is_dense标志。is_dense标志用于指示点云是否包含NaN值,对于随机生成的测试数据,通常设置为false。此外,程序还会打印出当前保存的点数以及具体的坐标数据值,以便开发者直观地验证数据生成的正确性。
紧接着:
for (size_t i = 0; i < cloud_in->points.size (); ++i)
cloud_out->points[i].x = cloud_in->points[i].x + 0.7f;
std::cout << "Transformed " << cloud_in->points.size () << " data points:"
<< std::endl;
for (size_t i = 0; i < cloud_out->points.size (); ++i)
std::cout << " " << cloud_out->points[i].x << " " <<
cloud_out->points[i].y << " " << cloud_out->points[i].z << std::endl;
程序对初始点云执行了一次简单的刚性变换,这通常涉及旋转和平移操作。变换完成后,再次输出点云的数据值,以便对比变换前后的坐标变化,从而确认变换矩阵是否被正确应用。
pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
icp.setInputCloud(cloud_in);
icp.setInputTarget(cloud_out);
此步骤实例化了一个IterativeClosestPoint对象,并为其配置了必要的输入参数。其中,“icp.setInputCloud(cloud_in);”语句将cloud_in指定为源点云,即需要进行变换的对象;而“icp.setInputTarget(cloud_out);”则将cloud_out设定为目标点云,即源点云试图匹配的最终形态。这种设定明确了ICP算法的优化方向,即寻找一个变换矩阵,使源点云尽可能接近目标点云。
随后,
pcl::PointCloud<pcl::PointXYZ> Final;
icp.align(Final);
std::cout << "has converged:" << icp.hasConverged() << " score: " <<
icp.getFitnessScore() << std::endl;
std::cout << icp.getFinalTransformation() << std::endl;
代码创建了一个新的pcl::PointCloud<pcl::PointXYZ>对象,用于存储ICP算法执行完毕后生成的对齐点云。如果两个点云能够正确对齐——即它们本质上是同一几何形状,且仅存在刚性变换差异——那么调用icp.hasConverged()函数将返回1(true),表示算法成功收敛。此外,程序还会输出最终变换的拟合分数(fitness score),该分数反映了点对之间的平均距离,数值越小表示对齐效果越好,同时还会打印出关于变换矩阵的其他详细信息。
#编译和运行程序
为了成功构建该项目,您需要将以下配置行添加到项目的CMakeLists.txt文件中,以确保CMake能够正确链接PCL库并生成可执行文件:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(iterative_closest_point)
find_package(PCL 1.2 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
add_executable (iterative_closest_point iterative_closest_point.cpp)
target_link_libraries (iterative_closest_point ${PCL_LIBRARIES})
After you have made the executable, you can run it. Simply do:
./iterative_closest_point
You will see something similar to:
Saved 5 data points to input:
0.352222 -0.151883 -0.106395
-0.397406 -0.473106 0.292602
-0.731898 0.667105 0.441304
-0.734766 0.854581 -0.0361733
-0.4607 -0.277468 -0.916762
size:5
Transformed 5 data points:
1.05222 -0.151883 -0.106395
0.302594 -0.473106 0.292602
-0.0318983 0.667105 0.441304
-0.0347655 0.854581 -0.0361733
0.2393 -0.277468 -0.916762
[pcl::SampleConsensusModelRegistration::setInputCloud] Estimated a sample
selection distance threshold of: 0.200928
[pcl::IterativeClosestPoint::computeTransformation] Number of
correspondences 4 [80.000000%] out of 5 points [100.0%], RANSAC rejected:
1 [20.000000%].
[pcl::IterativeClosestPoint::computeTransformation] Convergence reached.
Number of iterations: 1 out of 0. Transformation difference: 0.700001
has converged:1 score: 1.95122e-14
1 4.47035e-08 -3.25963e-09 0.7
2.98023e-08 1 -1.08499e-07 -2.98023e-08
1.30385e-08 -1.67638e-08 1 1.86265e-08
0 0 0 1
