【PCL自学:kdTree】PCL中kd-Tree的原理及使用(持续更新)

本文介绍了Kd-Tree数据结构在三维点云处理中的作用,它是计算机科学中用于组织k维空间点的一种数据结构,特别适用于距离和最近邻搜索。在实践中,通过PCL库展示了如何构建和使用Kd-Tree进行K近邻和半径搜索,以高效查找点云中的邻近点。示例代码演示了如何生成随机点云,并利用KdTree进行KNN和半径搜索操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Kd-Tree结构体及其使用

  在本章中,我们将学习如何使用KdTree来找到一个特定的点或位置的K个最近的邻点,然后我们还将学习如何在用户指定的某个半径内(在本例中是随机的)找到所有的邻点。

1)原理:什么是kd-Tree?

  k-dTree,称为k维树,是计算机科学中用于组织k维空间中的一些点的一种数据结构。它是一棵二叉搜索树,K-d树对于距离和最近邻搜索非常有用。在进行特征点计算或者点云配准等工作时常用,可以用来减小搜索时间,我们通常只处理三维的点云,所以我们所有的k-d树都是三维的。k-d树的每一层都使用垂直于相应轴的超平面,沿着特定的维度分割所有子节点。在树的根,所有的子树将基于第一个维度进行分割(例如,如果第一个维度的坐标小于根,它将在左子树中,如果它大于根,它将明显在右子树中)。树中的每一层向下划分到下一个维度,当所有其他维度都耗尽时,返回到第一个维度。构建k-d树的最有效方法是使用一种排序划分方法,比如【快速排序】将中值放在根上,将一维值较小的值放在左边,较大的值放在右边。然后在左右子树上重复这个过程,直到要划分的最后一个树仅由一个元素组成。在二维数据上建立KD-tree结构如下图所示。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2)实践:如何使用PCL?

  如果不是专业搞计算优化的同学,对于kd-Tree的原理我们只需要做到略懂即可,找工作面试能说出其所以然就行了。在实际使用中,我们只需要知道通过把点云变成KD-Tree的排列方式可以加快搜索的速度即可。
  那么如何使用KD-Tree结构呢,或者说如何把点云排列成KD-Tree形式呢,请看如下代码:

#include <pcl/point_cloud.h>
#include <pcl/kdtree/kdtree_flann.h>

#include <iostream>
#include <vector>
#include <ctime>

int
main ()
{
  srand (time (NULL)); // 随机种子 
// [1] 创建点云指针
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
// [2] 生成一千个无序点云数据
  // Generate pointcloud data
  cloud->width = 1000;
  cloud->height = 1;
  cloud->points.resize (cloud->width * cloud->height);

  for (std::size_t i = 0; i < cloud->size (); ++i)
  {
    (*cloud)[i].x = 1024.0f * rand () / (RAND_MAX + 1.0f);
    (*cloud)[i].y = 1024.0f * rand () / (RAND_MAX + 1.0f);
    (*cloud)[i].z = 1024.0f * rand () / (RAND_MAX + 1.0f);
  }

// [3]创建KD-Tre对象
  pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
// [4]向KDTREE中传入数据,即将点云数据设置成KD-Tree结构
  kdtree.setInputCloud (cloud);
// [5]随机生成一个点
  pcl::PointXYZ searchPoint;

  searchPoint.x = 1024.0f * rand () / (RAND_MAX + 1.0f);
  searchPoint.y = 1024.0f * rand () / (RAND_MAX + 1.0f);
  searchPoint.z = 1024.0f * rand () / (RAND_MAX + 1.0f);

  
  int K = 10;
 // [6]K近邻搜索,即搜索该点周围的10个点
  std::vector<int> pointIdxKNNSearch(K);
  // [7]设置搜索距离为10
  std::vector<float> pointKNNSquaredDistance(K);

  std::cout << "K nearest neighbor search at (" << searchPoint.x 
            << " " << searchPoint.y 
            << " " << searchPoint.z
            << ") with K=" << K << std::endl;
// 开始K近邻搜索
  if ( kdtree.nearestKSearch (searchPoint, K, pointIdxKNNSearch, pointKNNSquaredDistance) > 0 )
  {
    for (std::size_t i = 0; i < pointIdxKNNSearch.size (); ++i)
      std::cout << "    "  <<   (*cloud)[ pointIdxKNNSearch[i] ].x 
                << " " << (*cloud)[ pointIdxKNNSearch[i] ].y 
                << " " << (*cloud)[ pointIdxKNNSearch[i] ].z 
                << " (squared distance: " << pointKNNSquaredDistance[i] << ")" << std::endl;
  }

  // Neighbors within radius search
// 使用半径搜索条件搜索
  std::vector<int> pointIdxRadiusSearch;
  std::vector<float> pointRadiusSquaredDistance;
// 随机生成一个搜索半径
  float radius = 256.0f * rand () / (RAND_MAX + 1.0f);
  std::cout << "Neighbors within radius search at (" << searchPoint.x 
            << " " << searchPoint.y 
            << " " << searchPoint.z
            << ") with radius=" << radius << std::endl;

// 开始半径搜索
  if ( kdtree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0 )
  {
    for (std::size_t i = 0; i < pointIdxRadiusSearch.size (); ++i)
      std::cout << "    "  <<   (*cloud)[ pointIdxRadiusSearch[i] ].x 
                << " " << (*cloud)[ pointIdxRadiusSearch[i] ].y 
                << " " << (*cloud)[ pointIdxRadiusSearch[i] ].z 
                << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
  }


  return 0;
}

【博主简介】
  斯坦福的兔子,男,天津大学机械工程工学硕士。毕业至今从事光学三维成像及点云处理相关工作。因工作中使用的三维处理库为公司内部库,不具有普遍适用性,遂自学开源PCL库及其相关数学知识以备使用。谨此将自学过程与君共享。
博主才疏学浅,尚不具有指导能力,如有问题还请各位在评论处留言供大家共同讨论。
若前辈们有工作机会介绍欢迎私信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值