点云超体素聚类(Supervoxel Clustering)

今天学习这段 点云超体素聚类(Supervoxel Clustering) 的原理、代码逻辑和实际作用,帮你彻底理解:


一、先搞懂「超体素聚类」是做什么的?

简单说,它是一种 3D 点云的 “超像素” 分割算法:把点云分成许多 “超体素”(Supervoxel)—— 类似图像的 “超像素”,但在 3D 空间中。

  • 核心目标:用 “超体素” 替代原始点,减少后续处理的复杂度(比如分割、识别);
  • 优势:超体素能贴合物体边界,且分布均匀,让后续算法更高效、更准确。

二、算法原理:怎么生成 “超体素”?

超体素聚类基于 “体素云连接分割(VCCS)” 算法,步骤如下:

  1. 体素化与种子初始化

    • 把点云体素化(分成小立方体),用 voxel_resolution 控制体素大小;
    • 在体素中均匀撒 “种子点”,用 seed_resolution 控制种子间距(种子决定超体素的初始位置)。
  2. 区域生长(Region Growing)

    • 从种子点开始,逐步扩展超体素:计算当前体素与种子的 “特征距离”(融合空间、颜色、法向量信息);
    • 距离近的体素被合并到超体素中,直到无法扩展(达到搜索范围或无新体素)。
  3. 邻接关系维护

    • 超体素在 3D 空间中保持 26 - 邻接关系(共享面、边、顶点的体素视为相邻);

    • 用八叉树(Octree)高效维护体素的邻接关系,加速区域生长和后续处理。

      _images/supervoxel_clustering_adjacency.jpg

      ​ 从右到左,6(面)、18(面、边)和 26(面、边、顶点)的邻接关系

关键公式:特征距离计算

超体素扩展时,用以下公式计算 “特征距离”,决定是否合并体素:
_images/supervoxel_clustering_distance_eqn.png

  • Dc:颜色距离(RGB 空间的欧氏距离);

  • Ds:空间距离(体素与种子的欧氏距离);

  • Dn:法向量距离(法向量夹角的余弦距离);

  • wc,ws,wn:颜色、空间、法向量的权重(用户可调);

  • Rseed:种子间距(seed_resolution)。

    _images/supervoxel_clustering_parameters.jpg

    ​ 影响超体素聚类的各种尺寸参数。R_seed 和 R_voxel 必须由用户设置。


三、代码逐段拆解:每一步在干啥?

1. 头文件 & 类型定义
#include <pcl/console/parse.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/segmentation/supervoxel_clustering.h>

// VTK 用于绘制连线
#include <vtkPolyLine.h>

// 类型定义(简化代码)
typedef pcl::PointXYZRGBA PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
typedef pcl::PointNormal PointNT;
typedef pcl::PointCloud<PointNT> PointNCloudT;
typedef pcl::PointXYZL PointLT;
typedef pcl::PointCloud<PointLT> PointLCloudT;
  • 作用:引入必要的库(IO、可视化、超体素聚类等),定义点云类型(简化代码)。
2. 辅助函数:绘制超体素邻接关系
void addSupervoxelConnectionsToViewer (PointT &supervoxel_center,
                                       PointCloudT &adjacent_supervoxel_centers,
                                       std::string supervoxel_name,
                                       pcl::visualization::PCLVisualizer::Ptr & viewer)
{
  // VTK 数据结构:点、线、多边形
  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New ();
  vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New ();
  vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New ();

  // 添加“超体素中心”到“邻接超体素中心”的连线
  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);
  }

  // 构建 VTK 多边形数据
  vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New ();
  polyData->SetPoints (points);
  polyLine->GetPointIds  ()->SetNumberOfIds(points->GetNumberOfPoints ());
  for(unsigned int i = 0; i < points->GetNumberOfPoints (); i++)
    polyLine->GetPointIds ()->SetId (i,i);
  cells->InsertNextCell (polyLine);
  polyData->SetLines (cells);

  // 添加到可视化窗口
  viewer->addModelFromPolyData (polyData,supervoxel_name);
}
  • 作用:用 VTK 绘制 “超体素中心” 与 “邻接超体素中心” 的连线,展示超体素的邻接关系。
3. 主函数:流程控制
int main (int argc, char ** argv)
{
  // 解析命令行参数
  if (argc < 2)
  {
    pcl::console::print_error ("参数错误!用法:...\n");
    return (1);
  }

  // 加载点云
  PointCloudT::Ptr cloud (new PointCloudT);
  pcl::console::print_highlight ("加载点云...\n");
  if (pcl::io::loadPCDFile<PointT> (argv[1], *cloud))
  {
    pcl::console::print_error ("加载点云失败!\n");
    return (1);
  }

  // 参数设置(默认值 + 命令行解析)
  bool disable_transform = pcl::console::find_switch (argc, argv, "--NT");
  float voxel_resolution = 0.008f;   // 体素大小
  float seed_resolution = 0.1f;     // 种子间距
  float color_importance = 0.2f;    // 颜色权重
  float spatial_importance = 0.4f;  // 空间权重
  float normal_importance = 1.0f;   // 法向量权重

  // 配置超体素聚类
  pcl::SupervoxelClustering<PointT> super (voxel_resolution, seed_resolution);
  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;
  pcl::console::print_highlight ("提取超体素...\n");
  super.extract (supervoxel_clusters);
  pcl::console::print_info ("找到 %d 个超体素\n", supervoxel_clusters.size ());

  // 可视化准备
  pcl::visualization::PCLVisualizer::Ptr viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
  viewer->setBackgroundColor (0, 0, 0);

  // 显示体素中心
  PointCloudT::Ptr voxel_centroid_cloud = super.getVoxelCentroidCloud ();
  viewer->addPointCloud (voxel_centroid_cloud, "voxel centroids");
  viewer->setPointCloudRenderingProperties (...);

  // 显示带标签的体素
  PointLCloudT::Ptr labeled_voxel_cloud = super.getLabeledVoxelCloud ();
  viewer->addPointCloud (labeled_voxel_cloud, "labeled voxels");
  viewer->setPointCloudRenderingProperties (...);

  // 显示超体素法向量(可选)
  PointNCloudT::Ptr sv_normal_cloud = super.makeSupervoxelNormalCloud (supervoxel_clusters);
  // viewer->addPointCloudNormals (...); // 取消注释可显示法向量

  // 提取超体素邻接关系并可视化
  pcl::console::print_highlight ("获取超体素邻接关系...\n");
  std::multimap<std::uint32_t, std::uint32_t> supervoxel_adjacency;
  super.getSupervoxelAdjacency (supervoxel_adjacency);

  // 遍历邻接关系,绘制连线
  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 = ...; adjacent_itr != ...; ++adjacent_itr)
    {
      pcl::Supervoxel<PointT>::Ptr neighbor_supervoxel = ...;
      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);
  }
  return (0);
}
4. 关键步骤解释
  • 参数设置voxel_resolution 控制体素大小,seed_resolution 控制种子间距,color_importance/spatial_importance/normal_importance 控制超体素扩展的 “特征距离” 权重。
  • 超体素提取:用 SupervoxelClustering::extract 生成超体素,结果存在 supervoxel_clusters(标签 → 超体素指针的映射)。
  • 可视化:
    • voxel_centroid_cloud:体素中心(下采样后的点云);
    • labeled_voxel_cloud:带超体素标签的体素(颜色随机);
    • sv_normal_cloud:超体素的法向量(可选显示);
    • 邻接关系:用 addSupervoxelConnectionsToViewer 绘制超体素中心的连线,展示邻接关系。

四、运行流程

# 运行可执行文件(参数:点云文件 + 可选参数)
./supervoxel_clustering milk_cartoon_all_small_clorox.pcd --NT  
  • milk_cartoon_all_small_clorox.pcd:输入点云文件;
  • --NT:关闭单视角变换(适用于无序点云,如 LiDAR 扫描);
  • 可添加其他参数(如 -v 0.01 调整体素大小,-s 0.2 调整种子间距),观察超体素变化。

五、结合点云图理解

_images/supervoxel_clustering_results.jpg

上方点云图包含瓶子、纸盒等物体,超体素聚类的作用是:

  • 分割物体:每个物体被分成一个或多个超体素(颜色不同的区域);
  • 简化后续处理:用超体素替代原始点,后续算法(如识别、分割)只需处理少量超体素,效率更高;
  • 邻接关系:超体素之间的连线展示了它们的邻接关系(哪些超体素属于同一物体或相邻物体)。

可以尝试调整参数(如 seed_resolution),观察超体素的大小和数量变化 —— 比如增大 seed_resolution,超体素会更大、数量更少。


总结:核心知识点

  1. 算法思想:用 “区域生长” 生成超体素,融合空间、颜色、法向量信息,贴合物体边界。
  2. 关键参数:体素大小、种子间距、颜色 / 空间 / 法向量权重,决定超体素的形状和分布。
  3. 适用场景:点云分割、识别的预处理,减少计算量,提升算法效率。

如果想更深入,建议修改参数(如权重、分辨率),观察超体素的变化,或者尝试处理自己的点云数据~

Ps.
pcl官方文档点云聚类成超体素 - 理论入门 — 点云库 0.0 文档 — Clustering of Pointclouds into Supervoxels - Theoretical primer — Point Cloud Library 0.0 documentation

内容源自pcl官方文档Introduction — Point Cloud Library 0.0 documentation

本文为基于 PCL 官方文档的学习整理与个人理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值