[PCL] 点云特征估计

3D点云特征描述与提取是点云信息处理中最基础也是最关键的一部分,点云的识别、分割、重采样、配准、曲面重建等处理大部分算法,都严重依赖特征描述与提取的结果。从尺度上来分,一般分为局部特征的描述和全局特征的描述,例如局部的法线等几何形状特征的描述,全局的拓朴特征的描述,都属于3D点云特征描述与提取的范畴。

和数字图像处理中的特征点概念类似的,3D系统概念中所定义的点,使用它们的笛卡尔坐标x、y、z来表示。假设坐标系统的原点不随时间变化,可能有两个点p1和p2,分别在t1和t2处得到,具有相同的坐标。然而,比较这些点是一个ill-posed的问题,因为即使它们相对于某些距离度量(如欧几里得度量)是相等的,它们也可能是在完全不同的表面上采样的,因此,当它们与周围的其他点放在一起时,代表完全不同的信息。这是因为不能保证世界空间上在t1和t2之间没有变化。一些采集设备可能会为采样点提供额外的信息,如强度,甚至是颜色,但这并不能完全解决问题。

由于各种原因需要比较点的应用程序需要更好的特性和度量,以便能够区分几何表面。因此,三维点作为具有笛卡尔坐标的奇异实体的概念,取而代之的是一个新的概念,即局部描述符。

通过包含周围的邻居,可以在特征公式中推断表面几何形状。理想情况下,对于位于相同或相似表面上的点,合成的特征将非常相似(相对于某些度量),而对于位于不同表面上的点,合成的特征将非常不同,如下图所示。一个好的点特征表示法与一个坏的点特征表示法不同,它能够在以下情况下捕获相同的局部表面特征,即下面几个条件通过能否获得相同的局部表面特征值判定点特征表示方式的优劣:

  1. 刚体转换,即数据中的3D旋转和3D平移不应影响最终的特征向量F估计,即特征向量具有旋转平移不变性;
  2. 改变采样密度,原则上,采样密度或多或少的局部表面贴片应该具有相同的特征向量特征;
  3. 噪声,点特征表示必须在其特征向量中保留相同或非常相似的值,即使数据中存在轻微的噪声。

通常,PCL中特征向量利用快速kd-tree查询,使用近似法来计算查询点的最近邻元素,通常有两种查询类型:

  • 确定查询点的k(用户给定参数)邻域(也称为K-搜索);
  • 确定半径为r的球体(也称为半径搜索)内查询点的所有邻域。

输入点云数据

pcl中的所有类都继承自pcl::PCLBase类,pcl::feature类通过两种方式接收输入数据:

整个点云数据集:setInputCloud (PointCloudConstPtr &),试图估计给定输入点云中的每个点的特征。

点云数据集的子集:setInputCloud (PointCloudConstPtr &) 和 setIndices (IndicesConstPtr &)结合,尝试估计给定输入点云中在给定索引列表中有索引的每个点上的特征。默认情况下,如果没有给定一组索引,则会考虑云中的所有点。

此外,可以通过调用setSearchSurface(PointCloudConstPtr &)指定要使用的点邻域集。这个调用是可选的,当搜索平面没有给定时,默认使用输入点云数据集。

因为setInputCloud()接口总是必需的,所以我们可以使用最多四种组合来创建点云输入(setInputCloud(), setIndices(), setSearchSurface())。

图示两个点云P和Q的特征点情况。

1. setIndices() = false, setSearchSurface() = false。因为我们不期望根据给定的一组索引或搜索表面来维护不同的实现副本,所以此时,PCL创建一组内部索引(std::vector<int>),指向整个数据集(indexes=1..N,其中N为云中的点数)。在上图中,这对应于最左边的情况,首先,我们估计p_1的最近邻域,然后是p_2的最近邻域,以此类推,直到我们耗尽P中的所有点。

2. setIndices() = true, setSearchSurface() = false。在上图中,这对应于第二种情况。在这里,我们假设p_2的索引不是给定索引向量的一部分,所以在p2处没有邻居或特征。

3. setIndices() = false, setSearchSurface() = true。在上图中,这对应于第三种情况。如果Q={q_1, q_2}是另一个给定的点云作为输入,与P不同,P是Q的搜索面,那么q_1和q_2的邻居将从P中寻找和计算。

4. setIndices() = true, setSearchSurface() = true。在上图中,这对应于最后一种情况。邻域点将会在两个点云中进行计算,且考虑点的索引是否位于索引向量中。

当我们有一个非常密集的输入数据集,但我们不想估计所有点的特征,而是只希望估计一些关键点的特征,或希望处理下采样点云(例如使用pcl::VoxelGrid过滤器获取的下采样点云),此时,setSearchSurface()应该使用。

例程

一旦确定邻域以后,查询点的邻域点可以用来估计一个局部特征描述子,它用查询点周围领域点描述采样面的几何特征,描述几何表面图形的一个重要属性,首先是推断它在坐标系中的方位,也就是估计他的法线,表面法线是表面的一个重要的属性,在许多领域都有重要的应用,如果用光源来生成符合视觉效果的渲染等。

下面的代码用于估计输入数据集中所有点的一组表面法线:normal_estimate.cpp

#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 (std::floor (cloud->points.size () / 10));
  for (std::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 ()
}

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: pcl pcl 1.11.1 是一个开源的 3D 机器视觉库,用于处理点数据和进行 3D 数据处理、图像处理和计算几何等复杂的计算任务。它提供了大量的工具和算法,包括点滤波、分割、重构、注册等,可以用于许多应用领域,如机器人学、自动驾驶、虚拟现实等。 pcl 1.11.1 是 pcl库的最新版本,新增了许多重要的功能和改进,包括支持更多的文件格式、更高效的 I/O 性能、精度更高的运动估计算法、更方便的可视化工具等。此外,它还加入了深度学习相关的功能,如点到图像的转换、特征提取和分类等,可以更好地支持深度学习应用的开发和实现。 总之,pcl pcl 1.11.1 是一个功能强大、灵活可扩展的 3D 机器视觉库,适用于各种计算机视觉应用场景。无论是学术研究还是工业应用,都可以通过 pcl库来实现高效、准确的 3D 数据处理和分析。 ### 回答2: PCL (Point Cloud Library) 是一个用于点处理的开源 C++ 库,支持点的装载、过滤、特征提取、配准、分割、稠密重建等操作。其最新版本为 PCL 1.11.1,于 2020 年 11 月发布。 PCL 1.11.1 中新增了许多功能和改进,如点网络处理库 PointNet、全息投影模块、新的欧拉角和旋转矩阵表示、增加了刚体、仿射和投影变换支持等。此外,还改进了 PCL 的核心代码,提高了稳定性、速度和可靠性,修复了许多 bug。 PCL 的应用广泛,包括机器人、自动驾驶、室内外建模、地图构建、医学成像等领域。例如,PCL 可以用于机器人的环境感知,通过融合多种传感器数据获得更准确的环境模型;同时,PCL 也可用于医学图像分析,如三维重建和影像分割等。 总之,PCL 是一个功能强大的开源点处理库,不断更新和改进,为点处理和相关领域的研究提供了重要支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值