【PCL】教程 supervoxel_clustering执行超体聚类并可视化点云数据及其聚类结果

发布于:2024-05-02 ⋅ 阅读:(26) ⋅ 点赞:(0)

283b84ee4b86bda667354bac4dc12739.png

[done, 417.125 ms : 307200 points]
Available dimensions: x y z rgba

源点云milk_cartoon_all_small_clorox.pcd

ec9bcf1d875d53a5d2b4874aaff95fef.png

> Loading point cloud...
> Extracting supervoxels!
Found 423 supervoxels
> Getting supervoxel adjacency

这段代码主要是使用PCL(Point Cloud Library)库来执行超体聚类(supervoxel clustering),并将结果显示在3D可视化工具中。现在我分步解释代码中的具体逻辑:

  1. 包含必要的头文件,这些文件用于点云处理和可视化。

  2. 定义使用的点云类型,例如pcl::PointXYZRGBA和pcl::PointNormal

  3. 声明一个函数addSupervoxelConnectionsToViewer用于在视图中添加超体聚类的连接

在main函数中,代码执行如下步骤:

a. 检查命令行参数,确保提供了点云数据文件。
b. 读取点云数据文件,将点云数据载入到PointCloudT类型的智能指针中。
c. 解析命令行参数,根据用户输入设置超体聚类的参数,如体素分辨率、种子分辨率、颜色重要性等
d. 使用pcl::SupervoxelClustering类型创建超体聚类对象,并配置聚类参数。
e. 调用extract方法进行聚类操作,并将聚类结果存储到一个map容器中。
f. 创建一个PCLVisualizer对象用于3D数据的可视化。
g. 将超体聚类的结果添加到可视化对象中,包括体素中心点云和标记的体素云。
h. 计算超体的邻接性,并通过vtkPolyLine来创建和添加显示超体之间连接关系的可视化元素。
i. 启动可视化循环,直到用户关闭3D视图。

最后addSupervoxelConnectionsToViewer函数负责给每一对超体中心和其邻接超体中心之间添加连线,进而在3D视图中形成超体聚类的可视化图。

总结来说,这段代码是一个完整的PCL应用程序,用于执行超体聚类并可视化点云数据及其聚类结果。它可以让用户通过命令行参数来指定不同的聚类参数,并且能够显示每个聚类体素的中心,以及聚类体素之间的连接情况。

#include <pcl/console/parse.h> // 导入PCL库的console模块,用于解析命令行参数
#include <pcl/point_cloud.h> // 导入PCL库的点云处理模块
#include <pcl/point_types.h> // 导入PCL库的点类型定义
#include <pcl/io/pcd_io.h> // 导入PCL库的PCD文件输入输出模块
#include <pcl/visualization/pcl_visualizer.h> // 导入PCL库的可视化模块
#include <pcl/segmentation/supervoxel_clustering.h> // 导入PCL库的SuperVoxel聚类模块


//VTK include needed for drawing graph lines
#include <vtkPolyLine.h> // 导入VTK库的PolyLine模块,用于绘制图形线条


// Types
typedef pcl::PointXYZRGBA PointT; // 定义PointT为pcl::PointXYZRGBA类型
typedef pcl::PointCloud<PointT> PointCloudT; // 定义PointCloudT为PointT类型的点云
typedef pcl::PointNormal PointNT; // 定义PointNT为点的法线类型
typedef pcl::PointCloud<PointNT> PointNCloudT; // 定义PointNCloudT为PointNT类型的点云
typedef pcl::PointXYZL PointLT; // 定义PointLT为带标签的点类型
typedef pcl::PointCloud<PointLT> PointLCloudT; // 定义PointLCloudT为PointLT类型的点云


void addSupervoxelConnectionsToViewer (PointT &supervoxel_center,
                                       PointCloudT &adjacent_supervoxel_centers,
                                       std::string supervoxel_name,
                                       pcl::visualization::PCLVisualizer::Ptr & viewer); // 声明函数addSupervoxelConnectionsToViewer,用于向可视化视图中添加超体连接




int
main (int argc, char ** argv) // 主函数
{
  if (argc < 2) // 检查命令行参数数量是否小于2
  {
    pcl::console::print_error ("Syntax is: %s <pcd-file> \n "
                                "--NT Disables the single cloud transform \n"
                                "-v <voxel resolution>\n-s <seed resolution>\n"
                                "-c <color weight> \n-z <spatial weight> \n"
                                "-n <normal_weight>\n", argv[0]); // 打印错误信息和使用说明
    return (1); // 返回错误代码
  }


  PointCloudT::Ptr cloud (new PointCloudT); // 创建一个PointCloudT类型的智能指针
  pcl::console::print_highlight ("Loading point cloud...\n"); // 打印加载点云的提示信息
  if (pcl::io::loadPCDFile<PointT> (argv[1], *cloud)) // 加载PCD文件
  {
    pcl::console::print_error ("Error loading cloud file!\n"); // 打印加载文件错误信息
    return (1); // 返回错误代码
  }


  bool disable_transform = pcl::console::find_switch (argc, argv, "--NT"); // 查找命令行参数中的`--NT`选项


  float voxel_resolution = 0.008f; // 设置体素分辨率的默认值
  bool voxel_res_specified = pcl::console::find_switch (argc, argv, "-v"); // 查找命令行参数中的`-v`选项
  if (voxel_res_specified) // 如果指定了体素分辨率
    pcl::console::parse (argc, argv, "-v", voxel_resolution); // 解析体素分辨率的值


  float seed_resolution = 0.1f; // 设置种子分辨率的默认值
  bool seed_res_specified = pcl::console::find_switch (argc, argv, "-s"); // 查找命令行参数中的`-s`选项
  if (seed_res_specified) // 如果指定了种子分辨率
    pcl::console::parse (argc, argv, "-s", seed_resolution); // 解析种子分辨率的值


  float color_importance = 0.2f; // 设置颜色重要性的默认值
  if (pcl::console::find_switch (argc, argv, "-c")) // 查找命令行参数中的`-c`选项
    pcl::console::parse (argc, argv, "-c", color_importance); // 解析颜色重要性的值


  float spatial_importance = 0.4f; // 设置空间重要性的默认值
  if (pcl::console::find_switch (argc, argv, "-z")) // 查找命令行参数中的`-z`选项
    pcl::console::parse (argc, argv, "-z", spatial_importance); // 解析空间重要性的值


  float normal_importance = 1.0f; // 设置法线重要性的默认值
  if (pcl::console::find_switch (argc, argv, "-n")) // 查找命令行参数中的`-n`选项
    pcl::console::parse (argc, argv, "-n", normal_importance); // 解析法线重要性的值


  // 以下是使用SuperVoxels的示例代码
  pcl::SupervoxelClustering<PointT> super (voxel_resolution, seed_resolution); // 创建一个SupervoxelClustering对象
  if (disable_transform) // 检查是否禁用了单一视角变换
    super.setUseSingleCameraTransform (false); // 禁用单一视角变换
  super.setInputCloud (cloud); // 设置输入的点云
  super.setColorImportance (color_importance); // 设置颜色重要性
  super.setSpatialImportance (spatial_importance); // 设置空间重要性
  super.setNormalImportance (normal_importance); // 设置法线重要性


  std::map <std::uint32_t, pcl::Supervoxel<PointT>::Ptr > supervoxel_clusters; // 创建一个map,用于存储超体聚类的结果


  pcl::console::print_highlight ("Extracting supervoxels!\n"); // 打印提取超体的提示信息
  super.extract (supervoxel_clusters); // 提取超体聚类
  pcl::console::print_info ("Found %d supervoxels\n", supervoxel_clusters.size ()); // 打印找到的超体数量


  pcl::visualization::PCLVisualizer::Ptr viewer (new pcl::visualization::PCLVisualizer ("3D Viewer")); // 创建一个3D可视化视图
  viewer->setBackgroundColor (0, 0, 0); // 设置背景颜色为黑色


  PointCloudT::Ptr voxel_centroid_cloud = super.getVoxelCentroidCloud (); // 获取体素中心点云
  viewer->addPointCloud (voxel_centroid_cloud, "voxel centroids"); // 将体素中心点云添加到可视化视图中
  viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE,2.0, "voxel centroids"); // 设置点云的点大小
  viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY,0.95, "voxel centroids"); // 设置点云的透明度


  PointLCloudT::Ptr labeled_voxel_cloud = super.getLabeledVoxelCloud (); // 获取带标签的体素点云
  viewer->addPointCloud (labeled_voxel_cloud, "labeled voxels"); // 将带标签的体素点云添加到可视化视图中
  viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY,0.8, "labeled voxels"); // 设置点云的透明度


  PointNCloudT::Ptr sv_normal_cloud = super.makeSupervoxelNormalCloud (supervoxel_clusters); // 生成超体法线点云
  // 下面的代码行被注释掉了,如果需要查看超体法线,请取消注释
  //viewer->addPointCloudNormals<PointNormal> (sv_normal_cloud,1,0.05f, "supervoxel_normals");


  pcl::console::print_highlight ("Getting supervoxel adjacency\n"); // 打印获取超体邻接信息的提示信息
  std::multimap<std::uint32_t, std::uint32_t> supervoxel_adjacency; // 创建一个multimap,用于存储超体邻接信息
  super.getSupervoxelAdjacency (supervoxel_adjacency); // 获取超体邻接信息
  // 为了生成超体邻接图,需要遍历超体邻接信息的multimap
  for (auto label_itr = supervoxel_adjacency.cbegin (); label_itr != supervoxel_adjacency.cend (); ) // 遍历超体邻接信息
  {
    // 首先获取标签
    std::uint32_t supervoxel_label = label_itr->first;
    // 然后获取对应标签的超体
    pcl::Supervoxel<PointT>::Ptr supervoxel = supervoxel_clusters.at (supervoxel_label);


    // 现在需要遍历邻接的超体,并且创建他们的中心点云
    PointCloudT adjacent_supervoxel_centers;
    for (auto adjacent_itr = supervoxel_adjacency.equal_range (supervoxel_label).first; adjacent_itr!=supervoxel_adjacency.equal_range (supervoxel_label).second; ++adjacent_itr) // 遍历邻接的超体
    {
      pcl::Supervoxel<PointT>::Ptr neighbor_supervoxel = supervoxel_clusters.at (adjacent_itr->second);
      adjacent_supervoxel_centers.push_back (neighbor_supervoxel->centroid_); // 将邻接超体的中心点添加到点云中
    }
    // 现在为这个多边形创建一个名称
    std::stringstream ss;
    ss << "supervoxel_" << supervoxel_label;
    // 下面的函数在本教程的范围之外,基本上它只是从给定的点生成一个“星型”多边形网格
    addSupervoxelConnectionsToViewer (supervoxel->centroid_, adjacent_supervoxel_centers, ss.str (), viewer); // 向可视化视图中添加超体连接
    // 将迭代器向前移动到下一个标签
    label_itr = supervoxel_adjacency.upper_bound (supervoxel_label);
  }


  while (!viewer->wasStopped ()) // 当可视化视图没有被关闭时
  {
    viewer->spinOnce (100); // 每100毫秒旋转一次可视化视图
  }
  return (0); // 正常退出
}


void
addSupervoxelConnectionsToViewer (PointT &supervoxel_center,
                                  PointCloudT &adjacent_supervoxel_centers,
                                  std::string supervoxel_name,
                                  pcl::visualization::PCLVisualizer::Ptr & viewer) // addSupervoxelConnectionsToViewer函数定义
{
  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New (); // 创建一个vtkPoints对象
  vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New (); // 创建一个vtkCellArray对象
  vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New (); // 创建一个vtkPolyLine对象


  // 遍历所有邻接点,添加一个中心点到邻接点对
  for (auto adjacent_itr = adjacent_supervoxel_centers.begin (); adjacent_itr != adjacent_supervoxel_centers.end (); ++adjacent_itr) // 遍历邻接的超体中心点
  {
    points->InsertNextPoint (supervoxel_center.data); // 插入中心点
    points->InsertNextPoint (adjacent_itr->data); // 插入邻接点
  }
  // 创建一个polydata来存储一切
  vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New ();
  // 将点添加到数据集中
  polyData->SetPoints (points);
  polyLine->GetPointIds ()->SetNumberOfIds(points->GetNumberOfPoints ()); // 设置polyLine的点ID数量
  for(unsigned int i = 0; i < points->GetNumberOfPoints (); i++)
    polyLine->GetPointIds ()->SetId (i,i); // 为polyLine的每个点设置ID
  cells->InsertNextCell (polyLine); // 将polyLine添加到cells中
  // 将线添加到数据集中
  polyData->SetLines (cells);
  viewer->addModelFromPolyData (polyData,supervoxel_name); // 将模型从PolyData添加到可视化视图中
}

此代码主要演示了如何使用PCL库进行点云数据的读取、处理和超体聚类分析,以及如何使用VTK库进行可视化展示。代码主要包括点云数据的加载、超体聚类参数设置、超体聚类结果提取和显示,以及超体邻接关系的可视化展示。

pcl::SupervoxelClustering<PointT>
    super(voxel_resolution, seed_resolution);

2309011e78408db58aa7464b33cd29e6.png

PointCloudT::Ptr voxel_centroid_cloud =
      super.getVoxelCentroidCloud(); 
PointLCloudT::Ptr labeled_voxel_cloud =
      super.getLabeledVoxelCloud();
PointNCloudT::Ptr sv_normal_cloud =
      super.makeSupervoxelNormalCloud(supervoxel_clusters);
super.getSupervoxelAdjacency(supervoxel_adjacency);

8c1ef5d5855e0157909c1303e8175a79.png

超体聚类(supervoxel clustering)

cf39e232637593ad4a11524c6ac48faf.png