通过八叉树进行空间分割和搜索

一个octree是一个以树基础为的管理稀疏3-D数据的数据结构。每个中间的节点有8个子节点。在这次,我们将学习怎么使用octree进行稀疏分割和近邻搜索。尤其,我们将解释如何操作"体元近邻搜索",和"最近邻搜索"和"半径近邻搜索".
我们将创建一个octree_search.cpp这个文件
#include <pcl/point_cloud.h>
#include <pcl/octree/octree.h>

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

int
main (int argc, char** argv)
{
  srand ((unsigned int) 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 (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);

  // Neighbors within voxel search

  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 (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 nearest neighbor search

  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 (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 (octree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 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
                << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
  }

}
代码解释
定义和实例化了一个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 (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);
  }
接下去我们创造了一个用下面的这个分辨率为初始化的octree实例。octree保持了它的叶子节点的点下标。分辨率参数描述了小体元的长度。octree的深度因此是一个分辨率的函数和点云的空间维度一样。如果一个点云的边框盒子已知,它通过使用defineBoundingBox这个方法分配给octree。然后我们把一个指针分配给点云并把所有的点加入到octree里面。

  float resolution = 128.0f;

  pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree (resolution);

  octree.setInputCloud (cloud);
  octree.addPointsFromInputCloud ();

一旦点云与octree相联系上,我们就能使用搜索的操作。我们第一个搜索方法"Neighbors within Voxel Search"。它将被分配给相应叶子节点的体元的搜索点并返回一个点下标的向量。这个下标和进入同一个体元里面的点有关系。搜索点与搜索结果距离依赖于octree的分辨率。


  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 (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,"K最近邻搜索"的方法的搜索结果被写入两个独立的向量里面。第一个,pointIdxNKNSearch,将会包含搜索结果(与相邻点云数据集相关的下标)。第二个下标向量保持相应的搜索得到节点和最近邻之间的平方距离。


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

指定半径内的邻居搜索和"最近邻搜索"相似。它的搜索结果被写成2个独立的向量,描述了下标点和搜索点的平方距离。

 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 (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;
  }
下面是运行结果
Neighbors within voxel search at (974.82 188.793 138.779)
    903.656 82.8158 162.392
    1007.34 191.035 61.7727
    896.88 155.711 58.1942
K nearest neighbor search at (974.82 188.793 138.779) with K=10
    903.656 82.8158 162.392 (squared distance: 16853.1)
    903.18 247.058 54.3528 (squared distance: 15655)
    861.595 149.96 135.199 (squared distance: 14340.7)
    896.88 155.711 58.1942 (squared distance: 13663)
    995.889 116.224 219.077 (squared distance: 12157.9)
    885.852 238.41 160.966 (squared distance: 10869.5)
    900.807 220.317 77.1432 (squared distance: 10270.7)
    1002.46 117.236 184.594 (squared distance: 7983.59)
    1007.34 191.035 61.7727 (squared distance: 6992.54)
    930.13 223.335 174.763 (squared distance: 4485.15)
Neighbors within radius search at (974.82 188.793 138.779) with radius=109.783
    1007.34 191.035 61.7727 (squared distance: 6992.54)
    900.807 220.317 77.1432 (squared distance: 10270.7)
    885.852 238.41 160.966 (squared distance: 10869.5)
    1002.46 117.236 184.594 (squared distance: 7983.59)
    930.13 223.335 174.763 (squared distance: 4485.15)
一些额外的细节
PCL八叉树组件里面提供了几种八叉树的类型。他们通过他们的独特的叶子节点特征来区别。
OctreePointCloudPointVector(等于OctreePointCloud):这个octree可以包含每个叶子节点的一系列的点的下标。
OctreePointCloudSinglePoint:这个八叉树类在每一个叶子节点里面包含一个点的下标。只有被分配到叶子节点里面最多的下标将会被存储。
OctreePointCloudOccupancy:这个八叉树没有存储任何点的信息在它的叶子节点上。
OctreePointCloudDensity:这个octree计算每个叶子节点体元的数量。它允许特殊的空间密度查询。

如果八叉树需要经常被创建,请看一下八叉树的double buffering implementation(Octree2BufBase这个类)。这个类同时保持两个并行的八叉树结构在内存里面。除了每个搜索操作,它也使得空间改变检测成为可能。更多,一个先进的内存管理减少了内存分配和回收操作在octree构建的时候。
总结:
PCL里面的octree是一个进行空间分割和搜索的有力的工具。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/566196.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从一个点云里面创建一个深度图

这次&#xff0c;我们将显示如何从一个点云和一个给定的传感器来创造深度图。下面的代码&#xff0c;创建了一个在观察者前面的矩形。 #include <pcl/range_image/range_image.h>int main (int argc, char** argv) {pcl::PointCloud<pcl::PointXYZ> pointCloud;//…

从深度图里面导出边界

这次我们将学着怎么从一个深度图里面导出边界。我们对3种不同种类的点很感兴趣:物体的边框的点&#xff0c;阴影边框点&#xff0c;和面纱点(在障碍物边界和阴影边界)&#xff0c;这是一个很典型的现象在通过雷达获取的3D深度。 下面是代码 /* \author Bastian Steder */#incl…

以相关组为基础的3D物体识别

这次我们要解释如何以pcl_recognition模块来进行3D物体识别。特别地&#xff0c;它解释了怎么使用相关组算法为了聚类那些从3D描述器算法里面把当前的场景与模型进行匹配的相关点对点的匹配。(长难句)。对于每一次聚类&#xff0c;描绘了一个在场景中的可能模型实例&#xff0c…

隐式形状模型

在这次我们将学会隐式形状模型算法通过pcl::ism::ImplicitShapeModel这个类来实现。这个算法是把Hough转换和特征近似包进行结合。有训练集&#xff0c;这个算法将计算一个确定的模型用来预测一个物体的中心。 这个算法由两部分组成&#xff0c;第一部分是训练&#xff0c;第二…

3D物体识别的假设检验

3D物体识别的假设验证 这次目的在于解释如何做3D物体识别通过验证模型假设在聚类里面。在描述器匹配后&#xff0c;这次我们将运行某个相关组算法在PCL里面为了聚类点对点相关性的集合&#xff0c;决定假设物体在场景里面的实例。在这个假定里面&#xff0c;全局假设验证算法将…

怎么样递增的注册成对的点云

这次我们将使用Iterative Closest Point algorithm来递增的注册一系列的点云。 这个主意来自于把所有的点云转换成第一个点云的框架&#xff0c;通过找到每个连续点云间最好的装换&#xff0c;并且计算整个点云的转换。 你的数据集应该由重新排列的&#xff0c;在一个相同的框…

qt入门

&#xfeff;&#xfeff;qt入门 1.首先我们先创建一个qt的空项目 1.这会生成两个文件 xx.pro xx.pro.user xx.pro文件是qt的工程文件&#xff0c;有点类似于vc的prj文件&#xff0c;或者sln文件。xx.pro.user是这个当前环境下的工程文件。(移植的时候这个文件没啥用) 以…

新手博客,开博立言_Youcans2021

这是我的第一篇博客。 今后我会将我的学习心得和总结在这里发布&#xff0c;与大家共享&#xff0c;共勉。

qt输入框

&#xfeff;&#xfeff;qt里面的输入框是QLineEdit这个类来实现的。 下面是代码 /* 应用程序抽象类 */ #include <QApplication>/*窗口类*/ #include <QWidget> #include <QCompleter> #include <QLineEdit>int main(int argc, char* argv[]) {QAp…

Python数模笔记-PuLP库(2)线性规划进阶

1、基于字典的创建规划问题 上篇中介绍了使用 LpVariable 对逐一定义每个决策变量&#xff0c;设定名称、类型和上下界&#xff0c;类似地对约束条件也需要逐一设置模型参数。在大规模的规划问题中&#xff0c;这样逐个定义变量和设置模型参数非常繁琐&#xff0c;效率很低。P…

qt坐标系统与布局的简单入门

&#xfeff;&#xfeff;qt坐标系统 qt坐标系统比较简单 button.setGeometry(20,20,100,100); 上面的代码把按钮显示为父窗口的20,20处宽度为100&#xff0c;高度为100 接下去是布局 qt里面布局需要加入<QLayout.h>这个头文件。 qt里面垂直布局 qt里面的垂直布局…

Python数模笔记-PuLP库(1)线性规划入门

1、什么是线性规划 线性规划&#xff08;Linear programming&#xff09;&#xff0c;在线性等式或不等式约束条件下求解线性目标函数的极值问题&#xff0c;常用于解决资源分配、生产调度和混合问题。例如&#xff1a; max fx 2*x1 3*x2 - 5*x3 s.t. x1 3*x2 x3 < 1…

qt控件基本应用

Qt里面有很多控件&#xff0c;让我们来看一些常用控件。 首先是对pro文件的配置 HEADERS \ MyWidget.h SOURCES \ MyWidget.cpp QTwidgets gui CONFIG c11 因为要用到lambda所以要加一个CONFIGc11 下面是MyWidget.h #ifndef MYWIDGET_H #define MYWIDGET_H#include &…

Python数模笔记-PuLP库(3)线性规划实例

本节以一个实际数学建模案例&#xff0c;讲解 PuLP 求解线性规划问题的建模与编程。 1、问题描述 某厂生产甲乙两种饮料&#xff0c;每百箱甲饮料需用原料6千克、工人10名&#xff0c;获利10万元&#xff1b;每百箱乙饮料需用原料5千克、工人20名&#xff0c;获利9万元。 今工…

深度学习资料整理

本文是转载了别人的博客&#xff0c;然后还加上了自己到淘宝上买的百度云盘资料(还包括一些数据挖掘&#xff0c;大数据之类的教程)。 编者按&#xff1a;本文收集了百来篇关于机器学习和深度学习的资料&#xff0c;含各种文档&#xff0c;视频&#xff0c;源码等。而且原文也会…

Python数模笔记-模拟退火算法(1)多变量函数优化

1、模拟退火算法 模拟退火算法借鉴了统计物理学的思想&#xff0c;是一种简单、通用的启发式优化算法&#xff0c;并在理论上具有概率性全局优化性能&#xff0c;因而在科研和工程中得到了广泛的应用。 退火是金属从熔融状态缓慢冷却、最终达到能量最低的平衡态的过程。模拟退…

Python数模笔记-模拟退火算法(2)约束条件的处理

1、最优化与线性规划 最优化问题的三要素是决策变量、目标函数和约束条件。 线性规划&#xff08;Linear programming&#xff09;&#xff0c;是研究线性约束条件下线性目标函数的极值问题的优化方法&#xff0c;常用于解决利用现有的资源得到最优决策的问题。 简单的线性规…

Python数模笔记-模拟退火算法(3)整数规划问题

1、整数规划问题 整数规划问题在工业、经济、国防、医疗等各行各业应用十分广泛&#xff0c;是指规划中的变量&#xff08;全部或部分&#xff09;限制为整数&#xff0c;属于离散优化问题&#xff08;Discrete Optimization&#xff09;。 线性规划问题的最优解可能是分数或小…

数据结构之算法特性及分类

数据结构之算法特性及分类 算法的特性 1.通用性。2.有效性。3.确定性4.有穷性。基本算法分类 1.穷举法顺序查找K值2.回溯,搜索八皇后&#xff0c;树和图遍历3.递归分治二分查找K值&#xff0c;快速排序&#xff0c;归并排序。4.贪心法Huffman编码树&#xff0c;最短路Dijkstra…

Python数模笔记-模拟退火算法(4)旅行商问题

1、旅行商问题(Travelling salesman problem, TSP) 旅行商问题是经典的组合优化问题&#xff0c;要求找到遍历所有城市且每个城市只访问一次的最短旅行路线&#xff0c;即对给定的正权完全图求其总权重最小的Hamilton回路&#xff1a;设有 n个城市和距离矩阵 D[dij]&#xff0…