09 filters滤波/降采样 (yuque.com)
理论
PCL中总结了几种需要进行点云滤波处理情况,这几种情况分别如下:
(1) 点云数据密度不规则需要平滑
(2) 因为遮挡等问题造成离群点需要去除
(3) 大量数据需要下采样
(4) 噪声数据需要去除
对应的方案如下:
(1)按照给定的规则限制过滤去除点
(2) 通过常用滤波算法修改点的部分属性
(3)对数据进行下采样
PCL点云格式分为有序点云和无序点云
- 针对有序点云提供了双边滤波、高斯滤波、中值滤波等
- 针对无序点云提供了体素栅格、随机采样等
是根据传感器的采集数据上来说
- 一般深度相机采集到的点云的数据是有序点云
- 而我们激光雷达采集的点云的数据是无序的点云
类&函数介绍
Classes | |
pcl::ApproximateVoxelGrid< PointT > 类ApproximateVoxelGrid根据给定的点云形成三维体素栅格,并利用所有体素的中心点近似体素 | |
中包含的点集,这样完成下采样得到滤波结果,该类比较合适对海量点云数据在处理前进行压缩,提高算法效率 | |
class | pcl::BilateralFilter< PointT > 类BilateralFilter是对双边滤波算法在点云上的实现,该类的实现利用的并非XYZ字段的数据进行,而是利用 |
强度数据进行双边滤波算法的实现,所以在使用该类时点云的类型必须有强度字段,否则无法进行双边滤波处理, | |
class | pcl::BoxClipper3D< PointT >实现用一个原点为中心,XYZ各个方向尺寸为2 经过用户指定的仿射变换的立方体进行空间裁剪,通过设置一个仿射变换矩阵先对立方体进行变换处理,之后输出仿射变换后落在该立方体内的点集 |
class | pcl::Clipper3D< PointT >是3D空间裁剪对象的基类 |
class | pcl::ConditionalRemoval< PointT >实现过滤满足一定的条件的点云数据,非常灵活,可以设置滤波条件 |
class | pcl::filters::Convolution< PointIn, PointOut > 实现卷积滤波处理 |
class | pcl::filters::ConvolvingKernel< PointInT, PointOutT > 是所有卷积核的基类 |
class | pcl::filters::GaussianKernel< PointInT, PointOutT > 是基于高斯核的卷积滤波实现 高斯滤波相当于一个具有平滑性能的低通滤波器 |
class | pcl::filters::GaussianKernelRGB< PointInT, PointOutT > 是附加RGB通道基于高斯核的卷积滤波实现,不仅考虑空间XYZ而且考虑RGB |
class | pcl::CropBox< PointT > 过滤掉在用户给定立方体内的点云数据 |
class | pcl::CropHull< PointT > 过滤在给定三维封闭曲面或二维封闭多边形内部或外部的点云数据 |
class | pcl::ExtractIndices< PointT > 从一个点云中提取索引 |
class | pcl::Filter< PointT > 是滤波模块最重要的类 其他所有的滤波模块的类都从它继承。 |
。。。。。。。。。。(还有很多) |
官方Tutorials
Filtering a PointCloud using a PassThrough filter 在PCL 中使用直通滤波器对点云进行滤波处理
Downsampling a PointCloud using a VoxelGrid filter 使用VoxelGrid滤波器对点云进行下采样
Removing outliers using a StatisticalOutlierRemoval filter 使用statisticalOutlierRemoval滤波器移除离群点
Projecting points using a parametric model 使用参数化模型投影点云
Extracting indices from a PointCloud 从一个点云中提取索引
Removing outliers using a Conditional or RadiusOutlier removal 用ConditionalRemoval 或RadiusOutlinerRemoval移除离群点
1 pcl::PassThrough直通滤波器进行滤波处理
/*
* @Description: 在PCL 中使用直通滤波器对点云进行滤波处理 https://www.cnblogs.com/li-yao7758258/p/6445831.html
* @Author: HCQ
* @Company(School): UCAS
* @Email: 1756260160@qq.com
* @Date: 2020-10-20 10:36:02
* @LastEditTime: 2020-10-20 10:45:57
* @FilePath: /pcl-learning/09filters滤波/1直通滤波器进行滤波处理/passthrough.cpp
*/
#include <iostream>
#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>);
//生成并填充点云
cloud->width = 5;
cloud->height = 1;
cloud->points.resize (cloud->width * cloud->height);
for (size_t i = 0; i < cloud->points.size (); ++i) //填充数据
{
cloud->points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
cloud->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
std::cerr << "Cloud before filtering: " << std::endl; //打印
for (size_t i = 0; i < cloud->points.size (); ++i)
std::cerr << " " << cloud->points[i].x << " "
<< cloud->points[i].y << " "
<< cloud->points[i].z << std::endl;
/************************************************************************************
创建直通滤波器的对象,设立参数,滤波字段名被设置为Z轴方向,可接受的范围为(0.0,1.0)
即将点云中所有点的Z轴坐标不在该范围内的点过滤掉或保留,这里是过滤掉,由函数setFilterLimitsNegative设定
***********************************************************************************/
// 设置滤波器对象
pcl::PassThrough<pcl::PointXYZ> pass;
pass.setInputCloud (cloud); //设置输入点云
pass.setFilterFieldName ("z"); //设置过滤时所需要点云类型的Z字段
pass.setFilterLimits (0.0, 1.0); //设置在过滤字段的范围
//pass.setFilterLimitsNegative (true); //设置保留范围内还是过滤掉范围内 是否保存滤波的限制范围内的点云,默认为false,保存限制范围内点云,true时候是相反。
pass.filter (*cloud_filtered); //执行滤波,保存过滤结果在cloud_filtered
std::cerr << "Cloud after filtering: " << std::endl; //打印
for (size_t i = 0; i < cloud_filtered->points.size (); ++i)
std::cerr << " " << cloud_filtered->points[i].x << " "
<< cloud_filtered->points[i].y << " "
<< cloud_filtered->points[i].z << std::endl;
return (0);
}
cmake_minimum_required ( VERSION 2.6 FATAL_ERROR) #对于cmake版本的最低版本的要求
project(ch2) #建立的工程名,例如源代码目录路径的变量名为CH_DIR
#工程存储目录变量名为CH_BINARY_DIR
#要求工程依赖的PCL最低版本为1.3,并且版本至少包含common和IO两个模块 这里的REQUIRED意味着如果对应的库找不到 则CMake配置的过程将完全失败,
#因为PCL是模块化的,也可以如下操作:
# 一个组件 find_package(PCL 1.6 REQUIRED COMPONENTS io)
# 多个组件 find_package(PCL 1.6 REQUIRED COMPONENTS commom io)
# 所有组件 find_package(PCL 1.6 REQUIRED )
find_package(PCL 1.3 REQUIRED)
#下面的语句是利用CMake的宏完成对PCL的头文件路径和链接路径变量的配置和添加,如果缺少下面几行,生成文件的过程中就会提示
#找不到相关的头文件,在配置CMake时,当找到了安装的PCL,下面相关的包含的头文件,链接库,路径变量就会自动设置
# PCL_FOUND:如果找到了就会被设置为1 ,否则就不设置
# PCL_INCLUDE_DIRS:被设置为PCL安装的头文件和依赖头文件的目录
# PCL_LIBRARIES:被设置成所建立和安装的PCL库头文件
# PCL_LIBRARIES_DIRS:被设置成PCL库和第三方依赖的头文件所在的目录
# PCL_VERSION:所找到的PCL的版本
# PCL_COMPONENTS:列出所有可用的组件
# PCL_DEFINITIONS:列出所需要的预处理器定义和编译器标志
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARIES_DIRS})
add_definitions(${PCL_DEFINITIONS})
#这句话告诉CMake从单个源文件write_pcd建立一个可执行文件
add_executable(write_pcd write_pcd.cpp)
#虽然包含了PCL的头文件,因此编译器知道我们现在访问所用的方法,我们也需要让链接器知道所链接的库,PCL找到库文件由
#PCL_COMMON_LIBRARIES变量指示,通过target_link_libraries这个宏来出发链接操作
target_link_libraries(write_pcd ${PCL_COMMON_LIBRARIES} ${PCL_IO_LIBRARIES})