【PCL】教程 octree_search 八叉树的构建、体素内搜索、K近邻搜索和半径内搜索

使用八叉树进行空间分区和搜索操作 

八叉树是一种基于树的数据结构,用于管理稀疏的三维数据。每个内部节点都有八个子节点。在本教程中,我们将学习如何使用八叉树对点云数据进行空间分区和邻域搜索。特别是,我们将讲解如何执行 "体素内邻居搜索"、"K 最近邻搜索 "和 "半径内邻居搜索"。

终端输出:

K nearest neighbor search at (54.6875 786.5 19.9375) with K=10
    88.75 906.094 56.875 (squared distance: 16827.3)
    151.125 886.562 83.8438 (squared distance: 23396.7)
    61.9688 932.469 97.75 (squared distance: 27414.7)
    188.812 711.719 109.156 (squared distance: 31541.7)
    238.906 757.594 55.4688 (squared distance: 36034.6)
    217.594 874.125 82.25 (squared distance: 38099.4)
    170.062 628.906 0.28125 (squared distance: 38533.5)
    173.75 616.719 16.2812 (squared distance: 43014.9)
    85.6875 675.156 193.375 (squared distance: 43439)
    96.0938 816.375 222.5 (squared distance: 43638.6)
Neighbors within radius search at (54.6875 786.5 19.9375) with radius=113.641

这段代码是使用C++编写的,并且利用了PCL(Point Cloud Library,点云库)来进行点云数据的搜索和处理。主要内容包括初始化点云数据,构建八叉树索引,并通过不同的搜索方法来查询点云数据

具体来说,这段代码首先包含本PCL库中处理点云和八叉树搜索的相关头文件,还有标准输入输出头文件和向量处理头文件。在 main() 函数中完成了以下几个步骤:

  1. 初始化一个点云对象 cloud

  2. 随机生成1000个点的点云数据,这些点的X、Y、Z坐标值是通过随机数生成的。

  3. 创建一个八叉树搜索对象 octree,并设置其分辨率为128

  4. 将生成的点云数据添加到八叉树索引中。

  5. 生成一个随机的搜索点 searchPoint

  6. 执行体素内的邻域搜索,将搜索到的点索引存储在 pointIdxVec 向量中,并打印出这些点的坐标。

  7. 执行K近邻搜索,找到距离 searchPoint 最近的K个点(这里K设置为10),并打印出这些点的坐标和它们到搜索点的平方距离

  8. 最后执行半径内的邻域搜索,设置一个随机的搜索半径 radius,查找在这个半径内的所有点,并打印出它们的坐标和到搜索点的平方距离。

这段代码演示了PCL中八叉树的基本使用方法,包括八叉树的构建、体素内搜索、K近邻搜索和半径内搜索。八叉树是一种用于空间划分和快速点查找的数据结构,在点云数据处理中广泛应用。

//  包含PCL(点云库)和标准输入输出库头文件
#include <pcl/point_cloud.h> // 引入PCL库的点云定义头文件
#include <pcl/octree/octree_search.h> // 引入PCL库的八叉树搜索相关头文件


#include <iostream> // 引入标准输入输出流库,用于控制台输入输出
#include <vector> // 引入STL的vector容器类
#include <ctime> // 引入C标准库时间函数


int main ()
{
  // 初始化随机数种子
  srand ((unsigned int) time (NULL));


  // 创建一个新的点云指针
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);


  // 生成点云数据
  // 设定点云宽度为1000,高度为1,表示所有点在同一行
  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);
  }


  // 设置八叉树的分辨率
  float resolution = 128.0f;


  // 创建八叉树并设置分辨率
  pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree (resolution);


  // 设置输入点云到八叉树
  octree.setInputCloud (cloud);
  // 从输入点云中添加点到八叉树
  octree.addPointsFromInputCloud ();


  // 创建并随机生成一个搜索点
  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);


  // 体素内近邻搜索
  std::vector<int> pointIdxVec;


  // 如果搜索点的体素内存在点,则输出这些点的坐标
  if (octree.voxelSearch (searchPoint, pointIdxVec))
  {
    std::cout << "Neighbors within voxel search at (" << searchPoint.x 
     << " " << searchPoint.y 
     << " " << searchPoint.z << ")" 
     << std::endl;


    // 遍历所有在同一体素中的点并输出它们的坐标
    for (std::size_t i = 0; i < pointIdxVec.size (); ++i)
   std::cout << "    " << (*cloud)[pointIdxVec[i]].x 
       << " " << (*cloud)[pointIdxVec[i]].y 
       << " " << (*cloud)[pointIdxVec[i]].z << std::endl;
  }


  // 最近的K个邻居搜索
  int K = 10;
  std::vector<int> pointIdxNKNSearch;
  std::vector<float> pointNKNSquaredDistance;


  // 进行K邻近搜索,并输出搜索点的坐标以及K的值
  std::cout << "K nearest neighbor search at (" << searchPoint.x 
            << " " << searchPoint.y 
            << " " << searchPoint.z
            << ") with K=" << K << std::endl;


  // 如果找到了则输出每一个近邻点的坐标和它们的平方距离
  if (octree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)
  {
    for (std::size_t i = 0; i < pointIdxNKNSearch.size (); ++i)
      std::cout << "    "  <<   (*cloud)[ pointIdxNKNSearch[i] ].x 
                << " " << (*cloud)[ pointIdxNKNSearch[i] ].y 
                << " " << (*cloud)[ pointIdxNKNSearch[i] ].z 
                << " (squared distance: " << pointNKNSquaredDistance[i] << ")" << std::endl;
  }


  // 半径内邻居搜索
  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 (octree.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;
  }


}
octree.voxelSearch(searchPoint, pointIdxVec)

32198e8dcf88fc0ec409aef0c9a4c44e.png

octree.nearestKSearch(
              searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance)

57e758072acc419ea6a4f173abee90b0.png

octree.radiusSearch(
              searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance)

e0887a028a513cc410726c5ca305bde5.png

### PCL 中基于八叉树的空间变化检测 PCL(Point Cloud Library)提供了 `OCTree_OctreePointCloudChangeDetector` 类来实现点云之间的空间变化检测。该功能的核心在于利用八叉树结构对点云数据进行分层划分,并通过比较不同时间戳下的点云分布情况,识别新增或移除的。 #### 构建 CMake 工程 为了使用 PCL八叉树模块,需配置 CMake 文件以支持编译环境。以下是标准的 CMake 配置文件示例[^2]: ```cmake cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(octree_change_detection) find_package(PCL 1.2 REQUIRED) include_directories(${PCL_INCLUDE_DIRS}) link_directories(${PCL_LIBRARY_DIRS}) add_definitions(${PCL_DEFINITIONS}) add_executable(octree_change_detection octree_change_detection.cpp) target_link_libraries(octree_change_detection ${PCL_LIBRARIES}) ``` 此配置确保项目能够正确链接到 PCL 库并加载必要的头文件定义。 --- #### 八叉树初始化与设置参数 在实际应用中,可以通过以下方式创建并初始化八叉树对象: ```cpp #include <pcl/point_cloud.h> #include <pcl/octree/octree_pointcloud_changedetector.h> // 定义点类型 typedef pcl::PointXYZ PointT; int main() { // 创建点云实例 pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>); // 设置分辨率(即每个的边长) double resolution = 0.1; // 初始化八叉树对象 pcl::octree::OctreePointCloudChangeDetector<PointT> octree(resolution); } ``` 上述代码片段展示了如何指定八叉树的分辨率以及初始化过程[^1]。 --- #### 添加点云至八叉树 将初始点云添加到八叉树中以便后续对比操作: ```cpp // 将点云插入到八叉树 octree.setInputCloud(cloud); octree.addPointsFromInputCloud(); // 更新当前状态作为参考帧 octree.switchBuffers(); ``` 这里的关键步骤是调用 `switchBuffers()` 方法保存当前点云的状态,从而允许未来的新点云与其进行差异分析。 --- #### 对比新旧点云 当有新的点云到达时,可以将其加入同一棵八叉树并与之前的记录做对比: ```cpp // 假设 new_cloud 是更新后的点云集 pcl::PointCloud<PointT>::Ptr new_cloud(new pcl::PointCloud<PointT>()); new_cloud->points.push_back(PointT(x, y, z)); // 示例点坐标填充逻辑省略 // 清空现有缓存并将新点集载入 octree.setInputCloud(new_cloud); octree.addPointsFromInputCloud(); // 获取发生变化的位置集合 std::vector<int> added_indices; std::vector<int> removed_indices; octree.getAddedPointsIndices(added_indices); // 新增点索引列表 octree.getDeletedPointsIndices(removed_indices); // 移除点索引列表 ``` 以上部分实现了动态监测场景中的物移动或消失现象的功能。 --- #### 可选扩展:查询特定区域信息 如果需要进一步探索某一的具属性,则可通过如下接口完成: - **检查某个位置是否有对应存在** - **获取整棵树的最大深度** - **提取任意选定中心的世界坐标** 这些辅助工具均已在官方文档第六章节有所描述。 --- ### 总结 综上所述,借助于 PCL 提供的强大 API 支持,开发者仅需少量代码即可高效达成复杂任务目标——实时追踪三维环境中发生的细微变动状况。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值