目录
一、原理分析
在点云数据的处理过程中,滤波处理是点云预处理的第一步,只有在滤波预处理中将噪声点、离群点、孔洞、数据压缩等按照后续处理定制,才能够更好地进行配准、特征提取、曲面重建、可视化等后续应用处理。PCL中点云滤波模块提供了很多滤波处理算法,例如双边滤波、高斯滤波、条件滤波、直通滤波、基于随机采样一致性滤波等。
需要进行点云滤波处理的情况:
滤波有以下三种形式
(1)噪声点、离群点
在获取点云数据时,由于设备精度、操作者经验、环境因素等带来的影响,点云数据中将不可避免地出现一些噪声点,除了由于测量随机误差产生的噪声点外,由于受到外界干扰如视线遮挡障碍物等因素的影响,点云数据中往往还存在着一些远离主体点云的点,即离群点
(2)因点云数据量太大需进行点云下采样,减少点云数量
(3)点云数据密度不规则需要进行平滑处理
二、代码示例
1、使用passthrough(直通)滤波器对点云进行滤波处理
直通滤波器就是在点云的属性上设置范围,对点云进行滤波,保留范围内的或保留范围外的。
(1)指定一个维度以及该维度下的值域
(2)遍历点云中的每个点,判断该点在指定维度上的取值是否在值域内,删除取值不在值域内的点
(3)遍历结束,留下的点即构成滤波后的点云
#include <iostream>
#include <ctime>
#include <pcl/point_types.h>
#include <pcl/filters/passthrough.h>
#include <pcl/visualization/pcl_visualizer.h>
//#include <pcl/io/pcd_io.h>
using namespace std;
int main()
{
srand((unsigned int)time(NULL));//用系统时间初始化随机种子,防止每次随机数都一样
//定义并实例化一个PointCloud指针对象(滤波前)
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
//定义并实例化一个PointCloud指针对象(滤波后)
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
//pcl::io::loadPCDFile("bunny.pcd", *cloud);//加载自己的数据
//1、利用随机数生成点云,作为滤波的输入点云数据,并将其打印到标准输出
cloud->width = 100;//点云数量
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);
cloud->points[i].y = rand() / (RAND_MAX + 1.0f);
cloud->points[i].z = rand() / (RAND_MAX + 1.0f) - 0.5;
}
//输出上一步填充的点云的坐标
cout << "滤波前:" << endl;
for (size_t i = 0; i < cloud->points.size(); ++i)
cout << " " << cloud->points[i].x << " "
<< cloud->points[i].y << " "
<< cloud->points[i].z << endl;
//2、接下来创建直通滤波器的对象,设置它的参数,滤波字段设置为Z轴方向,可接受的范围是(0.0,1.0),
//即将点云中点的z坐标不在该范围内的删除或保留,由函数setFilterLimitsNegative决定
pcl::PassThrough<pcl::PointXYZ> pass;// 创建滤波器对象
pass.setInputCloud(cloud); //设置输入点云
pass.setFilterFieldName("z"); //按照点云数据的Z字段(Z坐标)进行过滤
pass.setFilterLimits(0.0, 1.0); //设置在过滤字段的范围(z坐标0-1)
pass.setFilterLimitsNegative(true); //设置保留范围内还是过滤掉范围内, 默认为flase,可以注释掉。true为过滤范围内的,flase为过滤掉范围外的
pass.filter(*cloud_filtered); //执行滤波,将完成过滤操作的点云数据保存在cloud_filtered中
//3、打印输出完成过滤操作后的点云的坐标
cout << "滤波后:" << endl;
for (size_t i = 0; i < cloud_filtered->points.size(); ++i)
cout << " " << cloud_filtered->points[i].x << " "
<< cloud_filtered->points[i].y << " "
<< cloud_filtered->points[i].z << endl;
//4、可视化滤波前后的点云
pcl::visualization::PCLVisualizer viewer("点云滤波前后");// 创建视窗对象
//添加坐标系
viewer.addCoordinateSystem(20);
//创建左右窗口
int v1(0);
int v2(1);
viewer.createViewPort(0.0, 0.0, 0.5, 1, v1);
viewer.setBackgroundColor(0, 0, 0, v1);
viewer.createViewPort(0.5, 0.0, 1, 1, v2);
viewer.setBackgroundColor(0.5, 0.5, 0.5, v2);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_out_blue(cloud, 0, 0, 255); // 滤波前为蓝色点云
viewer.addPointCloud(cloud, cloud_out_blue, "cloud_out1", v1);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_out_red(cloud_filtered, 250, 0, 0); //滤波后为红色点云
viewer.addPointCloud(cloud_filtered, cloud_out_red, "cloud_out2", v2);
while (!viewer.wasStopped())
{
viewer.spinOnce();
}
system("pause");
return 0;
}
2、使用VoxelGrid(体素)滤波器对点云进行下采样
体素滤波器在实现下采样同时不破坏点云本身几何结构,但会移动点的位置。可以去除一定程度的噪音点及离群点,主要功能是用来下采样。