【PCL-13】圆柱型分割

本文介绍了一种使用点云数据处理的方法,首先通过法线估计和KdTree对点云进行处理,然后利用SACSegmentation从圆柱体模型中分割出料仓面,最后提取出非料仓壁部分的数据。

背景:

有一料仓点云数据,需祛除料仓壁,提取料仓面。

思路:

1、点云法线估计

typedef pcl::PointXYZ PointT;
pcl::NormalEstimation<PointT, pcl::Normal> ne;    // 法线估算对象
pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>());
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);

ne.setSearchMethod(tree);			//设置法线估计的方式为kdtree
ne.setInputCloud(cloud_filtered_vg);	//输入点云用于法线估计
ne.setKSearch(50);	  //设置k近邻点的个数为5
ne.compute(*cloud_normals);

2、构建圆柱形分割模型

#include <pcl/segmentation/sac_segmentation.h>

pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg;    // 分割器
pcl::ModelCoefficients::Ptr coefficients_cylinder(new pcl::ModelCoefficients);
pcl::PointIndices::Ptr inliers_cylinder(new pcl::PointIndices);

//创建用于圆柱体分割的分割对象,并设置所有参数
seg.setOptimizeCoefficients(true);
seg.setModelType(pcl::SACMODEL_CYLINDER);   // 设置分割模型为圆柱体
seg.setMethodType(pcl::SAC_RANSAC);         // 设置采用 RANSAC 算法进行参数估计
seg.setNormalDistanceWeight(0.1);           // 设置表面法线权重系数
seg.setMaxIterations(1000);                // 设置最大迭代次数 10000
seg.setDistanceThreshold(0.03);             // 设置内点到模型的最大距离 0.05m
seg.setRadiusLimits(0, 8.0);                // 设置圆柱体的半径范围 0 ~ 0.1m
seg.setInputCloud(cloud_filtered_vg);      //输入点云数据
seg.setInputNormals(cloud_normals);
seg.segment(*inliers_cylinder, *coefficients_cylinder);
std::cerr << "Cylinder coefficients: " << *coefficients_cylinder << std::endl;

3、提取数据

pcl::ExtractIndices<PointT> extract;        // 点提取对象
pcl::PCDWriter writer; 

// 将圆柱体外点写入磁盘
extract.setInputCloud(cloud_filtered_vg);
extract.setIndices(inliers_cylinder);
extract.setNegative(true);  //ture:提取圆柱体外数据,false:提取圆柱体内数据
pcl::PointCloud<PointT>::Ptr cloud_cylinder(new pcl::PointCloud<PointT>());
extract.filter(*cloud_cylinder);
writer.write("..\\testdata\\result\\data\\output_cloud.pcd", *cloud_cylinder, false);

完整示例代码:

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

typedef pcl::PointXYZ PointT;

int main(int argc, char *argv[]) {
	pcl::PCDReader reader;    // PCD 文件读取对象
	pcl::NormalEstimation<PointT, pcl::Normal> ne;    // 法线估算对象
	pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg;    // 分割器
	pcl::PCDWriter writer;                                       // PCD 文件写入对象
	pcl::ExtractIndices<PointT> extract;                         // 点提取对象
	pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>());

	pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
	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);

	// 读取点云数据
	reader.read("..\\testdata\\result\\data\\tong.pcd", *cloud);
	std::cerr << "PointCloud has: " << cloud->points.size() << " data points." << std::endl;

	//---------------------------------------体素滤波-------------------------------
	pcl::PointCloud<PointT>::Ptr cloud_filtered_vg(new pcl::PointCloud<PointT>);

	//pcl::ApproximateVoxelGrid<pcl::PointXYZ> sor;
	pcl::VoxelGrid<PointT> vg;
	vg.setInputCloud(cloud);
	vg.setLeafSize(0.2f, 0.2f, 0.2f);//单位为m
	vg.filter(*cloud_filtered_vg);
	pcl::io::savePCDFileASCII("..\\testdata\\result\\data\\vg.pcd", *cloud_filtered_vg);

	
	ne.setSearchMethod(tree);			//设置法线估计的方式为kdtree
	ne.setInputCloud(cloud_filtered_vg);	//输入过滤后的点云用于法线估计
	ne.setKSearch(50);	  //设置k近邻点的个数为50
	ne.compute(*cloud_normals);

	//创建用于圆柱体分割的分割对象,并设置所有参数
	seg.setOptimizeCoefficients(true);
	seg.setModelType(pcl::SACMODEL_CYLINDER);   // 设置分割模型为圆柱体
	seg.setMethodType(pcl::SAC_RANSAC);         // 设置采用 RANSAC 算法进行参数估计
	seg.setNormalDistanceWeight(0.1);           // 设置表面法线权重系数
	seg.setMaxIterations(1000);                // 设置最大迭代次数 10000
	seg.setDistanceThreshold(0.03);             // 设置内点到模型的最大距离 0.05m
	seg.setRadiusLimits(0, 8.0);                // 设置圆柱体的半径范围 0 ~ 0.1m
	seg.setInputCloud(cloud_filtered_vg);
	seg.setInputNormals(cloud_normals);
	seg.segment(*inliers_cylinder, *coefficients_cylinder);
	std::cerr << "Cylinder coefficients: " << *coefficients_cylinder << std::endl;

	// 将圆柱体外点写入磁盘
	extract.setInputCloud(cloud_filtered_vg);
	extract.setIndices(inliers_cylinder);
	extract.setNegative(true);
	pcl::PointCloud<PointT>::Ptr cloud_cylinder(new pcl::PointCloud<PointT>());
	extract.filter(*cloud_cylinder);
	if (cloud_cylinder->points.empty()) {
		std::cerr << "Can't find the cylindrical component." << std::endl;
	}
	else {
		std::cerr << "PointCloud representing the cylindrical component: " << cloud_cylinder->points.size()
			<< " data points." << std::endl;
		writer.write("..\\testdata\\result\\data\\output_cloud.pcd", *cloud_cylinder, false);
	}

	return 0;
}

运行结果:

### PCL 1.8.1 中的圆柱分割算法实现与使用 在 Point Cloud Library (PCL) 版本 1.8.1 中,圆柱分割通常通过 `SACSegmentation` 类来完成。该类实现了基于随机采样一致性(Sample Consensus, SAC) 的模型拟合方法。 #### 圆柱分割的具体实现 为了执行圆柱分割,可以采用如下代码: ```cpp #include <pcl/point_types.h> #include <pcl/io/pcd_io.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> int main(int argc, char** argv) { // 加载点云数据 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); if (pcl::io::loadPCDFile<pcl::PointXYZ>("your_point_cloud.pcd", *cloud) == -1) { std::cerr << "Couldn't read file \n"; return (-1); } // 创建法线估计对象并计算法线 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>()); ne.setInputCloud(cloud); ne.setSearchMethod(tree); pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>); ne.setRadiusSearch(0.03); // 设置半径范围内的邻域搜索参数 ne.compute(*normals); // 将原始点云和对应的法线组合成一个新的点云结构 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>); pcl::concatenateFields(*cloud, *normals, *cloud_with_normals); // 定义 SAC 分割pcl::SACSegmentationFromNormals<pcl::PointNormal, pcl::Normal> seg; pcl::ModelCoefficients::Ptr coefficients_cylinder(new pcl::ModelCoefficients()); pcl::PointIndices::Ptr inliers_cylinder(new pcl::PointIndices()); // 可选设置:最大迭代次数以及距离阈值 seg.setMaxIterations(10000); seg.setDistanceThreshold(.01); // 必要设置:指定模型类型为圆柱体,并提供输入数据集及其关联的表面法向量 seg.setModelType(pcl::SACMODEL_CYLINDER); seg.setMethodType(pcl::SAC_RANSAC); seg.setOptimizeCoefficients(true); seg.setInputCloud(cloud_with_normals); seg.setInputNormals(normals); // 设定最小曲率条件以过滤掉不符合要求的结果 seg.setMinPoints(1000); float eps_angle = static_cast<float>(M_PI / 4); // ±45度角作为允许的最大偏差角度 seg.setEpsAngle(eps_angle); // 执行分割过程 seg.segment(*inliers_cylinder, *coefficients_cylinder); if(inliers_cylinder->indices.size() == 0){ std::cout<<"No points detected as part of a cylinder."<<std::endl; return(-1); } } ``` 此段程序展示了如何加载一个 `.pcd` 文件格式的三维点云文件,接着创建了一个法线估算实例用于获取每个点处的方向信息[^2]。之后利用这些方向信息辅助进行更精确的几何特征匹配——即寻找最佳拟合给定点集合的圆柱形模型。最后一步则是调用 `seg.segment()` 函数来进行实际的数据处理工作,在这里会返回两个主要结果变量:一个是表示哪些索引位置上的点属于所发现的最佳拟合圆柱的一部分(`*inliers_cylinder`);另一个则包含了描述这个理想化圆柱形状所需的全部系数(`*coefficients_cylinder`)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值