点云分割--RANSAC圆柱体分割

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);
}

5.效果

点云分割--RANSAC圆柱体分割
点云分割--RANSAC圆柱体分割

上一篇:javascript – 标准浏览器上Leaflet库中的最大标记数量是多少?


下一篇:第六周实验报告和总结