Advertisement

迭代最近点的使用方法(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
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    

How to use iterative closest point

全部评论 (0)

还没有任何评论哟~