PCL教程指南-PFH与FPFH特征描述子
1.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> ());
... read, pass in or create a point cloud with normals ...
... (note: you can create a single PointCloud<PointNormal> if you want) ...
//PFH估计类,其中pcl::PFHSignature125为输出类型为直方图数据
pcl::PFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::PFHSignature125> pfh;
pfh.setInputCloud (cloud);
pfh.setInputNormals (normals);
//根据点云类型不同,比如可使用pointNormal类型,则 pfh.setInputNormals (cloud);
// Kdtree搜索类,直接设置给pfh类
// 搜索直接按照pfh内部数据计算
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
//pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr tree (new pcl::KdTreeFLANN<pcl::PointXYZ> ()); -- older call for PCL 1.5-
pfh.setSearchMethod (tree);
// 输出结果集,即每个点都对应一个125个向量数据
pcl::PointCloud<pcl::PFHSignature125>::Ptr pfhs (new pcl::PointCloud<pcl::PFHSignature125> ());
// 设置半径,用于fph邻域计算
// 注意: 这个半径必须大于估计法线时的搜索半径
pfh.setRadiusSearch (0.05);
// 计算pfh特征
pfh.compute (*pfhs);
// pfhs->size () should have the same size as the input cloud->size ()*
}
- 其中
pcl::PFHSignature125
为直方图输出结果类型,125的含义是 这个类中特征选取了三个角度值,而没有距离信息(需要距离信息需要computePairFeatures方法计算),且角度在构建直方图时默认采用了5个间隔(bin),通俗来讲就是 有三个角度,每个角度有5份,穷举可能出现的结果构建直方图,即每个角度选一份出来组成一块,排列组合A15 * A15 * A15 即文档中所说的5 * 5 * 5=5^3
- 有时需要单独求某两点的特征信息,或者只求一个点的pfh特征,pcl提供了以下两种方法
//计算两点之间的三个角度和一个距离信息
bool pcl::PFHEstimation< PointInT, PointNT, PointOutT >::computePairFeatures (
const pcl::PointCloud< PointInT > & cloud,//输入 包含这两点的点云指针
const pcl::PointCloud< PointNT > & normals,//输入 点云的法向指针
int p_idx,//输入 点1索引
int q_idx,//输入 点2索引
float & f1,//输出 nq_idx 和 u的投影角度
float & f2,//输出 nq_idx 和 v的角度
float & f3,//输出 np_idx 和 |p_idx - q_idx|的角度
float & f4 //输出 距离
)
//计算某个点的pfh角度特征数据
void pcl::PFHEstimation< PointInT, PointNT, PointOutT >::computePointPFHSignature (
const pcl::PointCloud< PointInT > & cloud,//点云
const pcl::PointCloud< PointNT > & normals,//法向
const pcl::Indices & indices,// 某点的邻域内所有点的索引
int nr_split,//角度数据的分割数目 (bin数)
Eigen::VectorXf & pfh_histogram //输出的pfh向量 即如果bin是5,那么输出含125个数据的向量
)
2.FPFH
相比PFH,FPFH为了计算快速,计算时没有使用邻域网络交叉计算,而是通过邻域各点的SPFH加权得到结果。
SPFH即针对某点,只计算此点与邻域间的特征角度和距离信息,不必计算邻域内点间的特征信息。
#include <pcl/point_types.h>
#include <pcl/features/fpfh.h>
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal> ());
... read, pass in or create a point cloud with normals ...
... (note: you can create a single PointCloud<PointNormal> if you want) ...
// FPFH估计类,其中pcl::FPFHSignature33为输出类型为直方图数据
pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fpfh;
fpfh.setInputCloud (cloud);
fpfh.setInputNormals (normals);
//以下类似于FPH代码
pcl::search::KdTree<PointXYZ>::Ptr tree (new pcl::search::KdTree<PointXYZ>);
fpfh.setSearchMethod (tree);
//输出结果
pcl::PointCloud<pcl::FPFHSignature33>::Ptr fpfhs (new pcl::PointCloud<pcl::FPFHSignature33> ());
fpfh.setRadiusSearch (0.05);
fpfh.compute (*fpfhs);
// fpfhs->size () should have the same size as the input cloud->size ()*
}
- 其中
pcl::FPFHSignature33
,33的含义是3个角度,默认分割11份,不像PFH125那样穷举,而是直接独立拼凑到一起,即11+11+11=33 - 类比PFH单独计算特征信息的方法FPFH同样实现了,类似方法不再赘述
//计算两点间相关特征值
bool computePairFeatures (const pcl::PointCloud< PointInT > &cloud, const pcl::PointCloud< PointNT > &normals, int p_idx, int q_idx, float &f1, float &f2, float &f3, float &f4)
//计算某点的SPFH,返回各角度特征的矩阵形式; 比如计算第一个点row=0,那么矩阵只有第一行有值,以此类推
void pcl::FPFHEstimation< PointInT, PointNT, PointOutT >::computePointSPFHSignature (
const pcl::PointCloud< PointInT > & cloud,
const pcl::PointCloud< PointNT > & normals,
int p_idx,//查询点索引
int row,//矩阵的第几行,具体的行指邻域内SPFH计算所在的点,row则指查询点邻域内第row个点
const std::vector< int > & indices,//邻域索引
Eigen::MatrixXf & hist_f1,//输出 f1的直方图矩阵
Eigen::MatrixXf & hist_f2,//输出 f2的直方图矩阵
Eigen::MatrixXf & hist_f3 //输出 f3的直方图矩阵
)
//加权SPFH求得单点的FPFH (此方法甚用!,他是配合PCL源码所用,单独使用需要注意indeices参数!)
void pcl::FPFHEstimation< PointInT, PointNT, PointOutT >::weightPointSPFHSignature (
const Eigen::MatrixXf & hist_f1,//输入 f1邻域各点的直方图矩阵
const Eigen::MatrixXf & hist_f2,//输入 f2邻域各点的直方图矩阵
const Eigen::MatrixXf & hist_f3,//输入 f3邻域各点的直方图矩阵
//
******源码中此方法以indices中的值当作hist_f1,2,3的行索引即用了邻域点在点云中的索引数,显然直接使用会出错**********
******此方法在源码使用时,增加了一个过渡方法computeSPFHSignatures,保存了邻域点在点云的索引和在矩阵中行索引的映射向量**********
const std::vector< int > & indices, //输入 邻域索引
//
const std::vector< float > & dists,//输入 与邻域间距离
Eigen::VectorXf & fpfh_histogram
)
******源码中的过渡方法computeSPFHSignatures**********
//计算全局索引indices_,即提前设置的setIndex需要计算特征的点,映射向量和特征矩阵
void pcl::FPFHEstimation< PointInT, PointNT, PointOutT >::computeSPFHSignatures (
std::vector< int > & spf_hist_lookup, //输出 邻域点在点云的索引和在矩阵中行索引的映射向量
Eigen::MatrixXf & hist_f1,//输出
Eigen::MatrixXf & hist_f2,//输出
Eigen::MatrixXf & hist_f3 //输出
)
说明:PCL提供的其他方法,主要是为了方便代码组织,封装了各种功能的小方法,本质就是方法的互相调用简化代码使得更加清晰,不过因为继承的关系,想要理清这些方法的作用,需要明确PCL的模块的继承组织结构,单独使用时需谨慎。综上,FPFH提供的小方法过于耦合不建议用户单独使用
(PCL为了用户使用方便,不难发现特征计算都最后使用了compute方法,他则是统一重写,其中就是调用了内部的各种小方法,使得用户不管计算什么特征,代码都是类似的,体现了多态的好处)
- 相比PFH类,FPFH类提供了用户自定义分割Bin数量方法
//三个角度可自定义BIN数量
void pcl::FPFHEstimation< PointInT, PointNT, PointOutT >::setNrSubdivisions (
int nr_bins_f1,
int nr_bins_f2,
int nr_bins_f3
)