一、点特征直方图(PFH)描述子介绍
??Point Feature Histograms (PFH) 称为点特征直方图。 ??随着点特征的研究不断深入,利用点周围的邻近点估计表面法向和曲率的基本操作逐渐被点特征直方图取代,虽然表面法向和曲率的估计速度很快,但是他们缺失了很多细节,因为它们仅用很少的值近似一个点的k-邻域的几何形状。但是大多数场景将包含许多具有相同或非常相似特征值的点,从而使它们的信息特征不具有唯一性。 ??本文介绍了一组3D特征描述符PFH(点特征直方图),介绍了它们的理论优势,并从PCL的角度讨论了实现细节。作为先决条件,请先阅读第三章有关表面法线计算的相关内容,因为PFH描述子既依赖于xyz 3D数据,也依赖于表面法线的估计结果。
1、点特征直方图理论基础
??PFH的目标是通过使用多维直方图来泛化点周围的平均曲率进而编码点的k邻域几何属性。这种高维的超空间为特征表示提供了信息特征,对表面的6D位姿是不变的,并且可以很好地应对不同的采样密度或邻域存在的噪声。 点特征直方图表示是基于k-邻域中的点和它们估计的表面法线之间的关系。简单地说,它试图通过考虑估计法线方向之间的所有相互作用来尽可能地捕捉采样表面的变化。因此,合成的超空间依赖于每个点的表面法线估计的质量。 ??下图呈现出PFH的计算区域图,待计算点为
p
q
p_q
pq?, 点
p
q
p_q
pq?标有红色并放置在一个半径为r的3d球体当中,和所有k邻域内的点(距离小于半径r)完全互联。最终的PFH描述符被计算为邻域内所有点对之间关系的直方图,因此计算复杂度为O(
k
2
k^2
k2)。 ??为了计算两点
p
i
p_i
pi?和
p
j
p_j
pj?及其相关法线
n
i
n_i
ni?和
n
j
n_j
nj?之间的相对差,我们在其中一点上定义一个固定的坐标系(见下图)。 ??利用上述uvw框架,两法线n_s和n_t的差可以表示为一组角特征,如下所示: ??其中d为两点
(
p
s
)
({p}_s)
(ps?)与
(
p
t
)
({p}_t)
(pt?)之间的欧氏距离,d=
∣
∣
p
t
?
p
s
∥
2
{||{p}_t-{p}_s\|}_2
∣∣pt??ps?∥2?。对k-邻域中的每一对点计算四元组的
?
\langle
?
α
\alpha
α,
?
\phi
?,
θ
\theta
θ, d
?
\rangle
?范围,因此将这两点的12个信息值(xyz和法线信息)可以减少到使用上述4个信息值表示。 ??要估计一对点的4信息PFH,使用如下代码:其中f1~f4为输出的4元组信息
computePairFeatures (const Eigen::Vector4f &p1, const Eigen::Vector4f &n1,
const Eigen::Vector4f &p2, const Eigen::Vector4f &n2,
float &f1, float &f2, float &f3, float &f4);
??为了为待计算点创建最终的PFH表示,所有4元组的集合被归类到直方图中。统计过程将每个feature的取值范围划分为b个子区间,并统计每个子区间出现的次数。由于上述四个特征中有三个是法线之间角度的度量,它们的值可以很容易地归一化到相同区间。例如,将每个特征区间划分为相同数量的相等部分,因此在完全相关的空间中创建一个具有
b
4
b^4
b4个格子的直方图。在这个空间中,一个直方图格子增量对应于一个点,它的所有4个特征都有一定的值。下图展示了点云中不同点的点特征直方图的例子。
??细心的同学会发现,使用传感器获取点云后,对于d这个参数,对于距离视点较近的点集更为密集,较远的则较为稀疏,因此,对于局部点密度因视点变化的情况,省略d参数是更有益的。
2、示例代码分析
??点特征直方图是作为pcl_features库的一部分在PCL中实现的。默认PFH的实现使用5元细分和不包括距离的细分(如上解释尽管computePairFeatures方法可以调用用户获得的距离),其结果是一个125字节的数组(5^3)的浮点值。这些存储在pcl::PFHSignature125类型中。下面的代码片段将估计输入数据集中所有点的PFH描述子。
#include <pcl/point_types.h>
#include <pcl/features/pfh.h>
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal> ());
pcl::PFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::PFHSignature125> pfh;
pfh.setInputCloud (cloud);
pfh.setInputNormals (normals);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
pfh.setSearchMethod (tree);
pcl::PointCloud<pcl::PFHSignature125>::Ptr pfhs (new pcl::PointCloud<pcl::PFHSignature125> ());
pfh.setRadiusSearch (0.05);
pfh.compute (*pfhs);
}
pfhestimate类的实际计算调用在内部没有做任何事情,除了以下操作:
for each point p in cloud P
1. get the nearest neighbors of p
2. for each pair of neighbors, compute the three angular values
3. bin all the results in an output histogram
??当计算单个点的PFH时,可采用如下指令:
computePointPFHSignature (const pcl::PointCloud<PointInT> &cloud,
const pcl::PointCloud<PointNT> &normals,
const std::vector<int> &indices,
int nr_split,
Eigen::VectorXf &pfh_histogram);
??输入的点云是包含法线的点云(如果PointInT = PointNT = PointNormal也可以),索引indices代表的是点云中参与计算PFH的点云集合,nr_split是用于每个特征区间的分块细分数量,pfh_histogram是输出的结果直方图,是一个浮点值数组。
??拓展:有时我们考虑到效率问题,选择不检查法线是否包含NaN或infinite值。将这些值传递给compute(),但是这将导致未知输出。建议至少在参数设置和程序编写时,增加检查正常值的步骤。这可以通过在调用compute()之前插入以下代码来实现:
for (int i = 0; i < normals->size(); i++)
{
if (!pcl::isFinite<pcl::Normal>((*normals)[i]))
{
PCL_WARN("normals[%d] is not finite\n", i);
}
}
??在代码编写中,应该设置预处理步骤和参数,使法线是有限的否则将引发错误。
总结: ??本篇文章介绍了什么是PFH点特征直方图,并通过示例程序分析了如何使用Feature模块点特征直方图计算的流程。
【博主简介】 ??斯坦福的兔子,男,95,天津大学机械工程工学硕士。21年毕业至今从事光学三维成像及点云处理相关工作。因工作中使用的三维处理库为公司内部库,不具有普遍适用性,遂自学开源PCL库及其相关数学知识以备使用。谨此将自学过程与君共享。 博主才疏学浅,尚不具有指导能力,如有问题还请各位在评论处留言供大家共同讨论。 若前辈们有工作机会介绍欢迎私信。
|