【PCL】PCL点云分割圆柱体

本文介绍了如何在PCL库中使用SACSegmentationFromNormals类,结合RANSAC算法,基于法线信息对点云进行圆柱体分割的过程,包括数据预处理、模型估计和结果可视化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

在PCL中,可以使用pcl::SACSegmentationFromNormals类来实现圆柱体模型的分割。该类可以根据法线信息对点云进行分割,并提取出圆柱体点云。其原理是使用随机采样一致性(RANSAC)算法来估计圆柱体模型的参数,并从点云中提取圆柱体模型。该算法的基本流程如下:
**1、**过滤掉远离感兴趣区域的数据点。
**2、**估计每个点的表面法线。
**3、**使用RANSAC算法从点云中分割出平面模型,并保存。
**4、**使用RANSAC算法从点云中分割出圆柱体模型,并保存。

示例程序

#include <iostream>
#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.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>
#include <pcl/features/normal_3d.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/extract_indices.h>

int main()
{

	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::io::loadPCDFile("./Graphic/yuanzhu.pcd", *cloud_in);
	std::vector<pcl::PointIndices> clusters;
	int max_iterations = 500;
	double threshold = 1;
	float keepRatio = 0.2;
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out(new pcl::PointCloud<pcl::PointXYZ>);

	if (cloud_in->empty())
	{
		std::cout << "input cloud is empty";
		return -1;
	}

	// 创建圆柱模型的分割对象,并设置所有参数
	pcl::PassThrough<pcl::PointXYZ> pass;             //直通滤波对象
	pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;  //法线估计对象
	pcl::SACSegmentationFromNormals<pcl::PointXYZ, pcl::Normal> seg;    //分割对象

	pcl::ExtractIndices<pcl::PointXYZ> extract;      //点提取对象
	pcl::ExtractIndices<pcl::Normal> extract_normals;    ///点提取对象
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());

	pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
	pcl::ModelCoefficients::Ptr coefficients_cylinder(new pcl::ModelCoefficients);
	pcl::PointIndices::Ptr inliers_cylinder(new pcl::PointIndices);

	// Read in the cloud data
	std::cerr << "PointCloud has: " << cloud_in->points.size() << " data points." << std::endl;

	
	ne.setSearchMethod(tree);
	ne.setInputCloud(cloud_in);
	ne.setKSearch(30);
	ne.compute(*cloud_normals);


	// Create the segmentation object for cylinder segmentation and set all the parameters
	seg.setOptimizeCoefficients(true);   //设置对估计模型优化
	seg.setModelType(pcl::SACMODEL_CYLINDER);  //设置分割模型为圆柱形
	seg.setMethodType(pcl::SAC_RANSAC);       //参数估计方法
	seg.setNormalDistanceWeight(0.1);       //设置表面法线权重系数
	seg.setMaxIterations(1000);              //设置迭代的最大次数10000
	seg.setDistanceThreshold(0.5);         //设置内点到模型的距离允许最大值
	seg.setRadiusLimits(49, 51);             //设置估计出的圆柱模型的半径的范围
	seg.setInputCloud(cloud_in);
	seg.setInputNormals(cloud_normals);

	// Obtain the cylinder inliers and coefficients
	seg.segment(*inliers_cylinder, *coefficients_cylinder);
	std::cerr << "Cylinder coefficients: " << *coefficients_cylinder << std::endl;

	// Write the cylinder inliers to disk
	extract.setInputCloud(cloud_in);
	extract.setIndices(inliers_cylinder);
	extract.setNegative(false);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cylinder(new pcl::PointCloud<pcl::PointXYZ>());
	extract.filter(*cloud_out);
	if (cloud_out->points.empty())
		std::cerr << "Can't find the cylindrical component." << std::endl;
	else
	{
		std::cerr << "PointCloud representing the cylindrical component: "
			<< cloud_out->points.size() << " data points." << std::endl;
	}
	

	//可视化
	pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3d viewer"));
	//左边窗口显示输入的点云
	int v1(0);
	viewer->createViewPort(0, 0, 0.5, 1, v1);
	viewer->setBackgroundColor(0, 0, 0, v1);
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color_in(cloud_in, 255, 255, 255);
	viewer->addPointCloud<pcl::PointXYZ>(cloud_in, color_in, "cloud_in", v1);
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud_in", v1);

	//右边的窗口显示分割后的点云
	int v2(0);
	viewer->createViewPort(0.5, 0, 1, 1, v2);
	viewer->setBackgroundColor(0, 0, 0, v2);
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color_out(cloud_out, 0, 255, 0);
	viewer->addPointCloud<pcl::PointXYZ>(cloud_out,color_out,"cloud_out", v2);
	viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud_out", v2);

	while (!viewer->wasStopped())
	{
		viewer->spinOnce(100);
	}
	return 0;
}


测试结果

在这里插入图片描述

### PCL中RANSAC算法用于点云分割的不同类型 #### 平面拟合 在PCL库中,RANSAC常被用来进行平面拟合。此方法能够有效地从复杂的环境中分离出平坦表面,这对于室内场景分析特别有用。对于给定的一组3D点云数据,RANSAC随机选取三个不共线的点来构建一个假设的平面方程,并测试其余点到这个假定平面上的距离是否小于设定阈值。如果满足条件,则认为这些点属于同一个平面[^1]。 ```cpp pcl::SACSegmentation<pcl::PointXYZ> seg; seg.setOptimizeCoefficients (true); seg.setModelType (pcl::SACMODEL_PLANE); seg.setMethodType (pcl::SAC_RANSAC); seg.setMaxIterations (1000); seg.setDistanceThreshold (0.01); pcl::PointIndices::Ptr inliers (new pcl::PointIndices ()); pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients ()); seg.setInputCloud (cloud); seg.segment (*inliers, *coefficients); ``` #### 多平面拟合 当面对具有多个不同方向和平坦区域的对象时,单次运行标准RANSAC可能不足以完成整个物体的描述。因此,在某些情况下,需要连续执行几次RANSAC操作以检测并移除已发现的最大平面之后再继续寻找下一个显著平面直到不再有新的有效结果为止[^4]。 #### 直线拟合 除了平面外,RANSAC同样适用于其他类型的几何结构比如直线。通过调整模型参数设置为`SACMODEL_LINE`, 可实现对空间内线条特征的有效捕捉。这种方法尤其适合于建筑环境中的边缘提取或是机械零件轮廓重建等工作场合[^3]。 ```cpp // 更改模型类型为直线 seg.setModelType(pcl::SACMODEL_LINE); ``` #### 圆柱体和其他复杂形状 值得注意的是,虽然上述例子主要集中在简单几何实体上,但实际上PCL支持更广泛的形状匹配需求——包括但不限于圆锥形、球状物乃至任意自定义曲面等。这使得基于RANSAC框架下的点云处理技术具备高度灵活性与适应能力,广泛应用于各种实际项目当中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shanhedian2013

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值