在获取点云数据时 ,由于设备精度,操作者经验环境因素带来的影响,以及电磁波的衍射特性,被测物体表面性质变化和数据拼接配准操作过程的影响,点云数据中讲不可避免的出现一些噪声。在点云处理流程中滤波处理作为预处理的第一步,对后续的影响比较大,只有在滤波预处理中将噪声点 ,离群点,孔洞,数据压缩等按照后续处理定制,才能够更好的进行配准,特征提取,曲面重建,可视化等后续应用处理,PCL中点云滤波模块提供了很多灵活实用的滤波处理算法,例如:双边滤波,高斯滤波,条件滤波,直通滤波,基于随机采样一致性滤波, PCL中点云滤波的方案 PCL中总结了几种需要进行点云滤波处理情况,这几种情况分别如下: (1) 点云数据密度不规则需要平滑 (2) 因为遮挡等问题造成离群点需要去除 (3) 大量数据需要下采样 (4) 噪声数据需要去除 对应的方案如下: (1)按照给定的规则限制过滤去除点 (2) 通过常用滤波算法修改点的部分属性 (3)对数据进行下采样 双边滤波算法是通过取临近采样点和加权平均来修正当前采样点的位置,从而达到滤波效果,同时也会有选择剔除与当前采样点“差异”太大的相邻采样点,从而保持原特征的目的
pcl::ApproximateVoxelGrid< PointT > 类ApproximateVoxelGrid根据给定的点云形成三维体素栅格,并利用所有体素的中心点近似体素中包含的点集,这样完成下采样得到滤波结果,该类比较合适对海量点云数据在处理前进行压缩,提高算法效率
pcl::BilateralFilter< PointT > 类BilateralFilter是对双边滤波算法在点云上的实现,该类的实现利用的并非XYZ字段的数据进行,而是利用强度数据进行双边滤波算法的实现,所以在使用该类时点云的类型必须有强度字段,否则无法进行双边滤波处理,
pcl::BoxClipper3D< PointT >实现用一个原点为中心,XYZ各个方向尺寸为2 经过用户指定的仿射变换的立方体进行空间裁剪,通过设置一个仿射变换矩阵先对立方体进行变换处理,之后输出仿射变换后落在该立方体内的点
pcl::Clipper3D< PointT >是3D空间裁剪对象的基类
pcl::ConditionalRemoval< PointT >实现过滤满足一定的条件的点云数据,非常灵活,可以设置滤波条件
pcl::filters::Convolution< PointIn, PointOut > 实现卷积滤波处理
pcl::filters::GaussianKernel< PointInT, PointOutT > 是基于高斯核的卷积滤波实现 高斯滤波相当于一个具有平滑性能的低通滤波器
pcl::filters::GaussianKernelRGB< PointInT, PointOutT > 是附加RGB通道基于高斯核的卷积滤波实现,不仅考虑空间XYZ而且考虑RGB
等等类查询相关官方网站***********88
(1)在PCL 中使用直通滤波器对点云进行滤波处理应用实例
代码解析如下
#include <iostream>#include <pcl/point_types.h>#include <pcl/filters/passthrough.h>int
main (int argc, char** argv)
{
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 = 1024 * rand () / (RAND_MAX + 1.0f);
cloud->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
} 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 (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);
}
由于随机生成的点云,所以每次运行结果不一样,但是都会将点云中Z坐标在(0,1)范围外的点过滤掉
(2)使用VoxelGrid滤波器对点云进行下采样
使用体素化网格方法实现下采样,即减少点的数量 减少点云数据,并同时保存点云的形状特征,在提高配准,曲面重建,形状识别等算法速度中非常实用,PCL是实现的VoxelGrid类通过输入的点云数据创建一个三维体素栅格,容纳后每个体素内用体素中所有点的重心来近似显示体素中其他点,这样该体素内所有点都用一个重心点最终表示,对于所有体素处理后得到的过滤后的点云,这种方法比用体素中心逼近的方法更慢,但是对于采样点对应曲面的表示更为准确。
代码解释
voxel_grid.cpp
#include <iostream>#include <pcl/io/pcd_io.h>#include <pcl/point_types.h>#include <pcl/filters/voxel_grid.h>intmain (int argc, char** argv)
{ pcl::PCLPointCloud2::Ptr cloud (new pcl::PCLPointCloud2 ());
pcl::PCLPointCloud2::Ptr cloud_filtered (new pcl::PCLPointCloud2 ()); //点云对象的读取 pcl::PCDReader reader;
reader.read ("table_400.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 ("table_scene_lms400_downsampled.pcd", *cloud_filtered,
Eigen::Vector4f::Zero (), Eigen::Quaternionf::Identity (), false); return (0);
}
从输出的结果可以看出,过滤后的数据量大大减小了。打印结果如下
显示的结果图可以看出对比
原始点云与滤波后的点云可视化结果,明显的可以看出来,点的密度大小与整齐程度不同,虽然处理后的数据量大大减小,但是很明显所含有的形状特征和空间结构信息与原始点云差不多。