赞
踩
**
主要工具:visual studio 2019 和cloudcompare(自行编译)
原因: (1) 点云数据密度不规则需要平滑
(2) 因为遮挡等问题造成离群点需要去除
(3) 大量数据需要下采样
(4) 噪声数据需要去除
去除离群点:①半径滤波②统计滤波
点云的平滑处理:①双边滤波 ②导向滤波
1. 直通滤波器(PassThrough 滤波) pcl::PassThroughpcl::PointXYZ pass
最简单的一种滤波器,它的作用是过滤掉在指定维度方向上取值不在给定值域内的点。直通滤波器的实现原理如下:首先,指定一个维度以及该维度下的值域,其次,遍历点云中的每个点,判断该点在指定维度上的取值是否在值域内,删除取值不在值域内的点,最后,遍历结束,留下的点即构成滤波后的点云。直通滤波器简单高效,适用于消除背景等操作。
#include <pcl/filters/passthrough.h> 如果使用线结构光扫描的方式采集点云,必然物体沿z向分布较广, 但x,y向的分布处于有限范围内。 此时可使用直通滤波器,确定点云在x或y方向上的范围, 可较快剪除离群点,达到第一步粗处理的目的。 // 创建点云对象 指针 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>); // 原点云获取后进行滤波 pcl::PassThrough<pcl::PointXYZ> pass;// 创建滤波器对象 pass.setInputCloud (cloud);//设置输入点云 pass.setFilterFieldName ("z");//滤波字段名被设置为Z轴方向 pass.setFilterLimits (0.0, 1.0);//可接受的范围为(0.0,1.0) //pass.setFilterLimitsNegative (true);//设置保留范围内 还是 过滤掉范围内 pass.filter (*cloud_filtered); //执行滤波,保存过滤结果在cloud_filtered
2.体素滤波器(下采样)
使用体素化网格方法实现下采样,即减少点的数量 减少点云数据,并同时保存点云的形状特征,在提高配准,曲面重建,形状识别等算法速度中非常实用。
1.VoxelGrid原理是根据输入的点云,首先计算一个能够刚好包裹住点云的立方体,然后根据设定的分辨率,
将该大立方体分割成不同的小立方体,对于每个小立方体的点,计算他们的质心(重心),并用质心的坐标来近似该立方体内的若干点。
#include <pcl/filters/voxel_grid.h>
pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
sor.setInputCloud(cloud);
sor.setLeafSize(0.01f,0.01f,0.01f);//设置格子大小
sor.filter(*cloud_filtered)//保留滤波后的点
2.ApproximateVoxelGrid(近似体素)的不同在于利用每个小立方体的中心来近似表示该立方体的若干点,相比于VoxelGrid,
计算速度快,但损失了一部分点云局部形态的精细度。
pcl::ApproximateVoxelGrid<pcl::PointXYZ> approximate_voxel_filter;
approximate_voxel_filter.setLeafSize(0.2,0.2,0.2);//格子大小
approximate_voxel_filter.setInputCloud(input_cloud);
approximate_voxel_filter.filter(*filtered_cloud);//保留滤波后的点
3.均匀采样滤波器(下采样)
这个类基本上是相同的,但它输出的点云索引是选择的关键点,是在计算描述子的常见方式。均匀采样滤波器不改变点的位置,下采样后,点云分布基本均匀,
原理同体素格 (正方体立体空间内 保留一个点(重心点))
而 均匀采样:半径球体内 保留一个点(重心点)
#include <pcl/filters/uniform_sampling.h>//均匀采样
----------------------------------------------------------
// 创建滤波器对象 Create the filtering object
pcl::UniformSampling<pcl::PointXYZ> filter;// 均匀采样
filter.setInputCloud(cloud_ptr);//输入点云
filter.setRadiusSearch(0.01f);//设置半径
//pcl::PointCloud<int> keypointIndices;// 索引
filter.filter(*cloud_filtered_ptr);
4.增采样 setUpsamplingMethod
增采样是一种表面重建方法,当你有比你想象的要少的点云数据时, 增采样可以帮你恢复原有的表面(S),通过内插你目前拥有的点云数据, 这是一个复杂的猜想假设的过程。所以构建的结果不会百分之一百准确, 但有时它是一种可选择的方案。 所以,在你的点云云进行下采样时,一定要保存一份原始数据! #include <pcl/surface/mls.h> ------------ // 滤波对象 pcl::MovingLeastSquares<pcl::PointXYZ, pcl::PointXYZ> filter; filter.setInputCloud(cloud); //建立搜索对象 pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree; filter.setSearchMethod(kdtree); //设置搜索邻域的半径为3cm filter.setSearchRadius(0.03); // Upsampling 采样的方法有 DISTINCT_CLOUD, RANDOM_UNIFORM_DENSITY filter.setUpsamplingMethod(pcl::MovingLeastSquares<pcl::PointXYZ, pcl::PointXYZ>::SAMPLE_LOCAL_PLANE); // 采样的半径是 filter.setUpsamplingRadius(0.03); // 采样步数的大小 filter.setUpsamplingStepSize(0.02); filter.process(*filteredCloud);
5.统计滤波器 statisticalOutlierRemoval
统计滤波器的主要思想是假设点云中所有的点与其最近的k个邻居点的平均距离满足高斯分布,那么,根据均值和方差可确定一个距离阈值,当某个点与其最近k个点的平均距离大于这个阈值时,判定该点为离群点并去除。
统计滤波器的实现原理如下:首先,遍历点云,计算每个点与其最近的k个邻居点之间的平均距离;其次,计算所有平均距离的均值μ与标准差σ,则距离阈值dmax可表示为dmax=μ+α×σ,α是一个常数,可称为比例系数,它取决于邻居点的数目;最后,再次遍历点云,剔除与k个邻居点的平均距离大于dmax的点。
// 创建点云对象 指针
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);
// 源点云读取 获取 后
// 创建滤波器,对每个点分析的临近点的个数设置为50 ,并将标准差的倍数设置为1 这意味着如果一
//个点的距离超出了平均距离一个标准差以上,则该点被标记为离群点,并将它移除,存储起来
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;//创建滤波器对象
sor.setInputCloud (cloud); //设置待滤波的点云
sor.setMeanK (50); //设置在进行统计时考虑查询点临近点数
sor.setStddevMulThresh (1.0)