基于Open3D的点云处理4-数据结构Kdtree和Octree

Kdtree

Kdtree是一种划分k维数据空间的数据结构,本质也是一颗二叉树,只不过每个节点的数据都是k维,当k=1时,就是普通二叉树。

建立Kdtree实际上是一个不断划分的过程,首先选择最sparse的维度(一般通过计算数据在各个维度的方差,选择方差大的作为本次分割维度),然后找到该维度上的中间点,垂直该维度做第一次划分。此时k维超平面被一分为二,在两个子平面中再找最sparse的维度,以此类推直到最后一个点也被划分,那么就形了一个不断二分的树。
二维Kdtree的建立过程下图所示,首先分别计算x,y方向上数据的方差,得知x方向上的方差最大,所以split域值首先x轴方向;然后根据x轴方向的值2,5,9,4,8,7排序选出中值为7,所以Node-data = (7,2)。这样,该节点的分割超平面就是通过(7,2)并垂直于split = 0(x轴)的直线x = 7,后面以此类推。

有了KD树后,可以在点云中实现K近邻搜索、K半径搜索等算法。

测试用例:与背景点云进行比较,求出运动目标

  • 首先确定max d
  • 遍历待求异点云,寻找最近邻点;
  • 与最近邻点距离d小于dmax,认为是相同区域的点,将点删除;若大于dmax,则认为是不同点,保留该点;
import open3d as o3d
import numpy as np
pc1 = o3d.io.read_point_cloud("./data/1.ply",remove_nan_points=True,remove_infinite_points=True)#原始点云
pc2 = o3d.io.read_point_cloud("./data/2.ply",remove_nan_points=True,remove_infinite_points=True)#求异点云
#建立原始数据点云的k-d树结构
k_dTree = o3d.geometry.KDTreeFlann(pc1)
#ptsIdx是指灵片点云中相同部分的索引
ptsIdx=[]
#k是指K-NN搜索的参数,也就是说搜索另外一片点云中距离它的最近点
k=1
#将距离阈值设置为0.1
dist_max=0.1
#得到点个数
points = np.array(pc2.points)
pointNum=points.shape[0]
#遍历点云
for i in range(0, pointNum):
    # k返回点个数
    # idx 返回点索引
    # dist 返回点距离
    [k, idx, dist] = k_dTree.search_knn_vector_3d(pc2.points[i],k)#通过k-d Tree进行搜索最近点
    if dist[0] < dist_max:#如果另外一片点云中能够找到距离小于给定距离阈值的点,则判定为点云中相同的部分
        ptsIdx.append(i)

#最后将点云中相同的部分和不同的部分分别取出来进行显示
same_part=pc2.select_by_index(ptsIdx)
diff_part=pc2.select_by_index(ptsIdx,invert=True)
same_part.paint_uniform_color([0,0,1])
diff_part.paint_uniform_color([1,0,0])
o3d.visualization.draw_geometries([same_part,diff_part])

在这里插入图片描述

Octree

Octree是一种用于描述三维空间的树状数据结构。八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,将八个子节点所表示的体积元素加在一起就等于父节点的体积。能够很好的压缩点云节省存储空间。通过对三维空间的几何实体进行体元剖分,每个体元具有相同的时间和空间复杂度,通过循环递归的划分方法对大小为(2n∗2n∗2n)的三维空间的几何对象进行剖分,从而构成一个具有根节点的方向图。在八叉树结构中如果被划分的体元具有相同的属性,则该体元构成一个叶节点;否则继续对该体元剖分成8个子立方体,依次递剖分,对于(2n∗2n∗2n)大小的空间对象,最多剖分n次,如下图所示:
在这里插入图片描述

Octree的创建:

  1. 设定最大递归深度;
  2. 找出场景的最大尺寸,并以此尺寸建立第一个立方体;
  3. 依序将单位元元素丢入能被包含且没有子节点的立方体;
  4. 若没有达到最大递归深度,就进行细分八等份,再将该立方体所装的单位元元素全部分担给八个子立方体;
  5. 若发现子立方体所分配到的单位元元素数量不为零且跟父立方体是一样的,则该子立方体停止细分,因为根据空间分割理论,细分的空间所得到的分配必定较少,若是一样数目,则再怎么切数目还是一样,会造成无穷切割的情形。-
  6. 重复3,直到达到最大递归深度。

有了八叉树的结构可以实现分块功能、分邻域搜索、一点K邻域的获取等功能。

  • 备注:KD树与八叉树的不同
    1.八叉树的节点是均匀划分的,但k-d树的节点是每一次延不同的维度不均匀的切分,形成两个子节点;
    2.k-d树适用于不同维度的数据,但八叉树仅适用于三维数据;

测试用例: 可视化八叉树

import open3d as o3d

pcd = o3d.io.read_point_cloud("./data/people.ply")
# 设置颜色
pcd.paint_uniform_color([1.0, 0.0, 0.0])
# 建立八叉树
octree = o3d.geometry.Octree(max_depth=10)#设置最大深度
octree.convert_from_point_cloud(pcd, size_expand=0.1)#size_expand叶子节点大小
# 可视化
o3d.visualization.draw_geometries([octree], window_name="八叉树",
                                  width=800,
                                  height=600)

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zfjBIT/article/details/130913340