PCl点云滤波(2)半径滤波、条件滤波、索引提取、投影滤波、模型滤波

6 篇文章 2 订阅
4 篇文章 1 订阅

1、半径滤波RadiusOutlierRemoval

1.1 所需头文件

#include <pcl/filters/radius_outlier_removal.h>

1.2 代码实现

/**
 *某个点半径范围内搜索邻域的点集个数能否满足设置点个数,不满足就是离群点。
*/
void pcdROR(pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);	//滤波后点云
	cout << "<-半径滤波->" << endl;
	pcl::RadiusOutlierRemoval<pcl::PointXYZ> ror;	//创建统计滤波器对象
	ror.setInputCloud(inputCloud);		//设置待滤波点云
	ror.setRadiusSearch(0.8);	// 设置查询点的半径范围
	ror.setMinNeighborsInRadius(30);// 设置判断是否为离群点的阈值,即半径内至少包括的点数
	ror.setNegative(true);//默认false,保存内点;true,保存滤掉的离群点
	ror.filter(*cloud_filtered);			//执行滤波,保存滤波结果在cloud_filtered

	cout << "\t\t<滤波后的点云信息>\n" << *cloud_filtered << endl;
	cout << "inputCloud - cloud_filtered = " << inputCloud->width * inputCloud->height - cloud_filtered->width * cloud_filtered->height << endl;
	viewPort2(inputCloud, cloud_filtered);
}

1.3 输出结果

在这里插入图片描述

2、条件滤波

2.1 所需头文件

#include <pcl/filters/conditional_removal.h>

2.2 代码实现

/*
ConditionAnd: 所有条件都要满足
ConditionOr: 满足一个条件即可
GT:大于		GE:大于等于
LT:小于		LE:小于等于
EQ:等于
*/
void pcdCondRemoval(pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);	//滤波后点云
	//创建条件限定下的滤波器
	pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_cond(new pcl::ConditionAnd<pcl::PointXYZ>());//创建条件定义对象range_cond
	//为条件定义对象添加比较算子
	range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new
		pcl::FieldComparison<pcl::PointXYZ>("y", pcl::ComparisonOps::GT, -3.0)));//添加在x字段上大于 -.1 的比较算子
	range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new
		pcl::FieldComparison<pcl::PointXYZ>("y", pcl::ComparisonOps::LT, 1.0)));//添加在x字段上小于 1.0 的比较算子
	pcl::ConditionalRemoval<pcl::PointXYZ> cr;	//创建滤波器对象
	cr.setCondition(range_cond);			//用条件定义对象初始化
	cr.setInputCloud(inputCloud);			//设置待滤波点云
	cr.setKeepOrganized(true);			//保持点云结构,即有序点云经过滤波后,仍能够保持有序性。(是否保留无效点云数据的位置信息)
	cr.setUserFilterValue(5);				//将过滤掉的点用(5,5,5)代替
	
	cr.filter(*cloud_filtered);				//执行滤波,保存滤波结果于cloud_filtered

	cout << "\t\t<滤波后的点云信息>\n" << *cloud_filtered << endl;
	cout << "inputCloud - cloud_filtered = " << inputCloud->width * inputCloud->height - cloud_filtered->width * cloud_filtered->height << endl;
	viewPort2(inputCloud, cloud_filtered);
}

2.3 输出结果
在这里插入图片描述

3、索引提取ExtractIndices

3.1 所需头文件

#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/filters/extract_indices.h>

3.2 代码实现

void pcdExtractIndices(pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);	//滤波后点云

	pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());	//创建分割时所需要的模型系数对象
	pcl::PointIndices::Ptr inliers(new pcl::PointIndices());		//创建存储内点的点索引集合对象
	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);									//设置判断是否为模型内点的距离阈值

	seg.setInputCloud(inputCloud);
	seg.segment(*inliers, *coefficients);//分割实现:存储分割结果到点集合inliers;存储平面模型系数coefficients
	if (inliers->indices.size() == 0)
	{
		PCL_ERROR("不能从给定的点云数据集中提取出平面模型!\n");
	}

	pcl::ExtractIndices<pcl::PointXYZ> extract;	//创建点云提取对象
	extract.setInputCloud(inputCloud);			//设置输入点云
	extract.setIndices(inliers);				//设置分割后的内点inliers为需要提取的点集
	extract.setNegative(false);					//设置提取内点而非外点,默认false
	extract.filter(*cloud_filtered);			//提取点集并存储到 cloud_filtered
	cout << "平面点集点的个数为:" << cloud_filtered->points.size() << endl;



	cout << "\t\t<滤波后的点云信息>\n" << *cloud_filtered << endl;
	cout << "inputCloud - cloud_filtered = " << inputCloud->width * inputCloud->height - cloud_filtered->width * cloud_filtered->height << endl;
	viewPort2(inputCloud, cloud_filtered);
}

3.3 输出结果
在这里插入图片描述

4、ProjectInliers投影滤波

4.1 所需头文件

#include <pcl/filters/project_inliers.h>

4.2 代码实现

/*
* 将点投影到一个参数化模型上,这个参数化模型可以是平面、圆球、圆柱、锥形等进行投影滤波
*/
//定义球的结构体
struct Sphere
{
	float center_x;
	float center_y;
	float center_z;
	float radius;
};
void pcdProjectInliers(pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);	//滤波后点云

	pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());	//创建分割时所需要的模型系数对象
	//创建一个平面  平面方程ax+by+cz+d=0; c!=0
	coefficients->values.resize(4);	//设置模型系数的大小
	coefficients->values[0] = 1.0;	//x系数
	coefficients->values[1] = 1.0;	//y系数
	coefficients->values[2] = 1.0;	//z系数
	coefficients->values[3] = 0.0;	//d
	//coefficients->values[0] = coefficients->values[1] = 0;
	//coefficients->values[2] = 1.0;
	//coefficients->values[3] = 0;
	//投影滤波
	pcl::ProjectInliers<pcl::PointXYZ> proj;//创建投影滤波器对象
	proj.setModelType(pcl::SACMODEL_PLANE);	//设置对象对应的投影模型
	proj.setInputCloud(inputCloud);				//设置输入点云
	proj.setModelCoefficients(coefficients);//设置模型对应的系数
	proj.filter(*cloud_filtered);			//执行投影滤波,存储结果于cloud_projected
	cout << "\t\t<滤波后的点云信息>\n" << *cloud_filtered << endl;
	cout << "inputCloud - cloud_filtered = " << inputCloud->width * inputCloud->height - cloud_filtered->width * cloud_filtered->height << endl;
	viewPort2(inputCloud, cloud_filtered);

	Sphere sp;
	sp.center_x = -0.0267599;
	sp.center_y = 0.0952158;
	sp.center_z = 0.00894712;
	sp.radius = 12;
	---------------------------------投影到球面----------------------------------
	//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected(new pcl::PointCloud<pcl::PointXYZ>);
	//cloud_projected->width = inputCloud->width;
	//cloud_projected->height = inputCloud->height;
	//cloud_projected->resize(inputCloud->size());
	//cloud_projected->is_dense = false;

	//for (size_t i = 0; i < inputCloud->points.size(); i++)
	//{
	//	float d = sqrt(pow(inputCloud->points[i].x, 2) + pow(inputCloud->points[i].y, 2) + pow(inputCloud->points[i].z, 2));

	//	cloud_projected->points[i].x = inputCloud->points[i].x * sp.radius / d + sp.center_x;
	//	cloud_projected->points[i].y = inputCloud->points[i].y * sp.radius / d + sp.center_y;
	//	cloud_projected->points[i].z = inputCloud->points[i].z * sp.radius / d + sp.center_z;
	//}
	//viewPort2(inputCloud, cloud_projected);
}

4.3 输出结果
投影到平面
在这里插入图片描述
投影到球面
在这里插入图片描述

5、ModelOutlierRemoval 模型滤波器

5.1 所需头文件

#include <pcl/filters/model_outlier_removal.h>

5.2 代码实现

/*
* ModelOutlierRemoval基于模型和点之间的距离过滤云中的点。
* 迭代整个输入一次,自动过滤非有限点和setSampleConsensusModelPointer()指定的模型之外的点,以及setThreholdFunctionPointer()指定的阈值
*/
void pcdModelOutlierRemoval(pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud)
{
	cout << "<-正在模型滤波->" << endl;
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);	//滤波后点云

	//设置模型系数
	pcl::ModelCoefficients model_coeff;
	model_coeff.values.resize(4);
	model_coeff.values[0] = 0.0;
	model_coeff.values[1] = 0.0;
	model_coeff.values[2] = 14.0;
	model_coeff.values[3] = 0.0;
	///模型滤波
	pcl::ModelOutlierRemoval<pcl::PointXYZ> filter;	//创建模型滤波器对象
	filter.setModelCoefficients(model_coeff);		//为模型对象添加模型系数
	filter.setThreshold(14);						//设置判断是否为模型内点的阈值
	filter.setModelType(pcl::SACMODEL_PLANE);		//设置模型类别
	filter.setInputCloud(inputCloud);				//输入待滤波点云
	filter.setNegative(false);						//默认false,提取模型内点;true,提取模型外点
	filter.filter(*cloud_filtered);					//执行模型滤波,保存滤波结果于cloud_filtered
	cout << "\t\t<滤波后的点云信息>\n" << *cloud_filtered << endl;
	cout << "inputCloud - cloud_filtered = " << inputCloud->width * inputCloud->height - cloud_filtered->width * cloud_filtered->height << endl;
	viewPort2(inputCloud, cloud_filtered);
}

5.3 输出结果
在这里插入图片描述
在这里插入图片描述

6、空间裁剪滤波 CropHull滤波器

6.1 所需头文件

#include <pcl/filters/crop_hull.h>
#include <pcl/surface/concave_hull.h>

6.2 代码实现

void pcdCropHull(pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud)
{
	cout << "<----- CropHull滤波器 ----->" << endl;
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);	//滤波后点云
	pcl::PointCloud<pcl::PointXYZ>::Ptr boundingbox(new pcl::PointCloud<pcl::PointXYZ>);	//封闭区域顶点
	pcl::PointCloud<pcl::PointXYZ>::Ptr surface_hull(new pcl::PointCloud<pcl::PointXYZ>);	//描述凸包形状的点云
	pcl::PointCloud<pcl::PointXYZ>::Ptr objects(new pcl::PointCloud<pcl::PointXYZ>);		//提取的封闭区域内部点云
	///设置封闭范围顶点
	boundingbox->push_back(pcl::PointXYZ(0.4, 0.4, 0.3));
	boundingbox->push_back(pcl::PointXYZ(0.8, -90, 45));
	boundingbox->push_back(pcl::PointXYZ(-10, 0.3, 50));
	boundingbox->push_back(pcl::PointXYZ(-0.5, 0.1, -1.1));
	boundingbox->push_back(pcl::PointXYZ(6, 9, 0));
	boundingbox->push_back(pcl::PointXYZ(0.1, -0.1, 0));
	boundingbox->push_back(pcl::PointXYZ(-0.1, 0.1, 0));
	boundingbox->push_back(pcl::PointXYZ(-9, -34, 67));
	boundingbox->push_back(pcl::PointXYZ(15, 0.1, 88));


	/*
	* hull 和 ch 维度要一致
	*/
	///构造凸包
	pcl::ConvexHull<pcl::PointXYZ> hull;//创建凸包对象
	hull.setInputCloud(boundingbox);	//设置输入点云:封闭区域顶点点云
	hull.setDimension(2);				//设置凸包维度
	std::vector<pcl::Vertices> polygons;//设置Vertices类型的向量,用于保存凸包顶点
	hull.reconstruct(*surface_hull, polygons);//计算凸包结果

	///CropHull滤波
	pcl::CropHull<pcl::PointXYZ> ch;//创建CropHull滤波对象
	ch.setDim(2);					//设置维度,与凸包维度一致
	ch.setInputCloud(inputCloud);	//设置需要滤波的点云
	ch.setHullIndices(polygons);	//输入封闭区域的顶点
	ch.setHullCloud(surface_hull);	//输入封闭区域的形状
	ch.filter(*objects);			//执行CropHull滤波,存储结果于objects

	cout << "\t<滤波后的点云信息>\n" << *cloud_filtered << endl;
	cout << "inputCloud - cloud_filtered = " << inputCloud->width * inputCloud->height - cloud_filtered->width * cloud_filtered->height << endl;

	pcl::PCDWriter writer;
	writer.write("polygons.pcd", *boundingbox, true);
	cout << "\t<封闭区域顶点点云信息>\n" << *boundingbox << endl;
	writer.write("surface_hull.pcd", *surface_hull, true);
	cout << "\t<封闭形状点云信息>\n" << *surface_hull << endl;
	writer.write("objects.pcd", *objects, true);
	cout << "\t<提取的点云信息>\n" << *objects << endl;
	viewPort2(inputCloud, objects);

6.3 输出结果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值