PCL点云库学习笔记(搜索方法)

2023-10-27

PCL点云库学习笔记(搜索方法)

一、k-d tree

我们所有的k-d树都是三维空间的。 k-d树的每个级都使用特定维度拆分所有子级。 在树的根部,所有子项都将根据第一维进行拆分(即,如果第一维坐标小于根,则它将在左子树中;如果大于根,则显然会在 右边的子树)。 树中向下的每个级别都在下一个维度上划分,一旦所有其他级别都用尽后,将返回到第一个维度。 构造k-d树的最有效方法是使用一种分区方法,将中值点放置在根上,具有较小一维值在左子树,较大的值在右子树。 然后,在左右两个子树上都重复此过程,直到要分区的最后一棵树仅由一个元素组成。
在这里插入图片描述
理论部分见:link.
代码

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

  // 产生任意的点云数据
  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);
  }

 //创建kdtree对象,并将随机创建的云设置为输入。创建一个被分配随机坐标的searchPoint
  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;

//用于存储k个最近邻
  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;

//把KdTree计算的值和距离返回到储存点中,打印出随机搜索点的所有10个最近邻居的位置
  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;
  }

  // 使用半径进行最近邻搜索

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

二、八叉树

2.1 用八叉树进行空间搜索

#include <pcl/point_cloud.h>
#include <pcl/octree/octree_search.h>

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

int main (int argc, char** argv)
{
  srand ((unsigned int) time (NULL));
//创建一个pointcloud指针对象,并随机赋点集给它
  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);
  }
 //创建一个八叉树实例,并使用其分辨率对其进行初始化
  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);

  // PointCloud与八叉树相关联,就可以执行搜索操作。 
  //第一搜索方法是“体素近邻搜索”。 它将搜索点分配给相应的叶节点体素(三维的,相对于二维的像素),并返回点索引向量。 这些索引与属于同一体素的点有关。 

  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->points[pointIdxVec[i]].x 
       << " " << cloud->points[pointIdxVec[i]].y 
       << " " << cloud->points[pointIdxVec[i]].z << std::endl;
  }

  // K最近邻居搜索,K设置为10。将搜索结果写入两个单独的向量中。 
  //第一个pointIdxNKNSearch将包含搜索结果(引用关联的PointCloud数据集的索引)。 
  //第二向量在搜索点和最近的邻居之间保持对应的平方距离

  int K = 10;

  std::vector<int> pointIdxNKNSearch;
  std::vector<float> pointNKNSquaredDistance;

  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->points[ pointIdxNKNSearch[i] ].x 
                << " " << cloud->points[ pointIdxNKNSearch[i] ].y 
                << " " << cloud->points[ 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->points[ pointIdxRadiusSearch[i] ].x 
                << " " << cloud->points[ pointIdxRadiusSearch[i] ].y 
                << " " << cloud->points[ pointIdxRadiusSearch[i] ].z 
                << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
  }

}

2.2 无序点云的空间变化检测
使用八叉树实现来检测多个无序点云之间的空间变化,这些变化可能在大小,分辨率,密度和点排序方面有所不同。 通过递归比较八叉树的树结构,可以识别由体素组成之间的区别,它表示了空间变化。

#include <pcl/point_cloud.h>
#include <pcl/octree/octree_pointcloud_changedetector.h>

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

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

  // 八叉树的分辨率-体素的大小
  float resolution = 32.0f;

  // 初始化八叉树的点云变化检测类
  pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZ> octree (resolution);

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

  // Generate pointcloud data for cloudA
  cloudA->width = 128;
  cloudA->height = 1;
  cloudA->points.resize (cloudA->width * cloudA->height);

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

  // Add points from cloudA to octree
  octree.setInputCloud (cloudA);
  octree.addPointsFromInputCloud ();//从输出点云构建八叉树

  //点云cloudA是参考点云,八叉树结构描述了其空间分布。 
  //OctreePointCloudChangeDetector类可以同时在内存中保留和管理两个八叉树。 
  // 通过调用“ octree.switchBuffers()”,重置了octree类,同时将先前的octree结构保留在内存中。
  // 切换八叉树缓冲区:这将重置八叉树,但在内存中保留以前的树结构
  octree.switchBuffers ();

  pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB (new pcl::PointCloud<pcl::PointXYZ> );
   
  // Generate pointcloud data for cloudB 
  cloudB->width = 128;
  cloudB->height = 1;
  cloudB->points.resize (cloudB->width * cloudB->height);

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

  // Add points from cloudB to octree
  octree.setInputCloud (cloudB);
  octree.addPointsFromInputCloud ();

  std::vector<int> newPointIdxVector;

  //调用getPointIndicesFromNewVoxels,返回cloudb中新增的索引向量,探测出cloudB相对于cloudA变化的点集,
  //只能探测到cloudA上增加的点集,不能判断减少的点集
  // Get vector of point indices from octree voxels which did not exist in previous buffer
  octree.getPointIndicesFromNewVoxels (newPointIdxVector);

  // Output points
  std::cout << "Output from getPointIndicesFromNewVoxels:" << std::endl;
  for (std::size_t i = 0; i < newPointIdxVector.size (); ++i)
    std::cout << i << "# Index:" << newPointIdxVector[i]
              << "  Point:" << cloudB->points[newPointIdxVector[i]].x << " "
              << cloudB->points[newPointIdxVector[i]].y << " "
              << cloudB->points[newPointIdxVector[i]].z << std::endl;

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PCL点云库学习笔记(搜索方法) 的相关文章

随机推荐

  • cab补丁包离线安装命令

    dism online add package packagepath xxxxx xxxxx xxxx xxxx Windows10 0 KB4471329 x64 cab 因为补丁在共享盘 自己替换xxx的内容以及补丁名字
  • this.$router.options.routes

    this router options routes 可以拿到初始化时配置的路由规则 this route 可以拿到当前路由信息 包括路由路径 参数0
  • zookeeper 系列(2) 启动流程

    虽然天天在看源码 但很久没有写博客了 从这周开始写点系列 不写文章 就整些流程图吧
  • Linux部署Seata详细过程记录

    Seata服务搭建 Seata官方文档地址 Seata安装包下载地址 依赖版本说明地址 SpringCloudAlibaba版本对应组件版本说明 详细参考官网文档 当前使用Spring cloud alibaba对应的seata版本为v1
  • 中国需要怎样的智慧城市联盟?中外41家联盟组织大起底

    自2009年 智慧地球 概念的提出 智慧城市 作为支撑该系统性设想的组成部分 正在全球范围内 被多数发达和发展中国家所接受并在城市层面开展实践 开展智慧城市规划建设是数字城市 平安城市 数字化 信息化和物联网等 的升级性目标 为有效保障智慧
  • 1.3.6 手写数字识别之训练调试与优化.md

    文章目录 概述 一 计算模型的分类准确率 二 检查模型训练过程 三 加入校验或测试 四 加入正则化项 4 1 过拟合现象 4 2 导致过拟合原因 4 3 过拟合的成因与防控 4 4 正则化项 五 可视化分析 5 1 使用Matplotlib
  • 2022最新软件测试八股文,能不能拿心仪Offer就看你背得怎样了

    前言 鉴于目前测试就业越来越严峻 内卷也成了测试领域的代名词了 我的一个HR朋友告诉我 由于门槛较低 现在普通测试岗 偏功能 的投递比已经将近100 也就是一个岗位差不多有百分简历投进来 所以现在还想从事软件测试行业的小伙伴们 想要心仪的工
  • qt QTimer 提示 不能在另外一个线程停止

    发送 信号 停止 timer 提示 QObject killTimer Timers cannot be stopped from another threadQObject QObject Timers cannot be stopped
  • Spring之Ioc工作流程

    springIoc容器创建流程 在AbstractApplicationContext refresh 中描述了创建ioc的过程 1 前期准备校验参数等 prepareRefresh 2 创建beanFactory工厂对象 还把配置文件中的
  • sort函数数组排序(c++方法)

    sort函数的调用需要头文件 include 从小到大排 例如 a 50 2 3 5 1 1 想让它按照从小到大的顺序排列 那么就可以这么写 sort a a 5 然后数组就会变成 1 1 2 3 5 具体代码如下 include
  • 小菜鸡刷CTF

    一个小菜鸡的CTF成长史 本人小菜鸡一枚 刚入门CTF 不对 应该是脚刚刚沾上了CTF的边边 就只是在刷攻防世界中的题目 无奈脑子太笨 记性太差 只好将题目整理下来 代码多有借鉴 求勿喷 新手练习 题目一 base64 题目来源 poxlo
  • Kotlin手写RxJava变换符

    Kotlin手写RxJava变换符 本文链接 点击这里进入 1 核心点 中转站存储之前的数据 2 三行代码实现RxJava 使用create map observer fun main create构造出RxJavaCore存放 lambd
  • Open3D 入门教程

    文章目录 1 概述 2 安装 3 点云读写 4 点云可视化 4 1 可视化单个点云 4 2 同一窗口可视化多个点云 4 3 可视化的属性设置 5 k d tree 与 Octree 5 1 k d tree 5 2 Octree 5 2 1
  • Redis密码相关知识总结

    背景 工作中 生产环境的Redis集群都是无密码的 存在安全隐患 现在需要对Redis集群进行密码设置 相关工作总结如下 基础知识 requirepass redis实例自身的连接密码 当客户端请求连接当前Redis服务器时 需要使用的密码
  • 【Yarn】Yarn 是如何提交 MapReducer程序到Yarn集群的

    文章目录 1 概述 3 1 案例 3 2 waitForCompletion 3 3 submit 3 4 connect 3 5 submitJobInternal 3 6 submitJob 3 7 createApplicationS
  • 第五章:多重循环及程序调试

    第五章 多重循环及程序调试 一 什么是多重循环 多重循环 一个循环体内又包含另一个完整的循环结构 例子 while 循环条件1 循环操作1 while 循环条件2 循环操作2 do 循环操作1 do 循环操作2 while 循环条件2 wh
  • 基于libVLC的视频播放器(支持RTSP协议)

    VLC Media Player是一款优秀的播放器 大多数多媒体开发人员都使用过 VLC是一款开源的 跨平台的 可扩展的 多媒体播放器 流媒体服务器及框架 可播放大多数多媒体文件 以及DVD 音频CD VCD及各类流媒体协议 现更名为VLC
  • 自学黑客(网络安全),一般人我劝你还是算了吧

    一 自学网络安全学习的误区和陷阱 1 不要试图先成为一名程序员 以编程为基础的学习 再开始学习 我在之前的回答中 我都一再强调不要以编程为基础再开始学习网络安全 一般来说 学习编程不但学习周期长 而且实际向安全过渡后可用到的关键知识并不多
  • vue深度css样式

    vue 2 gt gt gt 或者 deep 或者 v deep vue 3 deep class
  • PCL点云库学习笔记(搜索方法)

    PCL点云库学习笔记 搜索方法 一 k d tree 二 八叉树 一 k d tree 我们所有的k d树都是三维空间的 k d树的每个级都使用特定维度拆分所有子级 在树的根部 所有子项都将根据第一维进行拆分 即 如果第一维坐标小于根 则它