PCL使用kd树搜索

文章目录

理论

  • kd树或k维树是计算机科学中用于组织k维空间中一些点的数据结构。它是一个二叉搜索树,上面有其他约束。Kd树对于范围搜索和最近邻居搜索非常有用。出于我们的目的,我们通常只处理三维空间的点云,因此我们所有的kd树都是三维空间的。
  • kd树的每个级别都使用垂直于相应轴的超平面沿特定维度拆分所有子级。在树的根部,所有子项都将根据第一维进行拆分(即,如果第一维坐标小于根,则它将位于左子树中,如果大于根,则显然位于右边的子树)。树中向下的每个级别都在下一个维度上划分,其他所有元素都用尽后,将返回到第一个维度。
  • 建立kd树的最有效方法是使用一种分区方法,例如快速排序所使用的一种方法,将中值点放置在根上,所有具有较小一维值的东西都放置在根上,而所有东西都在左边。然后,您在左右两个子树上都重复此过程,直到要分区的最后一棵树仅由一个元素组成。
    在这里插入图片描述
图1 kd树构建(二维平面,即k=2)
如图1 所示,我们对二维平面的点构建kd树。图2展示了kd树搜索最近邻点的流程。

在这里插入图片描述

图2 kd树搜索流程

实践

  • 以pcl的kdTree模块为例,进行点云中k近邻的检索。
#include <pcl/point_cloud.h>
#include <pcl/kdtree/kdtree_flann.h>

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

int
main (int argc, char** argv)
{
  srand (time (NULL));

  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);

  // Generate pointcloud data
  cloud->width = 1000;
  cloud->height = 1;
  cloud->points.resize (cloud->width * cloud->height);

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

  pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;

  kdtree.setInputCloud (cloud);

  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);

  // K nearest neighbor search

  int K = 10;

  std::vector<int> pointIdxNKNSearch(K);
  std::vector<float> pointNKNSquaredDistance(K);

  std::cout << "K nearest neighbor search at (" << searchPoint.x 
            << " " << searchPoint.y 
            << " " << searchPoint.z
            << ") with K=" << K << std::endl;

  if ( kdtree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0 )
  {
    for (std::size_t i = 0; i < pointIdxNKNSearch.size (); ++i)
      std::cout << "    "  <<   cloud->points[ pointIdxNKNSearch[i] ].x 
                << " " << cloud->points[ pointIdxNKNSearch[i] ].y 
                << " " << cloud->points[ pointIdxNKNSearch[i] ].z 
                << " (squared distance: " << pointNKNSquaredDistance[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->points[ pointIdxRadiusSearch[i] ].x 
                << " " << cloud->points[ pointIdxRadiusSearch[i] ].y 
                << " " << cloud->points[ pointIdxRadiusSearch[i] ].z 
                << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
  }


  return 0;
}
以下是一个简单的示例代码,演示如何使用PCL库实现kd树划分和遍历叶子节点。 ```c++ #include <iostream> #include <pcl/point_types.h> #include <pcl/kdtree/kdtree_flann.h> int main() { // 创建点云数据 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); cloud->width = 5; cloud->height = 1; cloud->points.resize(cloud->width * cloud->height); for (size_t i = 0; i < cloud->points.size(); ++i) { cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f); cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f); cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f); } // 创建kd树对象 pcl::KdTreeFLANN<pcl::PointXYZ> kdtree; kdtree.setInputCloud(cloud); // 查询点 pcl::PointXYZ searchPoint; searchPoint.x = 1024 * rand() / (RAND_MAX + 1.0f); searchPoint.y = 1024 * rand() / (RAND_MAX + 1.0f); searchPoint.z = 1024 * rand() / (RAND_MAX + 1.0f); // K近邻搜索 std::vector<int> pointIdxKNNSearch; std::vector<float> pointKNNSquaredDistance; int K = 3; kdtree.nearestKSearch(searchPoint, K, pointIdxKNNSearch, pointKNNSquaredDistance); // 遍历叶子节点 std::vector<int> pointIdxRadiusSearch; float radius = 256.0f * rand() / (RAND_MAX + 1.0f); if (kdtree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch) > 0) { for (size_t i = 0; i < pointIdxRadiusSearch.size(); ++i) std::cout << " " << cloud->points[pointIdxRadiusSearch[i]].x << " " << cloud->points[pointIdxRadiusSearch[i]].y << " " << cloud->points[pointIdxRadiusSearch[i]].z << std::endl; } return 0; } ``` 以上代码实现了以下操作: 1. 创建一个点云数据,包含5个点。 2. 使用KdTreeFLANN类创建kd树对象,并将点云数据设置为其输入。 3. 随机生成一个查询点,并执行K近邻搜索操作,找到距离该点最近的3个点。 4. 随机生成一个半径,并执行半径搜索操作,找到距离该查询点在该半径内的所有点。 代码中包含基本注释,可以帮助您更好地理解每个操作的含义和实现方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值