三维点云学习(2)下-Octree

Octree(八叉树)的基本结构

思想:立体空间的分割

二维平面的展示

Octree(八叉树)的构建

#extent:立方体中心点到面的距离
#Center of the cube 立方体的中心

1.判断每一个点里面都有怎么样的主节点
2.计算子节点的中心在哪,子节点的边长,再把属于这个子节点的数据放进去

Octant构建完成之后,进行kNN的搜寻
这里展现了Octree比kd-tree的优越在于当红色框被S2包围时,可以马上结束搜寻

1.如果octant是一个末尾叶子节点,直接把数据扔进去KNN搜寻
2.如果不是末尾节点,进行寻找最有可能的子节点
3.如果查找成功,直接退出返回True,不成功,再搜寻其他子节点
4.overlaps() 用于判断,子节点与球是否有交际,没有就跳过(空间结构思想)
5.inside() ,如果球面被某一个Octant包围,可直接退出

inside的实现
#红色代表worst——dist
#正方形代表一个octant
只需要判断 extent > radius +diff 就可认为球在正方体里面

overlaps的实现
#case1:判断是否有接触
如果 diff > extent + radius 可认为球面与octant没接触

#case2:判断球体和某一个面是否接触
假设case1 成立,当有球体的中心点有两个轴位于正方体的相应轴内部时,也同样可判断为有交集

#case3.1:判断球体有没有跟正方体某个角点接触
当 diff < radius 可判断为和角点有接触

#case3.2:判断球体有没有跟正方体某个棱是否接触
注意:用max(,0)解决球体中某个点会陷在正方体的某个轴上,而出现的负数影响


oerlaps回顾:

Better one:

如果有一个球体完全包围一个正方体,那只需要对相应的octant进行kNN search就行

图示:
如果:
图示绿色线 < radius 可认为被包裹

复杂度

完整代码

#运行结果

Radius search normal:
Search takes 45438.469msRadius search fast:
Search takes 20330.457ms
import random
import math
import numpy as np
import timefrom lidar_KnnRnnClass_2 import KNNResultSet, RadiusNNResultSetclass Octant:def __init__(self, children, center, extent, point_indices, is_leaf):self.children = childrenself.center = centerself.extent = extentself.point_indices = point_indicesself.is_leaf = is_leafdef __str__(self):output = ''output += 'center: [%.2f, %.2f, %.2f], ' % (self.center[0], self.center[1], self.center[2])output += 'extent: %.2f, ' % self.extentoutput += 'is_leaf: %d, ' % self.is_leafoutput += 'children: ' + str([x is not None for x in self.children]) + ", "output += 'point_indices: ' + str(self.point_indices)return outputdef traverse_octree(root: Octant, depth, max_depth):depth[0] += 1if max_depth[0] < depth[0]:max_depth[0] = depth[0]if root is None:passelif root.is_leaf:print(root)else:for child in root.children:traverse_octree(child, depth, max_depth)depth[0] -= 1def octree_recursive_build(root, db, center, extent, point_indices, leaf_size, min_extent):if len(point_indices) == 0:return Noneif root is None:root = Octant([None for i in range(8)], center, extent, point_indices, is_leaf=True)# determine whether to split this octantif len(point_indices) <= leaf_size or extent <= min_extent:root.is_leaf = Trueelse:root.is_leaf = Falsechildren_point_indices = [[] for i in range(8)]for point_idx in point_indices:point_db = db[point_idx]morton_code = 0if point_db[0] > center[0]:morton_code = morton_code | 1if point_db[1] > center[1]:morton_code = morton_code | 2if point_db[2] > center[2]:morton_code = morton_code | 4children_point_indices[morton_code].append(point_idx)# create childrenfactor = [-0.5, 0.5]for i in range(8):child_center_x = center[0] + factor[(i & 1) > 0] * extentchild_center_y = center[1] + factor[(i & 2) > 0] * extentchild_center_z = center[2] + factor[(i & 4) > 0] * extentchild_extent = 0.5 * extentchild_center = np.asarray([child_center_x, child_center_y, child_center_z])root.children[i] = octree_recursive_build(root.children[i],db,child_center,child_extent,children_point_indices[i],leaf_size,min_extent)return rootdef inside(query: np.ndarray, radius: float, octant:Octant):"""Determines if the query ball is inside the octant:param query::param radius::param octant::return:"""query_offset = query - octant.centerquery_offset_abs = np.fabs(query_offset)possible_space = query_offset_abs + radiusreturn np.all(possible_space < octant.extent)def overlaps(query: np.ndarray, radius: float, octant:Octant):"""Determines if the query ball overlaps with the octant:param query::param radius::param octant::return:"""query_offset = query - octant.centerquery_offset_abs = np.fabs(query_offset)# completely outside, since query is outside the relevant areamax_dist = radius + octant.extentif np.any(query_offset_abs > max_dist):return False# if pass the above check, consider the case that the ball is contacting the face of the octantif np.sum((query_offset_abs < octant.extent).astype(np.int)) >= 2:return True# conside the case that the ball is contacting the edge or corner of the octant# since the case of the ball center (query) inside octant has been considered,# we only consider the ball center (query) outside octantx_diff = max(query_offset_abs[0] - octant.extent, 0)y_diff = max(query_offset_abs[1] - octant.extent, 0)z_diff = max(query_offset_abs[2] - octant.extent, 0)return x_diff * x_diff + y_diff * y_diff + z_diff * z_diff < radius * radiusdef contains(query: np.ndarray, radius: float, octant:Octant):"""Determine if the query ball contains the octant:param query::param radius::param octant::return:"""query_offset = query - octant.centerquery_offset_abs = np.fabs(query_offset)query_offset_to_farthest_corner = query_offset_abs + octant.extentreturn np.linalg.norm(query_offset_to_farthest_corner) < radiusdef octree_radius_search_fast(root: Octant, db: np.ndarray, result_set: RadiusNNResultSet, query: np.ndarray):if root is None:return Falseif contains(query, result_set.worstDist(), root):# compare the contents of the octantleaf_points = db[root.point_indices, :]diff = np.linalg.norm(np.expand_dims(query, 0) - leaf_points, axis=1)for i in range(diff.shape[0]):result_set.add_point(diff[i], root.point_indices[i])# don't need to check any childreturn Falseif root.is_leaf and len(root.point_indices) > 0:# compare the contents of a leafleaf_points = db[root.point_indices, :]diff = np.linalg.norm(np.expand_dims(query, 0) - leaf_points, axis=1)for i in range(diff.shape[0]):result_set.add_point(diff[i], root.point_indices[i])# check whether we can stop search nowreturn inside(query, result_set.worstDist(), root)# no need to go to most relevant child first, because anyway we will go through all childrenfor c, child in enumerate(root.children):if child is None:continueif False == overlaps(query, result_set.worstDist(), child):continueif octree_radius_search_fast(child, db, result_set, query):return Truereturn inside(query, result_set.worstDist(), root)def octree_radius_search(root: Octant, db: np.ndarray, result_set: RadiusNNResultSet, query: np.ndarray):if root is None:return Falseif root.is_leaf and len(root.point_indices) > 0:# compare the contents of a leafleaf_points = db[root.point_indices, :]diff = np.linalg.norm(np.expand_dims(query, 0) - leaf_points, axis=1)for i in range(diff.shape[0]):result_set.add_point(diff[i], root.point_indices[i])# check whether we can stop search nowreturn inside(query, result_set.worstDist(), root)# go to the relevant child firstmorton_code = 0if query[0] > root.center[0]:morton_code = morton_code | 1if query[1] > root.center[1]:morton_code = morton_code | 2if query[2] > root.center[2]:morton_code = morton_code | 4if octree_radius_search(root.children[morton_code], db, result_set, query):return True# check other childrenfor c, child in enumerate(root.children):if c == morton_code or child is None:continueif False == overlaps(query, result_set.worstDist(), child):continueif octree_radius_search(child, db, result_set, query):return True# final check of if we can stop searchreturn inside(query, result_set.worstDist(), root)def octree_knn_search(root: Octant, db: np.ndarray, result_set: KNNResultSet, query: np.ndarray):if root is None:return Falseif root.is_leaf and len(root.point_indices) > 0:                             #如果是末尾节点(leaf)那就直接把数据扔进KNNResult# compare the contents of a leafleaf_points = db[root.point_indices, :]diff = np.linalg.norm(np.expand_dims(query, 0) - leaf_points, axis=1)for i in range(diff.shape[0]):result_set.add_point(diff[i], root.point_indices[i])# check whether we can stop search nowreturn inside(query, result_set.worstDist(), root)# go to the relevant child firstmorton_code = 0if query[0] > root.center[0]:morton_code = morton_code | 1if query[1] > root.center[1]:morton_code = morton_code | 2if query[2] > root.center[2]:morton_code = morton_code | 4if octree_knn_search(root.children[morton_code], db, result_set, query):return True# check other childrenfor c, child in enumerate(root.children):if c == morton_code or child is None:continueif False == overlaps(query, result_set.worstDist(), child):continueif octree_knn_search(child, db, result_set, query):return True# final check of if we can stop searchreturn inside(query, result_set.worstDist(), root)def octree_construction(db_np, leaf_size, min_extent):N, dim = db_np.shape[0], db_np.shape[1]db_np_min = np.amin(db_np, axis=0)db_np_max = np.amax(db_np, axis=0)db_extent = np.max(db_np_max - db_np_min) * 0.5db_center = db_np_min + db_extentroot = Noneroot = octree_recursive_build(root, db_np, db_center, db_extent, list(range(N)),leaf_size, min_extent)return rootdef main():# configurationdb_size = 64000dim = 3leaf_size = 4min_extent = 0.0001k = 8db_np = np.random.rand(db_size, dim)root = octree_construction(db_np, leaf_size, min_extent)# depth = [0]# max_depth = [0]# traverse_octree(root, depth, max_depth)# print("tree max depth: %d" % max_depth[0])# query = np.asarray([0, 0, 0])# result_set = KNNResultSet(capacity=k)# octree_knn_search(root, db_np, result_set, query)# print(result_set)## diff = np.linalg.norm(np.expand_dims(query, 0) - db_np, axis=1)# nn_idx = np.argsort(diff)# nn_dist = diff[nn_idx]# print(nn_idx[0:k])# print(nn_dist[0:k])begin_t = time.time()print("Radius search normal:")for i in range(100):query = np.random.rand(3)result_set = RadiusNNResultSet(radius=0.5)octree_radius_search(root, db_np, result_set, query)# print(result_set)print("Search takes %.3fms\n" % ((time.time() - begin_t) * 1000))begin_t = time.time()print("Radius search fast:")for i in range(100):query = np.random.rand(3)result_set = RadiusNNResultSet(radius = 0.5)octree_radius_search_fast(root, db_np, result_set, query)# print(result_set)print("Search takes %.3fms\n" % ((time.time() - begin_t)*1000))if __name__ == '__main__':main()

三维点云学习(2)下-Octree相关推荐

  1. 三维点云学习(1)下-点云体素降采样

    三维点云学习(1)下 点云体素降采样(Voxel Filter Downsampling) 代码参考网址秦乐乐CSDN博客 理论参考知乎博主:WALL-E 1.方法 Centroid 均值采样 Ran ...

  2. 三维点云学习(2)五种算法比较

    三维点云学习(2)五种算法比较 代码参考来自 黎老师github 本次测试包含五种算法比较: octree print("octree --------------")#时间统计c ...

  3. 三维点云学习(3)7- 实现GMM

    三维点云学习(3)7- 实现GMM github大神参考代码 高斯混合模型的通俗理解 GMM课程个人总结笔记 最终效果图 原图 进行高斯聚类后的图 代码编写流程 1.输入数据集x1 x2 -xn,和K ...

  4. 三维点云学习(3)2- K-Means

    三维点云学习(3)2- K-Means K-Means的具体构建流程 将输入的N个数据点,分为N个类 1.随机选取K个中心点 2.E-Step(expectation):N个点.K个中心,求N个点到K ...

  5. 三维点云学习(3)1-聚类数学理论

    三维点云学习(3)1-数学理论 Linear Algebra 谱定理 对于一个对称矩阵,我们可以用他的特征值特征向量的线性组合表示 瑞利熵 Probability – Joint Probabilit ...

  6. 三维点云学习(1)上-PCA主成分分析 法向量估计

    三维点云学习(1)上 环境安装 1.系统环境 win10 或者 ubuntu 2. Anaconda3+python3.6 使用Anaconda创建的conda虚拟环境进行python的编写 环境安装 ...

  7. 三维点云学习(5)5-实现Deeplearning-PointNet-2-classfication

    三维点云学习(5)5-实现Deeplearning-PointNet-2-classfication Github PointNet源码 数据集下载:为40种物体的三维点云数据集 提取码:es14 运 ...

  8. 三维点云学习(5)4-实现Deeplearning-PointNet-1-数据集的批量读取

    三维点云学习(5)4-实现Deeplearning-PointNet-1-数据集的批量读取 Github PointNet源码 数据集下载:为40种物体的三维点云数据集 提取码:es14 因为本人初次 ...

  9. 三维点云学习(5)3-Deep learning for Point Cloud-PointNet++

    三维点云学习(5)3-Deep learning for Point Cloud-PointNet++ 强烈推荐 PointNet的深刻理解 PointNet++示意图 可分为 Encoder. Se ...

最新文章

  1. HIVE-ORC表一些知识点
  2. java 入门 第三季1
  3. java中日期与字符串之间的转换
  4. [WCF安全系列]绑定、安全模式与客户端凭证类型:NetNamedPipeBinding、NetTcpBinding与NetMsmqBinding...
  5. oracle10g配置失败6,Oracle10g DataGuard中ORA-16026错误解决-入门基础-Oracle频道-中国IT实验室...
  6. MACOSX下查看某个端口被哪个程序占用及杀进程方法
  7. docker 安装hadoop
  8. swoole task 异步任务 注释请忽略 自己加的不一定对 别误导大家。。。。。。
  9. linux UID的长度,linux下文件数、目录数、文件名长度的各种限制
  10. android电视自动关机,Android定时关机问题解决
  11. 联想g510拆键盘的简单方法_联想g510笔记本电脑键盘拆卸视频
  12. QOS中PQ,CQ.RR,WFQ,CBWFQ,LLQ区分
  13. SEO基础知识简介(一)
  14. JAVA:JDBC数据库编程
  15. python代码示例大全 下载-python基础代码大全
  16. CT与DR双能X射线物质识别算法实现与应用(工业选煤、稀土分拣、毒爆检测、垃圾分类等)
  17. 【QT Creator学习记录】(一)上位机与下位机串口通信
  18. 为了搞清楚类加载,竟然手撸JVM!
  19. .nc地形数据的python转换实现tiff
  20. opencvsharp历程_opencvsharp 例程

热门文章

  1. NFS客户端挂载目录后无写入权限的解决方案
  2. linux 下mysql忘记密码或者安装好linux后不知道mysql初始密码解决方案
  3. IIS配置Url重写实现http自动跳转https的重定向方法(100%解决)
  4. 活动子项父项的复杂CSS选择器[重复]
  5. 如何在JavaScript中将浮点数转换为整数?
  6. hdfs mv命令_Hadoop2.x HDFS shell命令
  7. 教你win7显卡驱动如何安装,win7电脑显卡驱动的安装方法
  8. Linux,vi编辑器使用手册
  9. mysql centos7安装_Linux——CentOS7之mysql5.7安装与配置
  10. Android:复杂listview条目