ikd-tree

目录

1 kd-tree

1.1 定义

1.2 步骤

2 ikd-tree

2.1 原理

2.2 节点数据结构

2.3 功能实现

2.3.1 插入

2.3.2 删除

2.3.3 搜索

2.3.4 re-balancing再平衡

2.3.5 再平衡算法(重构)


先说一下kd-tree

1 kd-tree

1.1 定义

K-dimensional tree,一种高维索引树形数据结构,经常用于在大规模的高维数据空间进行最近邻查找

类似于K维二叉树,树中存储一些K维数据

1.2 步骤

1.3 缺点

  • 数据为多维结构,不同树节点根据不同维度进行数据划分

  • 父节点将所有数据划分至左右子树,叶子节点包含所有数据

  • 使用于动态程度不高的数据,插入删除不方便

  • 非动态增量式结构,每次都要重新构建kdtree

  • 深度影响搜索速度,图的结构可能不平衡

理解:kd-tree的搜索速度与其深度有关,然而,很多SLAM方案都需要kd-tree来维护一个动态的local map,因此必然需要不断的插入新点,并删除过远过旧的点,导致kd-tree的平衡性遭到破坏。换言之,在kd-tree总点数不变的情况下,由于一些位置的点被删除、其他位置的点有新增,导致整个kd-tree树不平衡,进而导致搜索效率下降

针对上述现象,如果能构建一个增量式的动态kd-tree结构,能够自行调整树的结构、始终保持动态平衡,那问题就会迎刃而解。ikd-tree就做到了。


2 ikd-tree

2.1 原理

2.2 节点数据结构

Struct TreeNode:
    PointType point;//点坐标、强度信息
    TreeNode *leftchild,*rightchild;//左右节点指针
    int axis;//分割轴
    // 1.treesize:tree中所有节点的数量(树的大小)
    // 2.incailnum:tree中被标记为"删除"的节点数
    int treesize,incailnum;
​
    // 1.deleted:当前节点是否被标记为删除
    // 2.treedeleted:当前tree是否被标记为删除
    //   注意:是累积一定数量的点后统一删除
    bool deleted,treedeleted;
​
    // 子树上点的范围(长方体空间)
    // 用于排除不必要的点
    CuboidVertices ranges;
end

树的构建:与kdtree一样,都是根据对比均值方差,进行初始的构建

2.3 功能实现

2.3.1 插入

输入:下采样分辨率,新插入点P,是否重构建

Start

  1. 根据点P及其分辨率,找到该点在哪个体素里,记为C_D

  2. 找到体素的中心点P_center

  3. 将体素C_D内所有点记为V

  4. 将新点P放入V中

  5. 近邻搜索,找到体素内距离P——center最近的点

  6. 判断最近点是否为新点

    Y:插入,并删除其余点

img

流程:

  • 将整个空间体素化,并明确新点落入哪个体素(目标体素)

  • 向ikd-Tree查询目标体素内是否已经有点以及有哪些点(查询过程参考box-wise delete)

  • 如果已经有点了,将已有点和新点一起排序,找出离体素中心最近的那个点,然后做判断:【如果最近的点是已有点,意味着新点无必要再插入了,结束处理;如果最近的点是新点,则把已有点全部标记删除,并插入新点】

  • 如果体素内尚不存在点,则直接插入新点

2.3.2 删除

策略

(1)删除:删除一个中间节点意味着该节点下方所以节点都要重构subtree,低效,所以增量式kd-tree基本采用lazy delete策略。

(2)lazy delete策略:删除一个节点时,先将其标记为“删除”,这些节点在KNN搜索时会被跳过,但在树形结构中它依旧存在,只有当tree结构被彻底重构时(低频),才会真的将这些节点从树结构中删除。

(3)box-wise delete策略:按区域批量删除点

  1. 为ikd-tree框定一个立方体区域,用于删除区域内所有的点

  2. 一旦机器人运动到区域边界,就将立方体沿着运动方向移动一定距离

  3. 实现删除区域外的点,引进新点

    1. 判断是否处于灰色区域

    2. 判断range是否与删除区域有交叉,有交叉就直接剪枝

下图为算法实现流程

                1. 从根节点遍历每个节点,判断是否处于灰色区域内

                         Y:标记删除

                2. 判断两个子节点的range是否与删除区域有交叉

                        N:剪枝

                3. 重复上述操作,直至遍历完成,

                4. 更新treesize、incalidnum、range、treedeleted

                5. 在re-balancing环节再真正删除

2.3.3 搜索

(1)KNN & ranged-KNN搜索基本与常规 kd-tree相同,此处不再赘述

(2)补充:ikd-Tree 中充分利用了数据结构部分提到的 range信息 来进行剪枝加速,也即在每个节点处,除了计算节点本身与查询点的距离之外,也会分别判断左右两个子树的range 是否与目标解空间有重叠,只有有重叠的子树才会被继续递归搜索,没重叠的子树将直接被剪枝掉,实现搜索加速

2.3.4 re-balancing再平衡

目的:经过多次删除,树的结构可能变得不平衡。由于深度影响搜索速度,于是通过re-balancing平衡树的结构、减小深度

树的平衡性判断准则

    \alpha-balanced

  • 左右两侧最大不平衡容忍度

  • 任意一个子树的规模不能大于特定比例

  • 值越趋近于0.5,越容易被判定为不平衡

       

            \alpha-deleted

  • 最多容忍subtree中被标记为"删除"(无效节点的数量)的占比

  • 任意一个子树中标记删除点的规模不能超过特定比例

  • 值越小,容忍标记为删除点的比例越低

2.3.5 再平衡算法(重构)

在判断为不平衡的基础上,触发对subtree的重建。

(1)子树规模较小

(2)子树规模较大

当子树规模较大,重建时间花销不可忽略,若在主线程中执行重建,就会导致ikd-tree一直被占用,外部的SLAM算法无法访问ikd-tree执行查询或增删操作 —— 导致算法阻塞。

  • 重建时间花销可以忽略,在主线程中直接重建

  • 流程:重建时先把subtree的所有节点打乱重排,在这一过程中会拿掉标记删除的点;然后,对剩下的点按中值点法执行常规的kdtree构建过程;构建完成后,把新的子树替换到原来的位置

  • 采用双线程策略,即将正在重建的tree的增删操作额外缓存到一个容器中,待额外线程中完成了重建后,再从容器把增删操作挪到新tree上。【主线程中依旧可以进行增删操作】

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值