点要素直方图的理论计算复杂性(见 点要素直方图(PFH)描述)为给定的ñ点组成的点云P是O(NK ^ 2),这里ķ是对在 P中的每个p点邻居的数量。对于实时或接近实时的应用,密集点邻域中的点特征直方图的计算可能代表主要的瓶颈之一。
本教程描述了PFH公式的简化,称为快速点特征直方图(FPFH)(参见Rusu论文以获取更多信息),这样可以降低算法的计算复杂度O(NK),同时仍保留大部分PFH的判别能力。
#理论引入
为了简化直方图特征计算,我们进行如下:
在第一步中, for each query point p_q a set of tuples \alpha, \phi, \theta between itself and its neighbors are computed as described in Point Feature Histograms (PFH) descriptors - this will be called the Simplified Point Feature Histogram (SPFH);
在第二步中,对于每个点,其k个邻居被重新确定,并且相邻的SPFH值被用于对pq的最终直方图(称为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)对进行评分,但是如果需要也可以被选择为不同的度量。为了理解这个加权方案的重要性,下图给出了以p_q为中心的k邻域集合的影响区域图。
_images/fpfh_diagram.png
因此,对于给定的查询点p_q,该算法首先通过在其自身与其邻居之间创建对(使用红线示出)来估计其SPFH值。对数据集中的所有点重复此操作,然后使用其P_K邻居的SPFH值重新计算pq的SPFH值 ,从而创建FPFH p_q。由于附加的加权方案而产生的额外FPFH连接以黑线显示。如图所示,一些数值对将被计数两次(在图中用粗线标出)。
#PFH和FPFH的区别
PFH和FPFH的主要差异总结如下:
p_q从图中可以看出,FPFH不能完全连接所有邻居,因此缺少一些可能有助于捕捉查询点周围几何图形的值对;
PFH在查询点周围建立精确确定的表面,而FPFH包括r半径范围以外的附加点对(尽管最多不超过2r)。
由于重新加权方案,FPFH结合SPFH值并重新捕获一些点相邻值对;
FPFH的总体复杂度大大降低,因此可以将其用于实时应用;
通过解相关值来简化结果直方图,即简单地创建d分离的特征直方图,每个特征维度一个,并将它们连接在一起(见下图)。
_images/fpfh_theory.jpg
#估计FPFH功能
快速点特征直方图是作为pcl_features
库的一部分在PCL中实现的 。
默认的FPFH实现使用11个binning细分(例如,四个特征值中的每一个将使用来自其值区间的这许多区间),并且解相关方案(参见上面:特征直方图被分开计算并且连贯),其导致33浮点值的字节数组。这些存储在pcl::FPFHSignature33
点类型中。
以下代码片段将估计输入数据集中所有点的一组FPFH特征。
#include
#include
{
pcl::PointCloud::Ptr cloud (new pcl::PointCloud);
pcl::PointCloud::Ptr normals (new pcl::PointCloud ());
... read, pass in or create a point cloud with normals ...
... (note: you can create a single PointCloud if you want) ...
// Create the FPFH estimation class, and pass the input dataset+normals to it
pcl::FPFHEstimation fpfh;
fpfh.setInputCloud (cloud);
fpfh.setInputNormals (normals);
// alternatively, if cloud is of tpe PointNormal, do fpfh.setInputNormals (cloud);
// Create an empty kdtree representation, and pass it to the FPFH estimation object.
// Its content will be filled inside the object, based on the given input dataset (as no other search surface is given).
pcl::search::KdTree::Ptr tree (new pcl::search::KdTree);
fpfh.setSearchMethod (tree);
// Output datasets
pcl::PointCloud::Ptr fpfhs (new pcl::PointCloud ());
// Use all neighbors in a sphere of radius 5cm
// IMPORTANT: the radius used here has to be larger than the radius used to estimate the surface normals!!!
fpfh.setRadiusSearch (0.05);
// Compute the features
fpfh.compute (*fpfhs);
// fpfhs->points.size () should have the same size as the input cloud->points.size ()*
}
来自FPFHEstimation
类的实际计算调用在内部不做任何事情,但是:
for each point p in cloud P
1. pass 1:
1. get the nearest neighbors of :math:`p`
2. for each pair of :math:`p, p_k` (where :math:`p_k` is a neighbor of :math:`p`, compute the three angular values
3. bin all the results in an output SPFH histogram
2. pass 2:
1. get the nearest neighbors of :math:`p`
3. use each SPFH of :math:`p` with a weighting scheme to assemble the FPFH of :math:`p`:
注意:
出于效率原因,`PFHEstimation`中的计算方法不检查法线是否包含`NaN`或`无限值`。将这些值传递给`compute()`会导致未定义的输出。建议检查法线,至少在加工链的设计或设置参数时。这可以通过在调用`compute()`之前插入以下代码来完成:
for (int i = 0; i < normals->points.size(); i++)
{
if (!pcl::isFinite(normals->points[i]))
{
PCL_WARN("normals[%d] is not finite\n", i);
}
}
在生产代码中,应该设置预处理步骤和参数,使法线是有限的或产生错误。
#使用OpenMP加速正常估计
对于精通速度的用户来说,PCL提供了额外的曲面法线估计实现,使用OpenMP的多核/多线程范例来加速计算。该类的名称是pcl::NormalEstimationOMP,它的API与单线程pcl::NormalEstimation完全兼容,这使得它适合作为一个插入式替换。在一个有8个内核的系统上,你应该得到6-8倍的计算时间。
Fast Point Feature Histograms (FPFH) descriptors