1.版本要求
版本: >PCL1.3
2.简介
有时我们想分割出点云中的圆柱体,比如汽车的*。ransac圆柱体分割是分割点云中圆柱体的方法之一,但目前通过本人实验发现ransac分割圆柱体并不可靠,算法鲁棒性很低,不像分割平面那样稳定可靠,因此建议大家在项目中不要使用此算法,如果实在想用,还请多测试检查算法可靠性。
3.数据
本例中使用的点云数据(test.pcd)请见百度网盘分享。
链接:https://pan.baidu.com/s/1-8jo148CSqBXO53hCrTCJw
提取码:kwm0
4.代码
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/features/normal_3d.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/visualization/cloud_viewer.h>
int main(int argc, char* argv[])
{
pcl::PCDReader reader;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
reader.read("test.pcd", *cloud); //读取点云
std::cerr << "test point cloud has: " << cloud->size() << " points." << std::endl;
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; //计算点云法向量
ne.setSearchMethod(tree); //使用kdtree搜索方法
ne.setInputCloud(cloud);
ne.setKSearch(5); //使用邻近5个点计算法向量
ne.compute(*cloud_normals);
pcl::ModelCoefficients::Ptr coefficients_cylinder(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers_cylinder(new pcl::PointIndices);
pcl::SACSegmentationFromNormals<pcl::PointXYZ, pcl::Normal> seg; //使用ransac分割圆柱体
seg.setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_CYLINDER); //分割模型设置为圆柱体
seg.setMethodType(pcl::SAC_RANSAC);
seg.setNormalDistanceWeight(0.05);
seg.setMaxIterations(10000); //迭代次数设置这么大是因为圆柱体不好分割,因此项目中慎用
seg.setDistanceThreshold(0.03);
seg.setRadiusLimits(0, 0.1); //半径都要设置的很精确,因此此算法鲁棒性并不高,项目中慎用
seg.setInputCloud(cloud);
seg.setInputNormals(cloud_normals);
seg.segment(*inliers_cylinder, *coefficients_cylinder);
std::cerr << "cylinder coefficients: " << *coefficients_cylinder << std::endl; //打印圆柱体几何模型系数
pcl::ExtractIndices<pcl::PointXYZ> extract;
extract.setInputCloud(cloud);
extract.setIndices(inliers_cylinder);
extract.setNegative(false);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cylinder(new pcl::PointCloud<pcl::PointXYZ>());
extract.filter(*cloud_cylinder); //抽取圆柱体点云
if (cloud_cylinder->points.empty())
{
std::cerr << "Can't find the cylindrical component." << std::endl;
}
pcl::visualization::PCLVisualizer viewer("Cloud Viewer");
int v1(0); //创建左窗口显式cloud1(原始点云)
viewer.createViewPort(0, 0, 0.5, 1.0, v1); //左右窗口大小划分,1:1
viewer.setBackgroundColor(0, 0, 0, v1);
viewer.addText("Cloud1", 2, 2, "Cloud1", v1); //窗口下的标题
pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> rgb1(cloud, "z");
viewer.addPointCloud<pcl::PointXYZ>(cloud, rgb1, "cloud1", v1);
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud1", v1);
int v2(1); //创建右窗口显示cloud2(圆柱体点云)
viewer.createViewPort(0.5, 0, 1.0, 1.0, v2); //左右窗口大小划分,1:1
viewer.setBackgroundColor(0, 0, 0, v2);
viewer.addText("Cloud2", 2, 2, "Cloud2", v2); //窗口下的标题
pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> rgb2(cloud_cylinder, "z");
viewer.addPointCloud<pcl::PointXYZ>(cloud_cylinder, rgb2, "cloud2", v2);
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud2", v2);
viewer.spin();
return (0);
}