基于超体素的点云分割VCCS
体素云连通性分割算法VCCS(voxel cloud connectivity segmentation,VCCS)是一种超体素分割算法。将体素化点云过分割为多个集合,形成超体素。————>该算法的输入数据:点云
VCCS算法(点云体素化)步骤:
1.根据输入点云建立体素空间————根据设定的体素分辨率(体素半径)Rvoxel使用八叉树结构对输入的点云数据进行等分,将三维空间划分为1个体素化网络【点云数据中最大和最小坐标点为对角线建立包围盒、最小值点作为坐标轴起始点、记录所有点云体素的中心坐标】
2.在规则的网络上均匀的生成超体素种子,设定的超体素种子分辨率(超体素半径)Rseed要远大于Rvoxel。【Rseed又叫超体素半径、Rvoxel又叫体素半径】
Rseed决定超体素区域的大小,由于超体素包含多个体素,故Rseed>>Rvoxel。
Rseed越大,最后分割出来的结果中,超体素数目越少。
3.选择初始种子(在网络中选定一个距离网络中心最近的体素为种子体素),设定搜索范围Rsearch,记录该范围内的体素数目,当搜索范围内的体素数目超过设定的阈值时,就保留该种子点,否则删除该超体素种子点。将种子体素移动到它范围内部梯度最小的体素的位置,作为新的种子体素的位置。
4.以种子体素为起点,广度优先搜索(逐层搜索)邻近的体素。根据特征距离,对体素进行局部聚类【体素与此种子点的特征距离近,就将该体素与该种子点聚类一类】。迭代,直到将所有体素分配给超体素为止。
聚类是在39维特征空间中进行的:
x、y、z是空间坐标。L、a、b是CIELab空间颜色。FPFH1..33为快速点特征直方图的33个元素
FPFH是一种位置不变的特征,它利用点的k个最近邻组合来描述点的局部曲面模型性质。按照体素与超体素质心的最小归一化距离D最小原则将每个体素分配到超体素中。
Dc是CIELab颜色空间中的欧氏距离;Ds是空间距离;Dhik是快速点直方图空间中的距离
m是一个归一化常数;λ、μ和ε分别是颜色、空间和法向量的权重。
VCCS算法能够将完整的物体点云分割成一个个小的聚类点团,并对每一个聚类点团赋予一个标签值进行标记,然后将相邻超体素间的凹凸性作为相似性法则进行基于凸边的区域生长。实现点云分割,对分割后的数据赋予一个标签值,具有同一标签值的数据会显示同一颜色,最后根据标签值提取分割后的点云。
———————————————————————————————————————————
PCL库代码:
注意:1.环境是PCL1.9.1+VS2017
2.pcd文件的地址需要根据自己的实际位置修改
#include
#include
#include
#include
#include
#include
#include
#include
//VTK include needed for drawing graph lines
#include
using namespace pcl;
using namespace std;
//
typedef PointXYZ PointT;
typedef PointXYZL PointTL;
//邻接线条可视化
void addSupervoxelConnectionsToViewer(PointXYZRGBA &supervoxel_center,
PointCloud &adjacent_supervoxel_centers,
std::string supervoxel_name,
pcl::visualization::PCLVisualizer::Ptr & viewer)
{
vtkSmartPointer points = vtkSmartPointer::New();
vtkSmartPointer cells = vtkSmartPointer::New();
vtkSmartPointer polyLine = vtkSmartPointer::New();
//Iterate through all adjacent points, and add a center point to adjacent point pair
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);
}
// Create a polydata to store everything in
vtkSmartPointer polyData = vtkSmartPointer::New();
// Add the points to the dataset
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);
// Add the lines to the dataset
polyData->SetLines(cells);
viewer->addModelFromPolyData(polyData, supervoxel_name);
}
int main() {
//点云读取
PointCloud::Ptr cloud(new PointCloud);
io::loadPCDFile("D:\\data\\noww\\2f.pcd", *cloud);
//去噪声
StatisticalOutlierRemovalsor;
PointCloud::Ptr sor_cloud(new PointCloud);
sor.setInputCloud(cloud);
sor.setMeanK(10);
sor.setStddevMulThresh(1);
sor.filter(*sor_cloud);
//构建超体素
float voxel_resultion = 0.01f;
float seed_resultion = 0.1f;
float color_importance = 0.0f;
float spatial_importance = 0.4f;
float normal_importance = 5.0f;
SupervoxelClustering super(voxel_resultion, seed_resultion);
super.setInputCloud(sor_cloud);
super.setNormalImportance(normal_importance);
super.setColorImportance(color_importance);
super.setSpatialImportance(spatial_importance);
std::map::Ptr >supervoxl_clustering;
super.extract(supervoxl_clustering);
cout << "supervoxel number is" << supervoxl_clustering.size() << endl;
visualization::PCLVisualizer::Ptr viewer(new visualization::PCLVisualizer("VCCS"));
PointCloud::Ptr supervoxel_centroid_cloud = super.getVoxelCentroidCloud();
viewer->addPointCloud(supervoxel_centroid_cloud, "supervoxel_centroid_cloud");
viewer->setPointCloudRenderingProperties(visualization::PCL_VISUALIZER_POINT_SIZE, 1, "supervoxel_centroid_cloud");
viewer->setPointCloudRenderingProperties(visualization::PCL_VISUALIZER_OPACITY, 0.5, "supervoxel_centroid_cloud");
PointCloud::Ptr supervoxel_cloud = super.getLabeledVoxelCloud();
viewer->addPointCloud(supervoxel_cloud, "supervoxel_cloud");
viewer->setPointCloudRenderingProperties(visualization::PCL_VISUALIZER_POINT_SIZE, 5, "supervoxel_cloud");
viewer->setPointCloudRenderingProperties(visualization::PCL_VISUALIZER_OPACITY, 0.5, "supervoxel_cloud");
//可视化法向量
//PointCloud::Ptr supervoxel_normal=super.makeSupervoxelNormalCloud(supervoxl_clustering);
//viewer->addPointCloudNormals(supervoxel_normal, 1, 0.2, "123");
multimapSupervoxelAdjacency;
super.getSupervoxelAdjacency(SupervoxelAdjacency);
//获得体素点云的邻接单元
for (auto label_itr = SupervoxelAdjacency.cbegin(); label_itr != SupervoxelAdjacency.cend();)
{
uint32_t super_label = label_itr->first;//获取体素单元的标签
Supervoxel::Ptr super_cloud = supervoxl_clustering.at(super_label);//把对应标签内的点云、体素质心、以及质心对应的法向量提取出来
PointCloud adjacent_supervoxel_centers;
for (auto adjacent_itr = SupervoxelAdjacency.equal_range(super_label).first; adjacent_itr != SupervoxelAdjacency.equal_range(super_label).second; ++adjacent_itr) {
Supervoxel::Ptr neighbor_supervoxel = supervoxl_clustering.at(adjacent_itr->second);
adjacent_supervoxel_centers.push_back(neighbor_supervoxel->centroid_);
}
std::stringstream ss;
ss << "supervoxel_" << super_label;
addSupervoxelConnectionsToViewer(super_cloud->centroid_, adjacent_supervoxel_centers, ss.str(), viewer);
label_itr = SupervoxelAdjacency.upper_bound(super_label);
}
viewer->spin();
return 0;
}
———————————————————————————————————————————
论文:基于激光点云数据的数木枝叶分割和三维重建
VCCS算法中,体素分辨率Rvoxel=0.05m;种子分辨率Rseed=0.1m;颜色权重λ=1;空间分辨率μ=1;法向量权重ε=4时,生成的超体素效果最佳。