简介
最近开始接触点云的数据处理模块,点云做分割、检测、识别之前需要做大量的预处理操作。直通滤波算作最为简单、粗暴的一种滤波方式,就是直接对点云的X、Y、Z轴的点云坐标约束来进行滤波,可以约束只在Z轴,或者XYZ三个坐标轴共同约束来达到点云滤波效果。下面直接上代码进行简单解释:
代码示例
下面这段代码是直通滤波最为频繁使用的函数:该简单示例通过读取pcd点云数据进行操作,最后保存为pcd文件。通过使用cloudcompare软件来进行查看直通滤波后的效果。
#include <iostream>
#include <pcl/io/pcd_io.h>
#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>);
// Fill in the cloud data
pcl::PCDReader reader;
reader.read("16line.pcd", *cloud);
std::cerr << "Cloud before filtering: " << cloud->points.size() << std::endl;
// Create the filtering object
pcl::PassThrough<pcl::PointXYZ> pass; // 声明直通滤波
pass.setInputCloud(cloud); // 传入点云数据
pass.setFilterFieldName("z"); // 设置操作的坐标轴
pass.setFilterLimits(0.0, 3.0); // 设置坐标范围
// pass.setFilterLimitsNegative(true); // 保留数据函数
pass.filter(*cloud_filtered); // 进行滤波输出
std::cerr << "Cloud after filtering: " << cloud_filtered->points.size() << std::endl;
// save filterd data
pcl::PCDWriter writer;
writer.write("16line_filtered.pcd", *cloud_filtered, false);
return 0;
}
设置过滤x或者y轴方向的部分代码:
// Create the filtering object
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud(cloud);
pass.setFilterFieldName("x");
pass.setFilterLimits(-5.0, 5.0);
// pass.setFilterLimitsNegative(true);
pass.filter(*cloud_filtered2);
pass.setInputCloud(cloud_filtered2);
pass.setFilterFieldName("y");
pass.setFilterLimits(-5.0, 5.0);
pass.filter(*cloud_filtered3);
实验结果可视化
下面简单贴出直通滤波过滤的结果点云:


下面图片点云过滤是上一张图片的全局剩余的点云,这里在代码中的pass.setFilterLimitsNegative(true);就是这个功能作用,是否保存滤波的限制范围内的点云,默认为false,保存限制范围点云,true时候是相反。


在查阅学习pcl直通滤波的过程中,发现网上所说 的关于不仅限于对单一坐标轴的过滤,其实主要就是再一次进行目标坐标轴过滤即可,通过重复使用直通滤波就可以进行三维区间的滤波。下面贴上代码部分,只是简单的增加一些变量和重复操作,并无特别复杂的地方:
#include <iostream>
#include <pcl/io/pcd_io.h>
#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>);
// Fill in the cloud data
pcl::PCDReader reader;
reader.read("16line.pcd", *cloud);
std::cerr << "Cloud before filtering: " << cloud->points.size() << std::endl;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered2(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered3(new pcl::PointCloud<pcl::PointXYZ>);
// Create the filtering object
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud(cloud);
pass.setFilterFieldName("x");
pass.setFilterLimits(-5.0, 5.0);
// pass.setFilterLimitsNegative(true);
pass.filter(*cloud_filtered2);
// filter range Y-axis
pass.setInputCloud(cloud_filtered2);
pass.setFilterFieldName("y");
pass.setFilterLimits(-5.0, 5.0);
pass.filter(*cloud_filtered3);
// filter range Z-axis
pass.setInputCloud(cloud_filtered3);
pass.setFilterFieldName("z");
pass.setFilterLimits(-0.5, 3.0);
pass.filter(*cloud_filtered);
std::cerr << "Cloud after filtering: " << cloud_filtered->points.size() << std::endl;
// save filterd data
pcl::PCDWriter writer;
writer.write("16line_filtered.pcd", *cloud_filtered, false);
return 0;
}

通过简单添加直通滤波的几行代码,就可以选择是只是过滤XY轴的范围,还是XYZ三维空间的范围。其实就是接着上一次直通滤波的结果进行下一个坐标轴的过滤。

源码部分功能浅析
具体函数模块功能主要介绍:
pcl::PassThrough官方API接口有两种数据结构模式供你使用(在声明直通滤波时候):PointT或者是pcl::PCLPointCloud2。
官方给出的示例:
* pcl::PassThrough<PointType> ptfilter (true); // Initializing with true will allow us to extract the removed indices
* ptfilter.setInputCloud (cloud_in);
* ptfilter.setFilterFieldName ("x");
* ptfilter.setFilterLimits (0.0, 1000.0);
* ptfilter.filter (*indices_x);
* // The indices_x array indexes all points of cloud_in that have x between 0.0 and 1000.0
* indices_rem = ptfilter.getRemovedIndices ();
* // The indices_rem array indexes all points of cloud_in that have x smaller than 0.0 or larger than 1000.0
* // and also indexes all non-finite points of cloud_in
* ptfilter.setIndices (indices_x);
* ptfilter.setFilterFieldName ("z");
* ptfilter.setFilterLimits (-10.0, 10.0);
* ptfilter.setNegative (true);
* ptfilter.filter (*indices_xz);
* // The indices_xz array indexes all points of cloud_in that have x between 0.0 and 1000.0 and z larger than 10.0 or smaller than -10.0
* ptfilter.setIndices (indices_xz);
* ptfilter.setFilterFieldName ("intensity");
* ptfilter.setFilterLimits (FLT_MIN, 0.5);
* ptfilter.setNegative (false);
* ptfilter.filter (*cloud_out);
* // The resulting cloud_out contains all points of cloud_in that are finite and have:
* // x between 0.0 and 1000.0, z larger than 10.0 or smaller than -10.0 and intensity smaller than 0.5.
小结
直通滤波比较简单粗暴的滤除点云的方式,实际运用中一般是作为第一步来进行点云的初步筛选与限制。可能你会觉得使用直通滤波不太智能化,要是对多个坐标轴进行滤波要操作多次的过程,那么你可以选择使用条件滤波来满足你的需求。下一篇就会介绍条件滤波。
参考
https://pcl-tutorials.readthedocs.io/en/pcl-1.11.0/passthrough.html#passthrough