PCL学习笔记——点云滤波(一)

本文介绍两种点云滤波方法:直通滤波PassThrough用于空间切割,仅保留设定范围内的点;VoxelGrid滤波器实现下采样,减少点云数据量同时保持形状特征。

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

本文主要借鉴于博主Being_young的文章https://blog.youkuaiyun.com/u013019296/article/details/70052319

一. 直通滤波PassThrough

对指定某一维度直接进行筛选过滤,实际上是一个空间切割,也就是只保留设定范围内的点,超出边界的就过滤掉了。

代码如下:

#include <iostream>
#include <ctime>
#include <pcl/point_types.h>
#include <pcl/filters/passthrough.h>
int
main(int argc, char** argv)
{
	srand(time(0));
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
	//填入点云数据
	cloud->width = 5;   //设置点云宽度或数量,此处为数量
	cloud->height = 1;  //设置点云高度或标准,此处为无序点云
	cloud->points.resize(cloud->width * cloud->height);
	for (size_t i = 0; i < cloud->points.size(); ++i)  //填充数据,由随机数产生
	{
		cloud->points[i].x = rand() / (RAND_MAX + 1.0f) - 0.5;    
		cloud->points[i].y = rand() / (RAND_MAX + 1.0f) - 0.5;
		cloud->points[i].z = rand() / (RAND_MAX + 1.0f) - 0.5;
	}
	std::cerr << "Cloud before filtering: " << std::endl;  //打印数据
	for (size_t i = 0; i < cloud->points.size(); ++i)
		std::cerr << "    " << cloud->points[i].x << " "
		<< cloud->points[i].y << " "
		<< cloud->points[i].z << std::endl;
	/************************************************************************************
  创建直通滤波器的对象,设立参数,滤波字段名被设置为Z轴方向,可接受的范围为(0.0,1.0)
  即将点云中所有点的Z轴坐标不在该范围内的点过滤掉或保留,这里是过滤掉,由函数setFilterLimitsNegative设定
  ***********************************************************************************/
	// 创建滤波器对象
	pcl::PassThrough<pcl::PointXYZ> pass;
	pass.setInputCloud(cloud);              //设置输入点云
	pass.setFilterFieldName("z");           //设置过滤时所需要点云类型的Z字段
	pass.setFilterLimits(0.0, 1.0);         //设置在过滤字段的范围
	pass.setFilterLimitsNegative(false);    //设置保留(false)范围内还是过滤掉(true)范围内(对范围取反)
	pass.filter(*cloud_filtered);           //执行滤波,保存过滤结果在cloud_filtered

	std::cerr << "Cloud after filtering: " << std::endl;  //打印结果
	for (size_t i = 0; i < cloud_filtered->points.size(); ++i)
		std::cerr << "    " << cloud_filtered->points[i].x << " "
		<< cloud_filtered->points[i].y << " "
		<< cloud_filtered->points[i].z << std::endl;

	return (0);
}

其中滤波器对象为:

pcl::PassThrough<pcl::PointXYZ> pass;
	pass.setInputCloud(cloud);              //设置输入点云
	pass.setFilterFieldName("z");           //设置过滤时所需要点云类型的Z字段
	pass.setFilterLimits(0.0, 1.0);         //设置在过滤字段的范围
	pass.setFilterLimitsNegative(false);    //设置保留(false)范围内还是过滤掉(true)范围内(对范围取反)
	pass.filter(*cloud_filtered);           //执行滤波,保存过滤结果在cloud_filtered

这里cloud就是需要过滤的点云,cloud_filtered就是过滤后的点云,使用setFilterFieldName来设置过滤Z轴,用setFilterLimits来设置范围,也就是只保留z坐标在0-1之间的点,其他的全部不要了。

注意此行代码:

pass.setFilterLimitsNegative(false); 

代表了是否显示被过滤掉的点,如果设置为true则将被过滤,设置为false则范围内将被保留,默认是false(即保留时可以直接注释掉此行代码)。

运行结果如下:
如图所示

二. 使用VoxelGrid滤波器对点云进行下采样

使用体素化网格方法实现下采样,即减少点的数量 减少点云数据,并同时保存点云的形状特征,在提高配准,曲面重建,形状识别等算法速度中非常实用,PCL是实现的VoxelGrid类通过输入的点云数据创建一个三维体素栅格,容纳后每个体素内用体素中所有点的重心来近似显示体素中其他点,这样该体素内所有点都用一个重心点最终表示,对于所有体素处理后得到的过滤后的点云,这种方法比用体素中心逼近的方法更慢,但是对于采样点对应曲面的表示更为准确。

代码如下:

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>


int
main(int argc, char** argv)
{

	pcl::PCLPointCloud2::Ptr cloud(new pcl::PCLPointCloud2());
	pcl::PCLPointCloud2::Ptr cloud_filtered(new pcl::PCLPointCloud2());

	//点云对象的读取,对应的pcd文件放在与程序名相同的文件内
	pcl::PCDReader reader;

	reader.read("table_scene_lms400.pcd", *cloud);    //读取点云文件中的数据到cloud对象中

	std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height
		<< " data points (" << pcl::getFieldsList(*cloud) << ").";

	/******************************************************************************
	创建一个叶大小为1cm的pcl::VoxelGrid滤波器,
	**********************************************************************************/
	pcl::VoxelGrid<pcl::PCLPointCloud2> sor;  //创建滤波对象
	sor.setInputCloud(cloud);                 //设置需要过滤的点云给滤波对象
	sor.setLeafSize(0.01f, 0.01f, 0.01f);     //设置滤波时创建的体素体积为1cm的立方体
	sor.filter(*cloud_filtered);              //执行滤波处理,存储输出

	std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height
		<< " data points (" << pcl::getFieldsList(*cloud_filtered) << ").";
	//最后将数据写入磁盘以作他用,例如可视化等
	pcl::PCDWriter writer;
	writer.write("squ4r filter.pcd", *cloud_filtered, Eigen::Vector4f::Zero(), Eigen::Quaternionf::Identity(), false);
	
	return (0);
}


运行结果如下(程序运行时间较长,耐心等待):
在这里插入图片描述
原点云数据为460400个,滤波后为41049个,而实际效果可以发现点的密度大小与整齐程度不同,虽然处理后的数据量大大减小,但是很明显所含有的形状特征和空间结构信息与原始点云差不多(可视化还不会,所以没有效果图。。)。

未完待续。

### PCL多线程点云滤波的实现方法与优化技巧 #### 1. 多线程支持概述 PCL(Point Cloud Library)提供了系列基于多线程的滤波器类,这些类继承自`pcl::Filter`并扩展了OpenMP的支持。通过设置线程数量,可以显著提升大规模点云数据处理的速度。具体来说,`*OMP`后缀的类表示该类已启用多线程功能[^3]。 #### 2. 常见多线程滤波器及其参数配置 以下是几种常见的多线程滤波器: ##### (1) **双边滤波** 双边滤波种既能平滑又能保留边缘特性的滤波方式,在PCL中可以通过`pcl::FastBilateralFilterOMP`实现。主要参数包括: - `setSigmaS(float sigma_s)`:定义空间邻域窗口的高斯标准差。 - `setSigmaR(float sigma_r)`:定义因深度差异而导致相邻像素权重下降的程度。 - `setNumberOfThreads(int threads)`:指定使用的线程数。 代码示例如下: ```cpp pcl::FastBilateralFilterOMP<pcl::PointXYZ> fbf; fbf.setInputCloud(cloud); fbf.setSigmaS(130); // 高斯标准差 fbf.setSigmaR(0.3f); // 控制权重衰减程度 fbf.setNumberOfThreads(4); // 设置线程数 fbf.filter(*cloud_filtered); ``` 此代码片段展示了如何使用多线程加速双边滤波过程[^2]。 ##### (2) **半径异常值移除** 对于去除点云中的孤立点或噪声点,`pcl::RadiusOutlierRemovalOMP`是个高效的选择。它会根据设定的球形区域内邻居点的数量决定是否保留某个点。关键参数为: - `setRadiusSearch(double radius)`:定义搜索半径。 - `setMinNeighborsInRadius(unsigned int min_neighbors)`:最小邻居点数目阈值。 代码示例: ```cpp #include "filters/radius_outlier_removal_omp.h" pcl::PointCloud<pcl::PointXYZ>::Ptr pcl_filter_radius_omp( pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in, float radius_search, int num ) { pcl::RadiusOutlierRemovalOMP<pcl::PointXYZ> radius; radius.setInputCloud(cloud_in); radius.setRadiusSearch(radius_search); radius.setMinNeighborsInRadius(num); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out(new pcl::PointCloud<pcl::PointXYZ>); radius.filter(*cloud_out); return cloud_out; } ``` 这段代码说明了如何利用多线程技术提高半径异常值移除效率[^3]。 #### 3. 性能优化建议 为了进步提升性能,可以从以下几个方面入手: - **合理分配线程资源**:过多的线程可能导致上下文切换开销增加,因此需测试不同硬件环境下的最佳线程数。 - **减少内存访问延迟**:确保输入点云数据结构紧凑,避免不必要的缓存未命中现象。 - **预计算辅助信息**:如果某些操作涉及重复计算(如距离矩阵),可提前完成这部分工作以节省时间。 #### 4. 结论 综上所述,借助PCL库内置的多线程机制能够有效改善点云滤波任务的表现。无论是简单的直通滤波还是复杂的双边滤波,都可以找到对应的`*OMP`版本加以应用[^1]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值