Octree(八叉树)

article/2025/10/28 23:29:13

1. 算法原理

八叉树(Octree)是一种用于描述三维空间的树状数据结构。八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,将八个子节点所表示的体积元素加在一起就等于父节点的体积。八叉树是四叉树在三维空间上的扩展,二维上我们有四个象限,而三维上,我们有8个卦限。八叉树主要用于空间划分和最近邻搜索。

Building an orthtree in 3D (octree) from a point cloud
左:将立方体递归细分为八分圆。右:相应的八叉树。

实现Octree的原理

  • 将当前的立方体细分为八个子立方体。
  • 如果任何一个子立方体内包含多个点,则将其进一步细分为八个子立方体。
  • 重复以上操作使得每个子立方体内包含最多一个点。

2. 实现

class OccupancyVoxelTree:
# only root node's parent node is None
def __init__(self, min_voxel_sizes=np.ones(3), parent_node=None, depth=0):self.min_voxel_sizes = min_voxel_sizesself.num_points = 0self.points = np.array([])self.center = np.zeros(3, float)self.min_values = np.zeros(3, float)self.max_values = np.zeros(3, float)self.parent_node = parent_nodeself.depth = depthself.voxel_indices = np.zeros(3, int)self.child_nodes = []self.is_leaf = Falsedef get_tree_points(self):if self.is_leaf:return [self.points]else:points = []for node in self.child_nodes:if node is not None:points.extend(node.get_tree_points())return points# only root node call this method
def build_tree(self, points):min_values = np.min(points, axis=0)max_values = np.max(points, axis=0)center = (min_values + max_values) * 0.5num_grids = np.max((max_values - min_values) / self.min_voxel_sizes)num_grids = 2 ** int(math.ceil(math.log2(num_grids)))half_sizes = self.min_voxel_sizes * (num_grids * 0.5)self.min_values = center - half_sizesself.max_values = center + half_sizesself.build_child_tree(points)def empty(self):return self.num_points == 0def get_all_leaves(self):if self.is_leaf:return [self]else:leaves = []for node in self.child_nodes:if node is not None:leaves.extend(node.get_all_leaves())return leavesdef get_neighbors(self):indices_from_root = self.get_indices_from_root()neighbors = []for i in range(-1, 2):for j in range(-1, 2):for k in range(-1, 2):voxel_indices = self.voxel_indices + np.array([i, j, k])neighbors.append(self.parent_node.get_voxel(voxel_indices, 1))return neighborsdef get_voxel(self, indices, depth_from_this_node):if depth_from_this_node > 1:half_octave = 2 ** (depth_from_this_node - 1)octave = half_octave * 2if np.any(indices < 0) or np.any(indices >= octave):voxel_indices = self.voxel_indices * 2 + indicesreturn self.parent_node.get_voxel(voxel_indices, depth_from_this_node + 1)else:child_indices = indices // half_octaveindices_from_child = indices - child_indices * half_octavechild_node = self.get_child_node(child_indices)if child_node is None:return Noneelse:return child_node.get_voxel(indices_from_child, depth_from_this_node - 1)elif self.is_leaf:return selfelif np.all(np.abs(indices) < 2):  # depth is 1child_node = self.get_child_node(indices)if child_node is None:return Noneelse:return child_nodeelse:  # depth is 1voxel_indices = self.voxel_indices * 2 + indicesreturn self.parent_node.get_voxel(voxel_indices, depth_from_this_node + 1)def get_child_node(self, indices):child_index = indices[0] * 4 + indices[1] * 2 + indices[2]return self.child_nodes[child_index]def get_indices_from_root(self):if self.parent_node is None:return self.voxel_indiceselse:return self.voxel_indices + 2 * self.parent_node.get_indices_from_root()def get_child_center_points(self):if self.is_leaf:return [self.center]else:points = []for child_node in self.child_nodes:if child_node is not None:points.extend(child_node.get_child_center_points())return pointsdef get_all_voxels(self):if self.is_leaf:return [self.center], [self]else:centers, voxels = [], [], []for child_node in self.child_nodes:if child_node is not None:child_centers, child_voxels = child_node.get_all_voxels()centers.extend(child_centers)voxels.extend(child_voxels)return centers, voxelsdef visualize(self):points = self.get_child_center_points()pcd = o3d.geometry.PointCloud()pcd.points = o3d.utility.Vector3dVector(np.vstack(points))o3d.visualization.draw_geometries([pcd])def build_child_tree(self, points):self.num_points = points.shape[0]# print("Number of points", self.num_points, self.min_values, self.max_values)self.center = (self.max_values + self.min_values) * 0.5half_sizes = (self.max_values - self.min_values) * 0.5if self.empty():return Falseif np.any(half_sizes < self.min_voxel_sizes):self.points = pointsself.is_leaf = Truereturn Trueelse:points_3d = pointsfor i in range(2):for j in range(2):for k in range(2):child_node = OccupancyVoxelTree(self.min_voxel_sizes, self, self.depth + 1)child_node.voxel_indices = np.array([i, j, k])child_node.min_values = self.min_values + child_node.voxel_indices * half_sizeschild_node.max_values = child_node.min_values + half_sizespoint_indices = np.where(np.all(points_3d >= child_node.min_values, axis=1) &np.all(points_3d < child_node.max_values, axis=1))[0]if child_node.build_child_tree(points[point_indices, :]):self.child_nodes.append(child_node)else:self.child_nodes.append(None)return True

3. 开源库

PCL八叉树组件提供了几种八叉树类型。它们的主要区别在于它们的单个叶节点特征。

OctreePointCloudPointVector(等于OctreePointCloud):这个八叉树可以在每个叶节点上保存一个点索引列表。
OctreePointCloudSinglePoint:这个八叉树类在每个叶节点上只有一个单点索引。仅存储分配给叶节点的最近的点索引。
OctreePointCloudOccupancy:这个八叉树在它的叶子节点上不存储任何点信息。它可以用于空间占用检查。
OctreePointCloudDensity:这个八叉树计算每个叶节点体素内的点的数量。它允许空间密度查询。
如果需要高速创建八叉树,请查看八叉树双缓冲实现(Octree2BufBase类)。这个类同时在内存中保存两个并行的八叉树结构。除了搜索操作之外,这还支持空间变化检测。此外,高级内存管理减少了八叉树构建过程中的内存分配和回收操作。双缓冲八叉树实现可以通过模板参数OctreeT赋值给所有的OctreePointCloud类。
所有八叉树都支持八叉树结构和八叉树数据内容的序列化和非序列化。

 #include <pcl/point_cloud.h>#include <pcl/octree/octree_search.h>#include <iostream>#include <vector>#include <ctime>intmain (){srand ((unsigned int) time (NULL));// [1]创建点云指针pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);// [2] 构造1000个随机的点云数据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;// [3]八叉树点云搜索实例pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree (resolution);// [4]将点云设置成八叉树结构octree.setInputCloud (cloud);octree.addPointsFromInputCloud ();// [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);//**************************体素搜索(搜索相同体素内的点)************************// [6]创建点云索引容器std::vector<int> pointIdxVec;// [7]开始进行体素内近邻点搜索if (octree.voxelSearch (searchPoint, pointIdxVec)){// [8] 将查找点所在体素内的邻点全都输出打印到命令窗口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近邻搜索(搜索K个最近点)************************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;// 开始最近K邻搜索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;}//*************************K近邻搜索(搜索半径范围内的点)************************// 创建半径范围内点索引的容器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;}}

参考文献

几何体数据结构学习(2)八叉树 - 知乎

【PCL自学:ocTree】八叉树(octree)的原理及应用案例(点云压缩,搜索,空间变化)_斯坦福的兔子的博客-CSDN博客 


http://chatgpt.dhexx.cn/article/pHDt6Qgj.shtml

相关文章

【PCL自学:ocTree】八叉树(octree)的原理及应用案例(点云压缩,搜索,空间变化)

PCL中八叉树&#xff08;octree&#xff09;的原理及应用案例 一、什么是八叉树ocTree&#xff1f;1.八叉树原理 二、八叉树应用案例1.点云压缩2.用八叉树进行空间划分和搜索操作3.无序点云数据的空间变化检测 一、什么是八叉树ocTree&#xff1f; 1.八叉树原理 上世纪80年代&…

十进制小数化为二进制小数的方法是什么_十进制转成二进制的两种方式

第一种&#xff1a;用2整除的方式。 用2整除十进制整数&#xff0c;得到一个商和余数&#xff1b;再用2去除商&#xff0c;又会得到一个商和余数&#xff0c;如此重复&#xff0c;直到商为小于1时为止&#xff0c;然后把先得到余数作为二进制数的低位有效位&#xff0c;后得到的…

Python 利用内置函数把二进制小数转换为十进制

如果需要把一个二进制整数转换为十进制整数&#xff0c;只需要简单的一行&#xff1a; int(1101,2) 但如果有一个二进制小数的话&#xff0c;就需要自己实现一个函数了。 不过&#xff0c;许多人是这样写的&#xff1a;(图片取自这里) 可是&#xff0c;由于python本身并不适…

[学习笔记] 二进制小数表示方法

文章目录 科学计数法二进制推广计算机中的小数EXCESS表示系统特殊情况举例&#xff08;float&#xff09;普通情况最大正实数普通情况最小负实数普通情况最小正实数特殊情况最大正实数 科学计数法 科学计数法想必大家都很熟悉了&#xff0c;往往通过如下形式表示一个实数&…

十进制小数化为二进制小数的方法是什么_二进制的转换

二进制是在计算机中常用的一种进制数&#xff0c;其数据用0和1两个数码来表示数据。我们人类常用的是十进制&#xff0c;那么二进制和十进制之间是有一个转换方法的。 二进制转换十进制 一个二进制数转换为十进制数&#xff0c;是比较简单的&#xff0c;其方法就是用每一个位置…

二进制小数的意义

回忆小学学的十进制小数的意义&#xff1a; 15.23这个小数&#xff0c;1是十位&#xff0c;5是个位&#xff0c;2是十分位&#xff0c;3是百分位。这个小数的意义为&#xff1a;&#xff0c;因为最低位为百分位&#xff0c;所以分母是100。 小数末尾加上0或去掉0&#xff0c;小…

浮点数(小数)在计算机中如何用二进制存储?

浮点数在计算机中如何用二进制存储&#xff1f; 前言 前面我有篇博文详解了二进制数&#xff0c;以及如何同二进制数表示整数。但是&#xff0c;计算机处理的不仅仅是整数&#xff0c;还有小数&#xff0c;同样小数在计算机也是用二进制进行存储的&#xff0c;但是&#xff0…

二进制小数的表示

二级制小数分为两大类&#xff1a;1、定点数&#xff1b;2、浮点数。 定点数 定点数&#xff1a; &#xff08;1&#xff09;小数点位置固定不变的数。 &#xff08;2&#xff09;定点数有定点整数和定点小数。 &#xff08;定点整数&#xff1a;小数部分为0&#xff1b;定点…

腾讯TDSQL全时态数据库系统论文入选VLDB

当地时间2019年8月26至30日&#xff0c;VLDB 2019会议在美国加利福尼亚召开&#xff0c;腾讯分布式数据库TDSQL与中国人民大学最新联合研究成果被VLDB 2019接收并将通过长文形式发表。VLDB是国际数据管理与数据库领域顶尖的学术会议之一&#xff0c;这是继去年腾讯TDSQL相似度计…

顶会VLDB‘22论文解读:CAE-ENSEMBLE算法

摘要&#xff1a;针对时间序列离群点检测问题&#xff0c;提出了基于CNN-AutoEncoder和集成学习的CAE-ENSEMBLE深度神经网络算法&#xff0c;并通过大量的实验证明CAE-ENSEMBLE算法能有效提高时间序列离群点检测的准确度与效率。 本文分享自华为云社区《VLDB22 CAE-ENSEMBLE论文…

【轨迹压缩】Trajectory Simplification: On Minimizing the Direction-based Error [2015] [VLDB]

一、一个动机 保护方向信息的方向保持轨迹简化&#xff08;DPTS&#xff09;已被证明表现良好&#xff0c;而现有关于 DPTS 的研究 要求用户指定一个容错&#xff0c;在某些情况下用户可能不知道如何正确设置&#xff08;例如&#xff0c;容错只能在未来某个时间知道&#xff…

VLDB 2021 EAB最佳论文:深度解析机器学习的基数估计为何无法实现?

©作者 | 曲昌博单位 | 西蒙菲莎大学近日&#xff0c;IEEE 数据工程新星奖王健楠团队论文《Are We Ready for Learned Cardinality Estimation?》夺得数据库顶会 VLDB 2021 年度的 EA&B 最佳论文奖。 数据库是企业管理和查询数据的复杂软件系统。 近年来随着机器学习以…

Transformers如何处理表格数据?【VLDB2022教程】Transformer表格数据表示:模型和应用...

来源&#xff1a;专知 本文为教程介绍&#xff0c;建议阅读5分钟最近的研究工作通过开发表格数据的神经表示扩展了语言模型。 在过去的几年中&#xff0c;自然语言处理界见证了基于transformer的语言模型(LM)在自由文本的神经表示方面的进展。鉴于关系表中可用知识的重要性&…

openGauss亮相VLDB2020,展示内存优化研究成果

VLDB&#xff08;Very Large Data Base&#xff09;作为数据库领域的三大顶级国际会议之一&#xff0c;是面向数据库研究人员&#xff0c;内核开发人员&#xff0c;开发商以及用户的年度国际会议论坛&#xff0c;代表数据库系统领域最杰出的研究和工程进展。在2020年&#xff0…

VLDB 2023 | 北大河图发布分布式训练神器Galvatron,一键实现大模型高效自动并行...

©作者 | 北京大学河图团队 单位 | 北京大学数据与智能实验室 北大河图团队提出了一套面向大模型的自动并行分布式训练系统 Galvatron&#xff0c;相比于现有工作在多样性、复杂性、实用性方面均具有显著优势&#xff0c;论文成果已经被 VLDB 2023 接收。 最近一段时间&…

利用 Map-Reduce 从文件中找到出现频率最高的 10 个 URL(2021 VLDB Summer School Lab0)

这篇博文主要是对 2021 VLDB Summer School Lab0 的一个总结 这个lab与MIT 6.824 的 lab1 相似&#xff0c;个人感觉比MIT 6.824 的 lab1 要稍微简单些&#xff0c;更容易上手。通过这个lab&#xff0c;可以学习到一些 Golang 的基础知识并对分布式系统有一个基础的了解&#…

Flink OLAP 助力 ByteHTAP 亮相数据库顶会 VLDB

复杂查询 QPS 破百&#xff0c;字节跳动 Flink OLAP 助力 ByteHTAP 亮相数据库顶会 VLDB。 2022 年 9 月 5 日至 9 月 9 日&#xff0c;VLDB 2022 在澳大利亚悉尼举行。字节跳动基础架构研究成果《ByteHTAP: ByteDance’s HTAP System with High Data Freshness and Strong Dat…

湖南大学计算机专业硕士研究导师,湖南大学研究生导师李睿科研论文被世界顶级数据库学术会议VLDB刊发...

李睿老师的论文被国际数据库顶级会议Very Large Data Bases接受并发表。 刊发的论文。 日前&#xff0c;以湖南大学信息科学与工程学院计算机科学系研究生导师李睿为第一作者&#xff0c;湖南大学为第一作者单位的科研论文“Fast Range Query Processing with Strong Privacy P…

PM-LSH: A Fast and Accurate LSH Framework for High-Dimensional Approximate NN Search(VLDB)

由于维数灾难的影响&#xff0c;高维空间中的最近邻(NN)搜索本质上是计算开销巨大的。局部敏感哈希(locality-sensitive hashing, LSH)是一种著名的近似神经网络搜索算法&#xff0c;能够以恒定概率在亚线性时间内回答c-近似神经网络(c-ANN)查询。现有的LSH方法主要基于哈希桶建…

Updatable Learned Index with Precise Positions(VLDB2022)

在现代数据库引擎中&#xff0c;索引在加速查询处理方面起着至关重要的作用。“学习索引”的新范式极大地改变了DBMS中索引结构的设计方式。关键的见解是&#xff0c;索引可以被视为预测数据集中查找键位置的学习模型。虽然这类研究在查找时间和索引大小方面都显示出良好的结果…