一、五种滤波器
直通滤波器: 对于在空间分布有一定空间特征的点云数据,比如使用线结构光扫描的方式采集点云,沿z向分布较广,但x,y向的分布处于有限范围内。此时可使用直通滤波器,确定点云在x或y方向上的范围,可较快剪除离群点,达到第一步粗处理的目的。得知道要滤波方向上的范围。
体素滤波器:体素的概念类似于像素,使用包围盒将点云数据体素化,一般体素越密集的地方信息越多,噪音点及离群点可通过体素网格去除。另一方面如果使用高分辨率相机等设备对点云进行采集,往往点云会较为密集。过多的点云数量会对后续分割工作带来困难。体素滤波器可以达到向下采样同时不破坏点云本身几何结构的功能。
统计滤波器:考虑到离群点的特征,则可以定义某处点云小于某个密度,既点云无效。计算每个点到其最近的k个点平均距离。则点云中所有点的距离应构成高斯分布。给定均值与方差,可剔除3∑之外的点。
条件滤波:条件滤波器通过设定滤波条件进行滤波,有点分段函数的味道,当点云在一定范围则留下,不在则舍弃。和直通滤波器差不多,但更加灵活。
半径滤波器:半径滤波器与统计滤波器相比更加简单粗暴。以某点为中心画一个圆计算落在该圆中点的数量,当数量大于给定值时,则保留该点,数量小于给定值则剔除该点。 此算法运行速度快,依序迭代留下的点一定是最密集的,但是圆的半径和圆内点的数目都需要人工指定。
二、实验代码
以下5种滤波器,使用table_scene_lms400_inliers.pcd点云文件。在vs2017+pcl1.9.1环境下实验
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
#include "iostream"
using namespace std;
//输入、输出点云和可视化
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/filters/conditional_removal.h>
#include <pcl/filters/radius_outlier_removal.h>
int main()
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>("test.pcd", *cloud) == -1)
{
cout << "could not open file" << endl;
return -1;
}
cout << "原始点云的点数:" << cloud->points.size() << endl;
pcl::visualization::CloudViewer viewer("cloud_viewer");
viewer.showCloud(cloud);
system("pause");
//直通滤波
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_passthrough(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PassThrough<pcl::PointXYZ> pass; //定义一个滤波对象
pass.setInputCloud(cloud); //设定输入
pass.setFilterFieldName("z"); //设定滤波字段
pass.setFilterLimits(-1.3, 0); //保留z方向-1.3到0之间的 主要是调这个参数
//pass.setFilterLimitsNegative(true) //保留z方向-1.3到0之外的
pass.filter(*cloud_passthrough);
cout << "passthrough后的点数:" << cloud_passthrough->points.size() << endl;
viewer.showCloud(cloud_passthrough);
system("pause");
//体素滤波器实现下采样
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_voxelfrid(new pcl::PointCloud<pcl::PointXYZ>);
pcl::VoxelGrid<pcl::PointXYZ> voxelgrid;
voxelgrid.setInputCloud(cloud);
voxelgrid.setLeafSize(0.01f, 0.01f, 0.01f); //主要调节这个参数,体素的大小
voxelgrid.filter(*cloud_voxelfrid);
cout << "cloud_voxelfrid后的点数:" << cloud_voxelfrid->points.size() << endl;
viewer.showCloud(cloud_voxelfrid);
system("pause");
//统计滤波器
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_statistical(new pcl::PointCloud<pcl::PointXYZ>);
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> statistical;
statistical.setInputCloud(cloud);
statistical.setMeanK(50);
statistical.setStddevMulThresh(1); //标准差倍数设为1,这意味着如果一个点的距离超出平均距离一个标准差以上
statistical.setNegative(true);
statistical.filter(*cloud_statistical);
cout << "cloud_statistical后的点数:" << cloud_statistical->points.size() << endl;
viewer.showCloud(cloud_statistical);
system("pause");
//条件滤波器
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_Condition(new pcl::PointCloud<pcl::PointXYZ>);
pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_condition(new pcl::ConditionAnd<pcl::PointXYZ>());
range_condition->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new
pcl::FieldComparison<pcl::PointXYZ>("z", pcl::ComparisonOps::GT, -1.2))); //GT表示大于等于
range_condition->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new
pcl::FieldComparison<pcl::PointXYZ>("z", pcl::ComparisonOps::LT, 0.0))); //LT表示小于等于
pcl::ConditionalRemoval<pcl::PointXYZ> condition;
condition.setCondition(range_condition);
condition.setInputCloud(cloud); //输入点云
condition.setKeepOrganized(true); //保持点云结构
condition.filter(*cloud_Condition);
cout << "cloud_Condition后的点数:" << cloud_Condition->points.size() << endl;
viewer.showCloud(cloud_Condition);
system("pause");
//方法五:半径滤波器
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_Radius(new pcl::PointCloud<pcl::PointXYZ>);
pcl::RadiusOutlierRemoval<pcl::PointXYZ> radiusoutlier; //创建滤波器
radiusoutlier.setInputCloud(cloud); //设置输入点云
radiusoutlier.setRadiusSearch(0.1); //设置半径为100的范围内找临近点
radiusoutlier.setMinNeighborsInRadius(50); //设置查询点的邻域点集数小于2的删除
radiusoutlier.filter(*cloud_Radius);
cout << "cloud_Radius后的点数:" << cloud_Radius->points.size() << endl;
viewer.showCloud(cloud_Radius);
system("pause");
return 0;
}
直通滤波后的
体素滤波器结果41049
统计滤波器
条件滤波器
参考链接
http://www.pclcn.org/study/shownews.php?lang=cn&id=68