PCL点云:点云分割_采样一致性分割_圆柱体分割_实例1

  • pcd文件在我的下载中 0 c币

  • 流程为:

  • 原始点云为:
    在这里插入图片描述

  • 直通滤波处理
    在这里插入图片描述

  • 分别分离出平面和圆柱体

  • 在这里插入图片描述
    在这里插入图片描述

#include <iostream>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization/pcl_visualizer.h>

#include <pcl/ModelCoefficients.h>             //模型的头文件
#include <pcl/filters/extract_indices.h>       //按索引进行提取的滤波
#include <pcl/filters/passthrough.h>           //直通滤波
#include <pcl/features/normal_3d.h>          
#include <pcl/sample_consensus/model_types.h>  //分割模型
#include <pcl/sample_consensus/method_types.h> //分割方法
#include <pcl/segmentation/sac_segmentation.h> //随机采样一致性的分割

int main() {
    
    
	/*
	* 读取点云
	*/
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::io::loadPCDFile("table_scene_mug_stereo_textured.pcd", *cloud);
	std::cout << "读取了点云 size = " << cloud->size() << std::endl;

	/*
	* 直通滤波处理点云
	* 去除无效的部分
	* 处理完成后还剩下一个杯子和一个平面
	* 并把处理好的点云放到 cloud_filtered
	*/
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
	//直通滤波
	pcl::PassThrough<pcl::PointXYZ> pass;
	//输入的点云
	pass.setInputCloud(cloud);
	//设置处理字段是Z轴 范围是 z = (0 ,1.2) 
	pass.setFilterFieldName("z");
	pass.setFilterLimits(0, 1.2);
	pass.setFilterLimitsNegative(false); //true = 过滤区间内的点  false = 过滤区间外的点
	pass.filter(*cloud_filtered);
	std::cout << "直通滤波处理后的点云 size = " << cloud_filtered->size() << std::endl;

	/*
	* 采用基于法线估计的方法 先分割出平面
	*/
	//存放法线结构的点云
	pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
	//法线评估对象
	pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
	//kd搜索树
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
	ne.setInputCloud(cloud_filtered);
	ne.setSearchMethod(tree);
	ne.setKSearch(50);   //搜索树的范围
	ne.compute(*cloud_normals);
	//基于法线的采样一致性分割  包括参数:索引,模型
	pcl::SACSegmentationFromNormals<pcl::PointXYZ, pcl::Normal> seg;
	//基于法线估计的平面分割模型 这个模型是一个有条件限制的平面模型
	//在规定的最大角度偏差限制下,每个局内的点的法线必须与所估计的平面的法线平行。
	pcl::PointIndices::Ptr inliers_plane(new pcl::PointIndices);
	pcl::ModelCoefficients::Ptr coefficients_plane(new pcl::ModelCoefficients);
	//参数优化
	seg.setOptimizeCoefficients(true);
	//输入	
	seg.setInputCloud(cloud_filtered);
	seg.setInputNormals(cloud_normals);
	//设置分割的模型
	seg.setModelType(pcl::SACMODEL_NORMAL_PLANE);
	//设置分割的方法
	seg.setMethodType(pcl::SAC_RANSAC);
	//设置法线相对权重 权重与距离成正比 与角度成反比
	seg.setNormalDistanceWeight(0.1);
	//设置最大迭代次数
	seg.setMaxIterations(100);
	//设置阈值
	seg.setDistanceThreshold(0.03);
	//分割
	seg.segment(*inliers_plane, *coefficients_plane);
	std::cout << "得到平面内的点 size = " << inliers_plane->indices.size() << std::endl;


	/*
	* 分别将平面和剩余部分 分离开
	*/
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_plane(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered2(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::Normal>::Ptr normals_plane(new pcl::PointCloud<pcl::Normal>);
	pcl::PointCloud<pcl::Normal>::Ptr normals_filtered2(new pcl::PointCloud<pcl::Normal>);
	//点提取对象和法向量提取对象
	pcl::ExtractIndices<pcl::PointXYZ> extract;
	extract.setInputCloud(cloud_filtered);
	extract.setIndices(inliers_plane);
	pcl::ExtractIndices<pcl::Normal> extract_normal;
	extract_normal.setInputCloud(cloud_normals);
	extract_normal.setIndices(inliers_plane);
	//处理平面
	extract.setNegative(false);
	extract.filter(*cloud_plane);
	extract_normal.setNegative(false);
	extract_normal.filter(*normals_plane);
	//处理剩下的部分
	extract.setNegative(true);
	extract.filter(*cloud_filtered2);
	extract_normal.setNegative(true);
	extract_normal.filter(*normals_filtered2);

	/*
	* 从filtered2中 提取圆柱体
	*/
	pcl::ModelCoefficients::Ptr coefficient_cylinder(new pcl::ModelCoefficients);
	pcl::PointIndices::Ptr inliers_cylinder(new pcl::PointIndices);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cylinder(new pcl::PointCloud<pcl::PointXYZ>);
	seg.setOptimizeCoefficients(true);
	seg.setModelType(pcl::SACMODEL_CYLINDER);
	seg.setMethodType(pcl::SAC_RANSAC);
	//设置表面法线权重系数
	seg.setNormalDistanceWeight(0.1);
	seg.setMaxIterations(10000);
	seg.setDistanceThreshold(0.05);
	//设置估计的圆柱体的半径范围
	seg.setRadiusLimits(0, 0.1);
	seg.setInputCloud(cloud_filtered2);
	seg.setInputNormals(normals_filtered2);
	seg.segment(*inliers_cylinder, *coefficient_cylinder);
	//提取出点云cloud_cylinder
	extract.setInputCloud(cloud_filtered2);
	extract.setIndices(inliers_cylinder);
	extract.setNegative(false);
	extract.filter(*cloud_cylinder);
	
	/*
	* 可视化
	*/
	pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("三个窗口"));
	int v1(0);
	int v2(1);
	int v3(2);
	//DDDD
	viewer->createViewPort(0.0, 0.0, 0.5, 1.0, v1);
	viewer->createViewPort(0.5, 0.0, 1.0, 0.5, v2);
	viewer->createViewPort(0.5, 0.5, 1.0, 1.0, v3);

	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_out_red(cloud, 255, 0, 0);
	viewer->addPointCloud(cloud, cloud_out_red, "cloud_out1", v1);

	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_out_green(cloud, 0, 255, 0); // 显示绿色点云
	viewer->addPointCloud(cloud_plane, cloud_out_green, "cloud_out2", v2);  // 平面

	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_out_blue(cloud, 0, 0, 255); // 显示蓝色点云
	viewer->addPointCloud(cloud_cylinder, cloud_out_blue, "cloud_out3", v3); // 圆柱

	viewer->spin();





	return 0;
}

おすすめ

転載: blog.csdn.net/weixin_42585456/article/details/121891676