【PCL-13】圆柱型分割

背景:

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

思路:

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

运行结果:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值