LCCP是Locally Convex Connected Patches的缩写
一、算法大致可以分成两个部分:
1.基于超体聚类的过分割。
2.在超体聚类的基础上再聚类。
超体聚类作为一种过分割方法,在理想情况下是不会引入错误信息的,也就是说适合在此基础上再进行处理。LCCP方法并不依赖于点云颜色,所以只使用空间信息和法线信息。
二、算法思路:
1.主要核心在CC(Extended Convexity Criterion) 和 SC (Sanity criterion)判据来进行判凹凸性
CC判据就是判别两个超体素的向量A和B与各自法向量之间的夹角,根据两个夹角对比进行判别
SC判据就是判别阈值与俩体素的夹角(这个夹角是通过求俩体素法向量的叉乘与中心连线d的夹角计算得来的)
2.在标记完各个小区域的凹凸关系后,则采用区域增长算法将小区域聚类成较大的物体。
3.至此,分割完成,在滤除多余噪声后即获得点云分割结果。
三、代码结构:
lccp_segmentation.cpp、lccp_segmentation.h、lccp_segmentation.hpp是PCL中LCCP的实现代码
mainwindow.cpp和mainwindow.h是QT窗口
mainwindow.cpp中默认参数:
粒子距离 = 0.0075f、晶核距离 = 0.3f 以及颜色容差 = 0.0f
if(lineVoxel->text()!=NULL &&
lineSeed->text()!=NULL){
voxel_resolution = this->lineVoxel->text().toFloat();
seed_resolution = this->lineSeed->text().toFloat();
color_importance = this->lineColor->text().toFloat();
}
else{
voxel_resolution = 0.0075f;
seed_resolution = 0.3f;
color_importance = 0.0f;
}
主要调用函数代码:void lccpSeg()
void mainwindow::lccpSeg()
{
clock_t startTime,endTime;
startTime = clock();
if(lineVoxel->text()!=NULL &&
lineSeed->text()!=NULL){
voxel_resolution = this->lineVoxel->text().toFloat();
seed_resolution = this->lineSeed->text().toFloat();
color_importance = this->lineColor->text().toFloat();
}
else{
voxel_resolution = 0.0075f;
seed_resolution = 0.3f;
color_importance = 0.0f;
}
//输入点云
pcl::PointCloud<PointT>::Ptr input_cloud_ptr(new pcl::PointCloud<PointT>);
pcl::PCLPointCloud2 input_pointcloud2;
if (pcl::io::loadPCDFile("milk_cartoon_all_small_clorox.pcd", input_pointcloud2))
{
PCL_ERROR("ERROR: Could not read input point cloud ");
return ;
}
pcl::fromPCLPointCloud2(input_pointcloud2, *input_cloud_ptr);
PCL_INFO("Done making cloud\n");
float spatial_importance = 1.0f;
float normal_importance = 4.0f;
bool use_single_cam_transform = false;
bool use_supervoxel_refinement = false;
unsigned int k_factor = 0;
//voxel_resolution is the resolution (in meters) of voxels used、seed_resolution is the average size (in meters) of resulting supervoxels
pcl::SupervoxelClustering<PointT> super(voxel_resolution, seed_resolution);
super.setUseSingleCameraTransform(use_single_cam_transform);
super.setInputCloud(input_cloud_ptr);
//Set the importance of color for supervoxels.
super.setColorImportance(color_importance);
//Set the importance of spatial distance for supervoxels.
super.setSpatialImportance(spatial_importance);
//Set the importance of scalar normal product for supervoxels.
super.setNormalImportance(normal_importance);
std::map<uint32_t, pcl::Supervoxel<PointT>::Ptr> supervoxel_clusters;
PCL_INFO("Extracting supervoxels\n");
super.extract(supervoxel_clusters);
PCL_INFO("Getting supervoxel adjacency\n");
std::multimap<uint32_t, uint32_t> supervoxel_adjacency;
super.getSupervoxelAdjacency(supervoxel_adjacency);
pcl::PointCloud<pcl::PointNormal>::Ptr sv_centroid_normal_cloud = pcl::SupervoxelClustering<PointT>::makeSupervoxelNormalCloud(supervoxel_clusters);
//LCCP分割
float concavity_tolerance_threshold = 20;
float smoothness_threshold = 0.1;
uint32_t min_segment_size = 0;
bool use_extended_convexity = false;
bool use_sanity_criterion = false;
PCL_INFO("Starting Segmentation\n");
pcl::LCCPSegmentation<PointT> lccp;
lccp.setConcavityToleranceThreshold(concavity_tolerance_threshold);
lccp.setSmoothnessCheck(true, voxel_resolution, seed_resolution, smoothness_threshold);
lccp.setKFactor(k_factor);
lccp.setInputSupervoxels(supervoxel_clusters, supervoxel_adjacency);
lccp.setMinSegmentSize(min_segment_size);
lccp.segment();
PCL_INFO("Interpolation voxel cloud -> input cloud and relabeling\n");
pcl::PointCloud<pcl::PointXYZL>::Ptr sv_labeled_cloud = super.getLabeledCloud();
pcl::PointCloud<pcl::PointXYZL>::Ptr lccp_labeled_cloud = sv_labeled_cloud->makeShared();
lccp.relabelCloud(*lccp_labeled_cloud);
SuperVoxelAdjacencyList sv_adjacency_list;
lccp.getSVAdjacencyList(sv_adjacency_list);
// Configure Visualizer
pcl::visualization::PCLVisualizer viewer = pcl::visualization::PCLVisualizer ("3D Viewer",false);
viewer.addPointCloud (lccp_labeled_cloud, "Segmented point cloud");
renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow = viewer.getRenderWindow();
qvtk->SetRenderWindow(renderWindow);
viewer.setupInteractor(qvtk->GetInteractor(),qvtk->GetRenderWindow());
qvtk->update();
qvtk->GetRenderWindow()->Render();
endTime = clock();
cout<<"The run time is :" << (double)(endTime-startTime)/CLOCKS_PER_SEC <<"s"<<endl;
}
显示效果: