一、五种滤波器

直通滤波器: 对于在空间分布有一定空间特征的点云数据,比如使用线结构光扫描的方式采集点云,沿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;
}


直通滤波后的


python点云滤波代码 点云滤波方法_python点云滤波代码

体素滤波器结果41049

python点云滤波代码 点云滤波方法_标准差_02

统计滤波器

python点云滤波代码 点云滤波方法_标准差_03

条件滤波器

python点云滤波代码 点云滤波方法_python点云滤波代码_04

参考链接


http://www.pclcn.org/study/shownews.php?lang=cn&id=68