快速点特征直方图(FPFH)描述子
已知点云P中有n个点,那么它的点特征直方图(PFH)的理论计算复杂度是,其中k是点云P中每个点p计算特征向量时考虑的邻域数量。对于实时应用或接近实时应用中,密集点云的点特征直方图(PFH)的计算,是一个主要的性能瓶颈。此处为PFH计算方式的简化形式,称为快速点特征直方图FPFH(Fast Point Feature Histograms)
为了简化直方图的特征计算,我们执行以下过程:
第一步,对于每一个查询点 ,计算这个点和它的邻域点之间的一个元组 (参考上一节PFH的介绍),第一步结果我们称之为简化的点特征直方图SPFH(Simple Point Feature Histograms);
第二步,重新确定每个点的k邻域,使用邻近的SPFH值来计算的最终直方图(称为FPFH)
权重 在一些给定的度量空间中,表示查询点 和其邻近点 之间的距离,因此可用来评定一对点( , ),但是如果需要的话,也可以把用 另一种度量来表示。如图1所示可以帮助理解这个权重方式的重要性,它表示的是以点 为中心的k邻域影响范围。
以点 为中心的k邻域影响范围图
因此,对于一个已知查询点 ,这个算法首先只利用 和它邻域点之间对应对(上图中以红色线来说明),来估计它的SPFH值,很明显这样比PFH的标准计算少了邻域点之间的互联。点云数据集中的所有点都要执行这一计算获取SPFH,接下来使用它的邻近点 的SPFH值和 点的SPFH值重新权重计算,从而得到 点的最终FPFH值。FPFH计算添加的计算连接对,在上图中以黑色线表示。如上图所示,一些重要对点(与 直接相连的点)被重复计数两次(图中以粗线来表示),而其他间接相连的用细黑线表示。
PFH和FPFH的区别
PFH和FPFH计算方式之间的主要区别总结如下:
1.FPFH没有对全互连 点的所有邻近点的计算参数进行统计,从图中可以看到,因此可能漏掉了一些重要的点对,而这些漏掉的对点可能对捕获查询点周围的几何特征有贡献。
2.PFH特征模型是对查询点周围的一个精确的邻域半径内,而FPFH还包括半径r范围以外的额外点对(不过在2r内);
3.因为重新权重计算的方式,所以FPFH结合SPFH值,重新捕获邻近重要点对的几何信息;
4.由于大大地降低了FPFH的整体复杂性,因此FPFH有可能使用在实时应用中;
5.通过分解三元组,简化了合成的直方图。也就是简单生成d分离特征直方图,对每个特征维度来单独绘制,并把它们连接在一起
估计FPFH特征
快速点特征直方图FPFH在点云库中的实现可作为pcl_features库的一部分。默认的FPFH实现使用11个统计子区间(例如:四个特征值中的每个都将它的参数区间分割为11个),特征直方图被分别计算然后合并得出了浮点值的一个33元素的特征向量,这些保存在一个pcl::FPFHSignature33点类型中。以下代码段将对输入数据集中的所有点估计一组FPFH特征值。
#include #include //fpfh特征估计类头文件声明 ...//其他相关操作 pcl::PointCloud<pcl::PointXYZ>::Ptrcloud(new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::Normal>::Ptrnormals(new pcl::PointCloud<pcl::Normal>()); ...//打开点云文件估计法线等 //创建FPFH估计对象fpfh,并把输入数据集cloud和法线normals传递给它。 pcl::FPFHEstimation<pcl::PointXYZ,pcl::Normal,pcl::FPFHSignature33> fpfh; fpfh.setInputCloud(cloud); fpfh.setInputNormals(normals); //如果点云是类型为PointNormal,则执行fpfh.setInputNormals (cloud); //创建一个空的kd树对象tree,并把它传递给FPFH估计对象。 //基于已知的输入数据集,建立kdtree pcl::search::KdTree<PointXYZ>::Ptrtree(new pcl::search::KdTree<PointXYZ>); fpfh.setSearchMethod(tree); //输出数据集 pcl::PointCloud<pcl::FPFHSignature33>::Ptrfpfhs(new pcl::PointCloud<pcl::FPFHSignature33>()); //使用所有半径在5厘米范围内的邻元素 //注意:此处使用的半径必须要大于估计表面法线时使用的半径!!! fpfh.setRadiusSearch(0.05); //计算获取特征向量 fpfh.compute(*fpfhs); // fpfhs->points.size ()应该和input cloud->points.size ()有相同的大小,即每个点有一个特征向量
FPFHEstimation类的实际计算内部只执行以下操作:
对点云P中的每个点p
第一步:
1.得到:math:`p`的邻域元素
2. 计算每一对:math:`p, p_k`的三个角度参数值(其中:math:`p_k`是:math:`p`的邻元素)
3.把所有结果统计输出到一个SPFH直方图
第二步:
1.得到:math:`p`的最近邻元素
2.使用:math:`p`的每一个SPFH和一个权重计算式,来计算最终:math:`p`的FPFH
估计一点云的VFH特征
视点特征直方图(或VFH)是源于FPFH描述子(见Fast Point Feature Histograms (PFH) 描述子)。由于它的获取速度和识别力,我们决定利用FPFH强大的识别力,但是为了使构造的特征保持缩放不变性的性质同时,还要区分不同的位姿,计算时需要考虑加入视点变量。我们做了以下两种计算来构造特征,以应用于目标识别问题和位姿估计:1.扩展FPFH,使其利用整个点云对象来进行计算估计(如2图所示),在计算FPFH时以物体中心点与物体表面其他所有点之间的点对作为计算单元。2.添加视点方向与每个点估计法线之间额外的统计信息,为了达到这个目的,我们的关键想法是在FPFH计算中将视点方向变量直接融入到相对法线角计算当中。
通过统计视点方向与每个法线之间角度的直方图来计算视点相关的特征分量。注意:并不是每条法线的视角,因为法线的视角在尺度变换下具有可变性,我们指的是平移视点到查询点后的视点方向和每条法线间的角度。第二组特征分量就是前面PFH中讲述的三个角度,如PFH小节所述,只是现在测量的是在中心点的视点方向和每条表面法线之间的角度
因此新组合的特征被称为视点特征直方图(VFH)。下图表体现的就是新特征的想法,包含了以下两部分:
1.一个视点方向相关的分量
2.一个包含扩展FPFH的描述表面形状的分量
估计VFH特征值
视点特征直方图在PCL中的实现属于pcl_features模块库的一部分。对扩展的FPFH分量来说,默认的VFH的实现使用45个子区间进行统计,而对于视点分量要使用128个子区间进行统计,这样VFH就由一共308个浮点数组成阵列。在PCL中利用pcl::VFHSignature308的点类型来存储表示。PFH/FPFH描述子和VFH之间的主要区别是:对于一个已知的点云数据集,只一个单一的VFH描述子,而合成的PFH/FPFH特征的数目和点云中的点数目相同。以下代码段将对输入数据集中的所有点估计一组VFH特征值。
#include <pcl/point_types.h> #include <pcl/features/vfh.h> //VFH特征估计类头文件 ...//其他相关操作 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal> ()); ...//打开点云文件估计法线等 //创建VFH估计对象vfh,并把输入数据集cloud和法线normal传递给它 pcl::VFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::VFHSignature308> vfh; vfh.setInputCloud (cloud); vfh.setInputNormals (normals); //如果点云是PointNormal类型,则执行vfh.setInputNormals (cloud); //创建一个空的kd树对象,并把它传递给FPFH估计对象。 //基于已知的输入数据集,建立kdtree pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr tree (new pcl::KdTreeFLANN<pcl::PointXYZ> ()); vfh.setSearchMethod (tree); //输出数据集 pcl::PointCloud<pcl::VFHSignature308>::Ptr vfhs (new pcl::PointCloud<pcl::VFHSignature308> ()); //计算特征值 vfh.compute (*vfhs); // vfhs->points.size ()的大小应该是1,即vfh描述子是针对全局的特征描述
微信公众号号可扫描二维码一起共同学习交流