一、为什么要进行滤波?
在获取点云数据时,由于设备精度、操作者经验、环境因素等带来的影响,以及电磁波衍射特性、被测物体表面性质变化和数据拼接配准操作过程的影响,点云数据中将不可避免地出现一些噪声点。实际应用中除了这些测量随机误差产生的噪声点之外,由于受到外界干扰如视线遮挡、障碍物等因素的影响,点云数据中往往存在着一些离主体点云较远的离散点,即离群点。不同的获取设备点云噪声结构也有不同。
二、滤波的功能:
通过滤波完成的功能还包括孔洞修复、最小信息损失的海量点云数据压缩处理等 。在点云处理流程中滤波处理作为预处理的第一步,往往对后续处理流程影响很大,只有在滤波预处理中将噪声点、离群点、孔洞、数据压缩等 按照后续需求处理,才能够更好地进行配准、特征提取、曲面重建、可视化等后续流程。
三、直通滤波器:
直通滤波器主要的使用过程:
1、创建待处理点云对象,以及存储点云处理完成后的点云对象。
2、设置点云的容量:宽+高+长×宽;
3、设置点云内所有点的xyz坐标;
4、创建PassThroughFilter对象,并设置其滤波参数。
5、将待处理点云对象作为filter的输入进行滤波;
6、得到结果:在filter对象设置的x,y,z的范围之内的点将被保留,范围之外的点将被舍弃,实现直通滤波的功能
直通滤波器的作用:根据点云的属性在点的属性上设置范围,对点进行滤波,保留范围内的或保留范围外的.
通俗讲:点云数据有xyz三维坐标,选择一个方向的维度的数据,设置一个范围,在这个范围中的点云会被保留,不在此范围内的点云会被去除掉
直通滤波器核心代码:
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>); //滤波后点云
pcl::PassThrough<pcl::PointXYZ> pt; // 创建滤波器对象
pt.setInputCloud(cloud); //设置存入点云
pt.setFilterFieldName("x"); //设置滤波所需字段x
pt.setFilterLimits(-0.1, 1); //滤除在z轴方向上不在-0.1-1范围内的所有点
pt.setFilterLimitsNegative(false); //默认false,保留范围内的点云;true,保存范围外的点云
//pt.setKeepOrganized(true); //是否保持点云的组织结构(针对结构点云)
// 上面两行填写true代表滤除(-0.1, 1)范围外的点云;false代表滤除(-0.1, 1)范围内的点云;二者是内外互补;
pt.filter(*cloud_filtered); //执行滤波,并将滤波后点云保存到cloud_filtered中
// 存在疑问点:滤波的范围如何选取,如何根据pcd文件来设置直通滤波的范围
完整代码:
#include <pcl/io/pcd_io.h>
#include <pcl/filters/passthrough.h>
#include <pcl/visualization/cloud_viewer.h>
using namespace std;
int main()
{
//----------------------------------------- 加载点云 ----------------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); //待滤波点云
if (pcl::io::loadPCDFile("bunny.pcd", *cloud) < 0)
{
PCL_ERROR("点云文件不存在!\n");
system("pause");
return -1;
}
cout << "->加载点云个数:" << cloud->points.size() << endl;
//==========================================================================================
//----------------------------------------- 直通滤波 ----------------------------------------
cout << "->正在进行直通滤波..." << endl;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>); //滤波后点云
pcl::PassThrough<pcl::PointXYZ> pt; // 创建滤波器对象
pt.setInputCloud(cloud); //设置输入点云
pt.setFilterFieldName("x"); //设置滤波所需字段x
pt.setFilterLimits(-0.1, 1); //滤除在z轴方向上不在-0.1-1范围内的所有点
pt.setFilterLimitsNegative(false); //默认false,保留范围内的点云;true,保存范围外的点云
//pt.setKeepOrganized(true); //是否保持点云的组织结构(针对结构点云)
pt.filter(*cloud_filtered); //执行滤波,并将滤波后点云保存到cloud_filtered中
//去除 NaN 点(只针对结构点云。散乱点云不需要)
//vector<int> Idx;
//pcl::removeNaNFromPointCloud(*cloud_filtered, *cloud_filtered, Idx);
//==========================================================================================
//-------------------------------------- 可视化(可选) -------------------------------------
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("滤波前后对比"));
/*-----原始点云-----*/
int v1(0);
viewer->createViewPort(0.0, 0.0, 0.5, 1.0, v1); //设置第一个视口在X轴、Y轴的最小值、最大值,取值在0-1之间
viewer->setBackgroundColor(0, 0, 0, v1); //设置背景颜色,0-1,默认黑色(0,0,0)
viewer->addText("befor_filtered", 10, 10, "v1_text", v1);
viewer->addPointCloud<pcl::PointXYZ>(cloud, "befor_filtered_cloud", v1);
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "befor_filtered_cloud", v1);
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, "befor_filtered_cloud", v1);
/*-----滤波后点云-----*/
int v2(0);
viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);
viewer->setBackgroundColor(0.3, 0.3, 0.3, v2);
viewer->addText("after_filtered", 10, 10, "v2_text", v2);
viewer->addPointCloud<pcl::PointXYZ>(cloud_filtered, "after_filtered_cloud", v2);
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "after_filtered_cloud", v2);
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 0, 1, 0, "after_filtered_cloud", v2);
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
//boost::this_thread::sleep(boost::posix_time::microseconds(100000));
std::this_thread::sleep_for(std::chrono::microseconds(100000));
}
//==========================================================================================
return 0;
}