PCL中常用的高级采样方法

您所在的位置:网站首页 点云ppf PCL中常用的高级采样方法

PCL中常用的高级采样方法

2023-09-24 09:46| 来源: 网络整理| 查看: 265

PCL中常用的高级采样方法 敢敢のwings 分类:建图导航 个人专栏:FAST-LIO系列 发布时间 2023.01.04阅读数 3190 评论数 0 0. 简介

我们在使用PCL时候,常常不满足于常用的降采样方法,这个时候我们就想要借鉴一些比较经典的高级采样方法。这一讲我们将对常用的高级采样方法进行汇总,并进行整理,来方便读者完成使用

1. 基础下采样 1.1 点云随机下采样

点云下采样是对点云以一定的采样规则重新进行采样,目的是在保证点云整体几何特征不变的情况下,降低点云的密度,进而可以降低相关处理的数据量和算法复杂度。随机下采样顾名思义,随机下采样就似乎在原始点云中随机采样一定点数的点。这种方法最终得到的点云数量也是固定的。

pcl::PointCloud::Ptr cloud_sub(new pcl::PointCloud); //随机下采样点云 pcl::RandomSample rs; //创建滤波器对象 rs.setInputCloud(cloud); //设置待滤波点云 rs.setSample(20000); //设置下采样点云的点数 //rs.setSeed(1); //设置随机函数种子点 rs.filter(*cloud_sub); //执行下采样滤波,保存滤波结果于cloud_sub

在这里插入图片描述

1.2 体素下采样

体素下采样的原理如图1所示,首先将点云空间进行网格化,也称体素化,即图1(b),网格化后的每一个格子称为体素,在这些划分为一个个极小的格子中包含一些点,然后对这些点取平均或加权平均得到一个点,以此来替代原来网格中所有的点,即图1(c)中蓝色的点。显然,网格选取越大则采样之后的点云越少,处理速度变快,但会对原先点云过度模糊,网格选取越小,则作用相反。在这里插入图片描述

pcl::VoxelGrid sor; //创建体素网格采样处理对象 sor.setInputCloud(cloud); //设置输入点云 sor.setLeafSize(0.01f, 0.01f, 0.01f); //设置体素大小,单位:m sor.filter(*cloud_filtered); //进行下采样 1.3 均匀采样

均匀采样的原理类似于体素化网格采样方法,同样是将点云空间进行划分,不过是以半径=r的球体,在当前球体所有点中选择距离球体中心最近的点替代所有点,注意,此时点的位置是不发生移动的。球体半径选取越大则采样之后的点云越少,处理速度变快,但会对原先点云过度模糊,网格选取越小,则作用相反。

pcl::UniformSampling form; // 创建均匀采样对象 form.setInputCloud(cloud); //设置输入点云 form.setRadiusSearch(0.02f); //设置半径大小,单位:m form.filter(*after_cloud); //执行滤波处理 1.4 增采样

增采样的特点是可极大的增加点云数据,但由于内插点的不确定性会导致最后输出的结果不一定准确。

//创建增采样对象 pcl::MovingLeastSquares filter; filter.setInputCloud(cloud); //设置输入点云 pcl::search::KdTree::Ptr kdtree; //定义搜索方法 filter.setSearchMethod(kdtree); //设置搜索方法 filter.setSearchRadius(0.03); //设置搜索邻域的半径为3cm //Upsampling 采样的方法还有 DISTINCT_CLOUD, RANDOM_UNIFORM_DENSITY filter.setUpsamplingMethod(pcl::MovingLeastSquares::SAMPLE_LOCAL_PLANE); //对点云进行上采样 filter.setUpsamplingRadius(0.03); //设置采样半径大小,3cm filter.setUpsamplingStepSize(0.02); //设置采样步长大小,2cm filter.process(*after_cloud); //执行采样操作 1.5 滑动最小二乘法采样

滑动最小二乘法采样的原理是将点云进行了滑动最小二乘法的映射,使得输出的点云更加平滑。

pcl::PointCloud::Ptr smoothedCloud(new pcl::PointCloud); //定义法线 pcl::MovingLeastSquares filter; pcl::search::KdTree::Ptr kdtree; //定义搜索方法 filter.setInputCloud(cloud); //设置输入点云 filter.setUpsamplingMethod(); //增加密度较小区域的密度对于holes的填补却无能为力,具体方法要结合参数使用 filter.setSearchRadius(10);// 用于拟合的K近邻半径。在这个半径里进行表面映射和曲面拟合。半径越小拟合后曲面的失真度越小,反之有可能出现过拟合的现象。 filter.setPolynomialFit(true); //对于法线的估计是有多项式还是仅仅依靠切线。true为加多项式;false不加,速度较快 filter.setPolynomialFit(3); // 拟合曲线的阶数 filter.setComputeNormals(true); // 是否存储点云的法向量,true 为存储,false 不存储 filter.setSearchMethod(kdtree); //设置搜索方法 filter.process(*smoothedCloud); //处理点云并输出 2. 最远点采样(Farthest Point Sampling)

这个PCL代码目前已经集成到https://github.com/farthest_point_sampling.hpp。这里我们来单独看一下调用代码,这里可以看到PCL中支持直接调用farthest_sampling这个函数可以实现最远点采样。最远点采样(Farthest Point Sampling)是一种非常常用的采样算法,由于能够保证对样本的均匀采样,被广泛使用,像3D点云深度学习框架中的PointNet++对样本点进行FPS采样再聚类作为感受野,3D目标检测网络VoteNet对投票得到的散乱点进行FPS采样再进行聚类,6D位姿估计算法PVN3D中用于选择物体的8个特征点进行投票并计算位姿。FPS算法原理:

输入点云有N个点,从点云中选取一个点P0作为起始点,得到采样点集合S={P0}; 计算所有点到P0的距离,构成N维数组L,从中选择最大值对应的点作为P1,更新采样点集合S={P0,P1}; 计算所有点到P1的距离,对于每一个点Pi,其距离P1的距离如果小于L[i],则更新L[i] = d(Pi, P1),因此,数组L中存储的一直是每一个点到采样点集合S的最近距离; 选取L中最大值对应的点作为P2,更新采样点集合S={P0,P1,P2}; 重复2-4步,一直采样到N’个目标采样点为止。 std::vector input_point_clouds(1); std::vector output_point_clouds; ASSERT_NE(pcl::io::loadPLYFile(STR(INPUT_POINT_CLOUD_PATH), input_point_clouds[0]), -1) size()*kSampleRatio); // 执行采样并带出采样结果 nss.filter(*cloud_with_normal_sampled); 4. 泊松盘采样

泊松盘采样(possion disk sampling)的特点是任何两个点的距离都不会隔得太近。比如下图,左边是随机生成的点,右边是泊松盘采样生成的点。在这里插入图片描述具体流程如下

设定好两个点之间最近的距离r,以及采样点所在空间的维度n,比如2维平面

在空间里生成足够多的网格,保证不接触的两个网格之间的点的距离大于r,并且网格数量足够多保证每个网格至多只需装一个采样点就能满足采样数量。为了最优化,一般取网格边长为r/\sqrt{n}。

随机生成一个点,再创建两个数组,第一个是处理数组,第二个是结果数组,即最终的输出数组。把这个点放进处理数组中和结果数组中。

如果处理数组非空,从中随机选择一个点,如下图的红点,并把这个点从处理数组中删除。如果处理数组是空的,直接输出结果数组并结束算法。

设定最小距离minr,比如r,最大距离maxr,比如2*r。以红点为中心生成一个圆环,如下图灰色圆环,在这个圆环中生成一个采样点,如下图蓝点。

在这里插入图片描述

#include //泊松重建 cout width = 1; incloud->height = uint32_t (incloud->points.size ()); pcl::SamplingSurfaceNormal ssn_filter; ssn_filter.setInputCloud (incloud); ssn_filter.setRatio (0.3f); ssn_filter.filter (outcloud); // All the sampled points should have normals along the direction of Z axis for (unsigned int i = 0; i < outcloud.points.size (); i++) { EXPECT_NEAR (outcloud.points[i].normal[0], 0, 1e-3); EXPECT_NEAR (outcloud.points[i].normal[1], 0, 1e-3); EXPECT_NEAR (outcloud.points[i].normal[2], 1, 1e-3); }

在这里插入图片描述

6. 半径滤波器采样

对整个输入迭代一次,对于每个点进行半径R邻域搜索,如果邻域点的个数低于某一阈值,则该点将被视为噪声点并被移除。

流程:读入点云→创建半径滤波器对象→设置离群点阈值→执行下采样→保存采样结果

pcl::PointCloud::Ptr pcl_cloud_ptr(pcl_cloud); boost::shared_ptr pcl_vg_cloud(new pcl::PointCloud()); pcl::PointCloud::Ptr pcl_vg_cloud_ptr(pcl_vg_cloud); boost::shared_ptr pcl_ror_cloud(new pcl::PointCloud()); pcl::PointCloud::Ptr pcl_ror_cloud_ptr(pcl_ror_cloud); //Use VoxelGrid to make points sparse pcl::VoxelGrid sor; sor.setInputCloud (pcl_cloud_ptr); sor.setLeafSize (0.08, 0.1, 0.1); sor.filter (*pcl_vg_cloud_ptr); //Use RadiusOutlierRemoval to remove the point whitch is far away to others pcl::RadiusOutlierRemoval outrem; outrem.setInputCloud(pcl_vg_cloud_ptr); outrem.setRadiusSearch(0.5); outrem.setMinNeighborsInRadius (3); outrem.filter (*pcl_ror_cloud_ptr); //transfrom and publish sensor_msgs::PointCloud2Ptr msg_pointcloud(new sensor_msgs::PointCloud2); pcl::toROSMsg(*pcl_ror_cloud, *msg_pointcloud); msg_pointcloud->header.frame_id = optical_frame_id_[RS_STREAM_DEPTH];; msg_pointcloud->header.stamp = ros::Time::now();

在这里插入图片描述

参考链接

https://zhuanlan.zhihu.com/p/503073511

https://blog.csdn.net/weixin_43236428/article/details/103644570

https://blog.csdn.net/qq_34792438/article/details/114363189

视觉SLAM定位

原创文章作者:敢敢のwings。如若转载,请注明出处:古月居 http://www.guyuehome.com/41699

打赏 0

点赞 0

收藏 1

分享

微信 微博 QQ 图片 上一篇:经典文献阅读之--FAST-LIVO(Fast-LIO系列的激光视觉惯性里程计) 下一篇:Sophus降维、升维与欧拉角、旋转向量的爱恨情仇


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3