Features
pcl::Feature 以两种方式输入数据
- 整个点云数据集,通过setInputCloud (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中最常用的情况,即用户只是输入一个PointCloud数据集,并期望在云中的所有点上估计出某种特征。
由于我们不希望根据是否给出一组索引和/或搜索面来维护不同的实现副本,因此只要索引=false,PCL就会创建一组内部索引(作为std::vector),基本上指向整个数据集(indices=1…N,其中N是云中的点数量)
在上图中,这与最左边的情况相对应。首先,我们估计p_1的最近的邻居,然后是p_2的最近的邻居,以此类推,直到我们用尽P中的所有点。 -
setIndices() = true, setSearchSurface() = false - 如前所述,特征估计方法将只计算那些在给定的索引向量中具有索引的点的特征。
在上图中,这对应的是第二种情况。在这里,我们假设p_2的索引不在给定的索引向量中,所以p2没有邻居或特征将被估计。 -
setIndices() = false, setSearchSurface() = true - 与第一种情况一样,将对所有输入点进行特征估计,但是,setSearchSurface()中给出的底层邻接面将被用来获得输入点的最近邻接点,而不是输入云本身。
在上图中,这对应的是第三种情况。如果Q={q_1, q_2}是另一个与P不同的输入云,并且P是Q的搜索面,那么q_1和q_2的邻居将从P计算出来。 -
setIndices() = true, setSearchSurface() = true - 这可能是最罕见的情况,即同时给出指数和搜索面。在这种情况下,将只对<input, indices>对中的一个子集进行特征估计,使用 setSearchSurface() 中给出的搜索面信息。
最后,在上图中,这对应于最后一种(最右边)情况。在这里,我们假设q_2的索引不是Q的索引向量的一部分,所以没有邻居或特征将被估计在q2。
使用 setSearchSurface() 的最有用的例子是,我们有一个非常密集的输入数据集,但我们不想在其中的所有点上估计特征,而是在使用 pcl_keypoints 中的方法发现的一些关键点上,或者在云的下采样版本(例如,使用 pcl::VoxelGrid 过滤器获得)上。在这种情况下,我们通过setInputCloud()传递降采样/关键点输入,并通过setSearchSurface()传递原始数据。
An example for normal estimation
一旦确定,查询点的邻接点就可以用来估计一个局部特征表示,以捕捉查询点周围底层采样表面的几何形状。描述曲面几何的一个重要问题是首先推断其在坐标系中的方向,也就是估计其法线。表面法线是表面的重要属性,在许多领域都被大量使用,如计算机图形应用,以应用正确的光源,产生阴影和其他视觉效果(更多信息见[RusuDissertation])。
- 下面的代码片段将为输入数据集中的所有点估计一组表面法线。
#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->size () should have the same size as the input cloud->size ()
}
…待续