PCL学习:点云特征-快速点特征直方图(FPFH)描述子

已知点云P中有n个点,那么它的点特征直方图(PFH)的理论计算复杂度是O(nk^2), 其中k是点云P中每个点p计算特征向量时考虑的邻域数量。对于实时应用或接近实时应用中,密集点云的点特征直方图(PFH)的计算,是一个主要的性能瓶颈。PFH计算方式的简化形式,称为快速点特征直方图FPFH(Fast Point Feature Histograms),FPFH把算法的计算复杂度降低到了 ,但是仍然保留了PFH大部分的识别特性。

执行步骤:

第一步:先计算了每个查询点Pq的一系列值,并把它叫做SPFH(Simplified Point Feature Histgram)

第二步:每个点的最近邻是重新分配,SPFH值将用来权衡FPFH的值:

FPFH(\boldsymbol{p}_q) = SPFH(\boldsymbol{p}_q) + {1 \over k} \sum_{i=1}^k {{1 \over \omega_k} \cdot SPFH(\boldsymbol{p}_k)}

上式中,权重 \omega_k  在一些给定的度量空间中,表示查询点 p_q 和其邻近点 p_k 之间的距离,因此可用来评定一对点(p_q, p_k,但是如果需要的话,也可以把\omega_k用另一种度量来表示。如图1所示可以帮助理解这个权重方式的重要性,它表示的是以点p_q 为中心的k邻域影响范围。 

_images/fpfh_diagram.png

图1 以点p_q 为中心的k邻域影响范围图

因此,对于一个已知查询点p_q ,这个算法首先只利用p_q 和它邻域点之间对应对(上图中以红色线来说明),来估计它的SPFH值,很明显这样比PFH的标准计算少了邻域点之间的互联。点云数据集中的所有点都要执行这一计算获取SPFH,接下来使用它的邻近点p_k 的SPFH值和p_q 点的SPFH值重新权重计算,从而得到p_q 点的最终FPFH值。FPFH计算添加的计算连接对,在上图中以黑色线表示。如上图所示,一些重要对点(与p_q 直接相连的点)被重复计数两次(图中以粗线来表示),而其他间接相连的用细黑线表示。

PFH和FPFH的区别

PFH和FPFH计算方式之间的主要区别总结如下:

1.FPFH没有对全互连 点的所有邻近点的计算参数进行统计,从图12-18中可以看到,因此可能漏掉了一些重要的点对,而这些漏掉的对点可能对捕获查询点周围的几何特征有贡献。

2.PFH特征模型是对查询点周围的一个精确的邻域半径内,而FPFH还包括半径r范围以外的额外点对(不过在2r内);

3.因为重新权重计算的方式,所以FPFH结合SPFH值,重新捕获邻近重要点对的几何信息;

4.由于大大地降低了FPFH的整体复杂性,因此FPFH有可能使用在实时应用中;

5.通过分解三元组,简化了合成的直方图。也就是简单生成d分离特征直方图,对每个特征维度来单独绘制,并把它们连接在一起(见下2图)。

 _images/fpfh_theory.jpg

图2 PFH与FPFH示意图

估计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

利用OpenMP提高FPFH速度

对于计算速度要求苛刻的用户,PCL提供了一个FPFH估计的另一实现,它使用多核/多线程规范,利用OpenMP开发模式来提高计算速度。这个类的名称是pcl::FPFHEstimationOMP,并且它的应用程序接口(API)100%兼容单线程pcl::FPFHEstimation,这使它适合作为一个替换元件。在8核系统中,OpenMP的实现可以在6-8倍更快的计算时间内完全同样单核系统上的计算。

猜你喜欢

转载自blog.csdn.net/zfjBIT/article/details/93711546