pcl::Feature 类输入数据的传入方法和四种应用模式
pcl::Feature类 有两种输入数据的方法,共对应四种应用模式:
两种输入数据的方法
- 一个完整的点云数据集,通过setInputCloud (PointCloudConstPtr &)来传入。任何特征估计的子类都会尝试估计这个输入点云中每个点的特征。
- 一个点云数据集的子集,通过setInputCloud (PointCloudConstPtr &)和setIndices (IndicesConstPtr &)来传入。任何特征估计的子类都会尝试估计给定索引列表中的每个索引对应的点的特征,如果没有给定索引列表,则会默认估计点云数据集中所有点的特征。
此外,可以通过附加调用setSearchSurface(PointCloudConstPtr&)指定要使用的相邻点集。 此调用是可选的,当未给出搜索表面时,默认使用输入点云数据集。
要分清楚两种点,上面的概念才好理解:
第一种是将以这个点为中心,估计这个点的特征的那一个点子集,一般用setInputCloud (PointCloudConstPtr &)和setIndices (IndicesConstPtr &)来传入。
另一种是为第一类待估计的点提供邻接信息和特征约束的点集,一般用setSearchSurface(PointCloudConstPtr&)来传入。
第一种点的特征,用第二种点来描述,这就是特征估计。
对应的四种应用模式
因为总是需要setInputCloud(),所以我们可以使用<setInputCloud(),setIndices(),setSearchSurface()>创建最多四种组合。
假设我们有两个点云,P = {p_1,p_2,… p_n}和Q = {q_1,q_2,…,q_n}。 下图显示了所有四种情况:
- setIndices() = false, setSearchSurface() = false
无疑这是PCL中最常用的一种形式,第一类点是输入的全体点云数据,第二类点也是输入的全体点云数据。这种应用模式,将对输入的所有点进行特征估计,用来特征表示的相邻点集也都来自输入点云。当给定一个待估计的点,便用输入点云自身的其他点表示待估计点的特征。
如左1图所示, 首先,我们估计p_1的相邻点集,然后是p_2的相邻点集,依此类推,直到我们遍历完了P中的所有点。 - setIndices()= true,setSearchSurface()= false
这种应用模式下,第一类点由输入点云数据与索引列表共同决定,即只估计输入点云中索引号在索引列表中的那些点,第二类的点则是完整的输入点云数据集。
如左2图所示,我们假设p_2的索引不在给定的索引列表中,因此不会估计p_2处的相邻点集或特征。 - setIndices()= false,setSearchSurface()= true
这种应用模式下,第一类点是输入的全体点云数据,第二类点是则由setSearchSurface()指定。
如左3图所示,假设Q = {q_1,q_2}是第一类点,P是第二类点,即P是Q的搜索表面,则q_1和q_2的相邻点集或特征将用P中的点进行表示。 - setIndices()= true,setSearchSurface()= true
这可能是最罕见的情况,其中给出了索引和搜索表面。在这种应用模式下,第一类点由输入点云数据与索引列表共同决定,第二类点由setSearchSurface()指定。
如左4图所示,假设q_2的索引不是为Q给出的索引向量的一部分,因此在q_2处不会估计相邻点集或者特征信息。
使用setSearchSurface()最有用的例子是:
当我们有一个点云密度非常大的输入数据集时,基于计算花费的考虑,我们不想估计其中所有点的特征,而是想更精准地估计某些关键点(比如用pcl_keypoints中的方法获得的),或者估计点云的下采样版本中的点(比如用体素格滤波器获得)。 在这种情况下,我们可以通过setInputCloud()传入下采样/关键点作为数据输入,并将原始点云数据作为setSearchSurface()传入,从而灵活高效地实现估计指定点的特征。
在法向量估计中的应用举例
- 估计输入数据集中所有点的曲面法线
#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
... read, pass in or create a point cloud ...
// Create the normal estimation class, and pass the input dataset to it
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud (cloud);
// Create an empty kdtree representation, and pass it to the normal 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<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
ne.setSearchMethod (tree);
// Output datasets
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
// Use all neighbors in a sphere of radius 3cm
ne.setRadiusSearch (0.03);
// Compute the features
ne.compute (*cloud_normals);
// cloud_normals->points.size () should have the same size as the input cloud->points.size ()
}
- 估计输入数据集的子集中的所有点的曲面法线
#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
... read, pass in or create a point cloud ...
// Create a set of indices to be used. For simplicity, we're going to be using the first 10% of the points in cloud
std::vector<int> indices (floor (cloud->points.size () / 10));
for (size_t i = 0; i < indices.size (); ++i) indices[i] = i;
// Create the normal estimation class, and pass the input dataset to it
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud (cloud);
// Pass the indices
boost::shared_ptr<std::vector<int> > indicesptr (new std::vector<int> (indices));
ne.setIndices (indicesptr);
// Create an empty kdtree representation, and pass it to the normal 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<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
ne.setSearchMethod (tree);
// Output datasets
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
// Use all neighbors in a sphere of radius 3cm
ne.setRadiusSearch (0.03);
// Compute the features
ne.compute (*cloud_normals);
// cloud_normals->points.size () should have the same size as the input indicesptr->size ()
}
- 估计输入数据集中的所有点的曲面法线,但使用另一个数据集估计其相邻点集。 即估计下采样版本点云中所有点的法向量的实现方法。
#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_downsampled (new pcl::PointCloud<pcl::PointXYZ>);
... read, pass in or create a point cloud ...
... create a downsampled version of it ...
// Create the normal estimation class, and pass the input dataset to it
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud (cloud_downsampled);
// Pass the original data (before downsampling) as the search surface
ne.setSearchSurface (cloud);
// Create an empty kdtree representation, and pass it to the normal estimation object.
// Its content will be filled inside the object, based on the given surface dataset.
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
ne.setSearchMethod (tree);
// Output datasets
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
// Use all neighbors in a sphere of radius 3cm
ne.setRadiusSearch (0.03);
// Compute the features
ne.compute (*cloud_normals);
// cloud_normals->points.size () should have the same size as the input cloud_downsampled->points.size ()
}