@[TOC]PCL中点云分割模块的学习
学习背景
参考书籍:《点云库PCL从入门到精通》以及官方代码PCL官方代码链接,,PCL版本为1.10.0,CMake版本为3.16,可用点云下载地址
学习内容
基于超体素的点云分割,如何使用 pcl::SupervoxelClustering以及如何使用和可视化邻接信息和超体素本身。 本文所用点云
源代码及所用函数
源代码
//基于超体素的点云分割
#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>
#include<vtkPolyLine.h>//vtk用于绘图头文件
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;
void addSupervoxelConnectionsToViewer(PointT &supervoxel_center,PointCloudT &adjacent_supervoxel_centers,
std::string supervoxel_name,pcl::visualization::PCLVisualizer::Ptr &viewer);
int main(int argc,char** argv)
{
/**********************************************提示消息************************************************/
if(argc<2)
{
pcl::console::print_error ("语法为: %s <pcd-file> \n "
"--NT 禁用单视图转换 \n"
"-v <体素分辨率>\n-s <种子分辨率>\n"
"-c <颜色的权重> \n-z <空间权重> \n"
"-n <法线的权重>\n", argv[0]);
return (1);
}
/***********************************************读取PCD文件******************************/
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;
bool voxel_res_specified = pcl::console::find_switch(argc,argv,"-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");
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"))
{
pcl::console::parse (argc, argv, "-c", color_importance);
}
float spatial_importance = 0.4f;
if (pcl::console::find_switch (argc, argv, "-z"))
{
pcl::console::parse (argc, argv, "-z", spatial_importance);
}
float normal_importance = 1.0f;
if (pcl::console::find_switch (argc, argv, "-n"))
{
pcl::console::parse (argc, argv, "-n", normal_importance);
}
/*************************************************超像素**********************************/
pcl::SupervoxelClustering<PointT> super(voxel_resolution,seed_resolution);//SupervoxelClustering 是 PCL 库中提供的一个类,用于将点云分割成超体素(supervoxels)。
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);//执行超体素分割算法,将点云分割为多个超体素,并将结果存储在 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();//超像素分割器super中获取体素质心点云,并将其存储在智能指针voxel_centroid_cloud中
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.getLabeledCloud();//从超像素分割器super中获取带有标签的体素点云,并将其存储在智能指针labeled_voxel_cloud中。
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);
pcl::console::print_highlight ("Getting supervoxel adjacency\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 = 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);
}
return 0;
}
void addSupervoxelConnectionsToViewer (PointT &supervoxel_center,
PointCloudT &adjacent_supervoxel_centers,
std::string supervoxel_name,
pcl::visualization::PCLVisualizer::Ptr & viewer)
{
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);
}
//创建一个多数据来存储所有内容
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);
}
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 (supervoxel_clustering supervoxel_clustering.cpp)
target_link_libraries (supervoxel_clustering ${PCL_LIBRARIES})#将PCL库链接到可执行文件目标。
运行结果
输入这行命令
./supervoxel_clustering milk_cartoon_all_small_clorox.pcd --NT
函数
- SupervoxelClustering 是 PCL 库中提供的一个类,用于将点云分割成超体素(supervoxels)。超体素是点云中的一些小区域,每个超体素内的点具有相似的特征,如颜色、法线等。通过超体素分割,可以将点云划分为多个有意义的区域,便于进一步的分析和处理。创建 SupervoxelClustering 对象时,需要指定两个参数:
- voxel_resolution:体素分辨率,即每个体素的大小。体素是三维空间中的立方体单元。较小的体素分辨率会生成更多的体素,从而得到更细粒度的超体素分割结果,但会增加计算量。
- seed_resolution:种子点分辨率,即每个超体素的种子点之间的最小距离。种子点是超体素的中心点,用于生成超体素。较小的种子点分辨率会生成更多的超体素,但会增加计算量。
std::map<std::uint32_t, pcl::Supervoxel<PointT>::Ptr>supervoxel_clusters;
这行代码定义了一个 std::map 类型的变量 supervoxel_clusters,用于存储超体素分割的结果。std::map 是 C++ 标准库中的一个关联容器,它以键值对的形式存储数据,其中每个键(key)都唯一地对应一个值(value)。在这里,std::map 的键类型是 std::uint32_t,表示超体素的标签(label),值类型是 pcl::Supervoxel::Ptr,表示指向超体素对象的智能指针。