antd tree搜索并定位_KD-Tree原理详解

5d2aabd135258aa4e6e9d8ea7683a46e.png

kd-tree是在进行激光点云编程中经常使用的一个工具,我们平时使用的时候可能就是使用其中的一小部分的内容,并未对其进行很深的思考。那么kd-tree的原理到底是什么呢?我们又经常使用哪些常用函数呢?

本片文章将对kd-tree进行细致的整理,方便以后的使用和阅读。

1、简介

kd-tree简称k维树,是一种空间划分的数据结构。常被用于高维空间中的搜索,比如范围搜索和最近邻搜索。kd-tree是二进制空间划分树的一种特殊情况

在激光雷达SLAM中,一般使用的是三维点云。所以,kd-tree的维度是3。

由于三维点云的数目一般都比较大,所以,使用kd-tree来进行检索,可以减少很多的时间消耗,可以确保点云的关联点寻找和配准处于实时的状态。

本篇文章将从原理层面讲解kd-tree,以便大家在使用中,可以有着更深刻的理解。

2、原理

2.1、数据结构

kd-tree,是k维的二叉树。其中的每一个节点都是k维的数据,数据结构如下所示

struct 

上面的数据在进行算法解析中,并不是全部都会用到。一般情况下,会用到的数据是{数据矢量,切割轴号,左支节点,右支节点}。这些数据就已经满足kd-tree的构建和检索了。

2.2、构建kd-tree

kd-tree的构建就是按照某种顺序将无序化的点云进行有序化排列,方便进行快捷高效的检索。

构建算法:

Input

这样的化,就可以构建出一颗完整的kd-tree了。

拿个例子说明为:

二维样例:{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}

构建步骤:

1、初始化分割轴:

发现x轴的方差较大,所以,最开始的分割轴为x轴。

2、确定当前节点:

对{2,5,9,4,8,7}找中位数,发现{5,7}都可以,这里我们选择7,也就是(7,2);

3、划分双支数据:

在x轴维度上,比较和7的大小,进行划分:

左支:{(2,3),(5,4),(4,7)}

右支:{(9,6),(8,1)}

4、更新分割轴:

一共就两个维度,所以,下一个维度是y轴。

5、确定子节点:

左节点:在左支中找到y轴的中位数(5,4),左支数据更新为{(2,3)},右支数据更新为{(4,7)}

右节点:在右支中找到y轴的中位数(9,6),左支数据更新为{(8,1)},右支数据为null。

6、更新分割轴:

下一个维度为x轴。

7、确定(5,4)的子节点:

左节点:由于只有一个数据,所以,左节点为(2,3)

右节点:由于只有一个数据,所以,右节点为(4,7)

8、确定(9,6)的子节点:

左节点:由于只有一个数据,所以,左节点为(8,1)

右节点:右节点为空。

最终,就可以构建整个的kd-tree了。

示意图如下所示

二维空间表示:

9a72f376907d1d1271aba17f67d82d06.png
二维坐标系下的分割示意图

kd-tree表示:

dfd76ebc3c403129582f522c8e5b7eda.png
构建kd-tree

2.3、最近邻检索

在构建了完整的kd-tree之后,我们想要使用他来进行高维空间的检索。所以,这里讲解一下比较常用的最近邻检索,其中范围检索也是同样的道理。

最近邻搜索,其实和之前我们曾经学习过的KNN很像。不过,在激光点云章,如果使用常规的KNN算法的话,时间复杂度会空前高涨。因此,为了减少时间消耗,在工程上,一般使用kd-tree进行最近邻检索。

由于kd-tree已经按照维度进行划分了,所以,我们在进行比较的时候,也可以通过维度进行比较,来快速定位到与其最接近的点。由于可能会进行多个最近邻点的检索,所以,算法也可能会发生变化。因此,我将从最简单的一个最近邻开始说起。

  • 一个最近邻

一个最近邻其实很简单,我们只需要定位到对应的分支上,找到最接近的点就可以了。

举个例子:查找(2.1,3.1)的最近邻。

  1. 计算当前节点(7,2)的距离,为6.23,并且暂定为(7,2),根据当前分割轴的维度(2.1 < 7),选取左支。
  2. 计算当前节点(5,4)的距离,为3.03,由于3.03 < 6.23,暂定为(5,4),根据当前分割轴维度(3.1 < 4),选取左支。
  3. 计算当前节点(2,3)的距离,为0.14,由于0.14 < 3.03,暂定为(2,3),根据当前分割轴维度(2.1 > 2),选取右支,而右支为空,回溯上一个节点。
  4. 计算(2.1,3.1)与(5,4)的分割轴{y = 4}的距离,如果0.14小于距离值,说明就是最近值。如果大于距离值,说明,还有可能存在值与(2.1,3.1)最近,需要往右支检索。

由于0.14 < 0.9,我们找到了最近邻的值为(2,3),最近距离为0.14。

  • 多个最近邻

多个近邻其实和一个最近邻类似,不过是存储区间变为了多个,判定方法还是完全一样。

由于篇幅的原因,这里就不在赘述。这篇博客讲的很详细,有兴趣的同学可以去学习一下:

加载中​www.joinquant.com

3、常用函数

kd-tree在日常使用中,一般会在两个方面使用:

  • 最近邻搜索
  • 距离范围搜索

距离范围搜索的原理和最近邻搜索的差不多,把满足距离的全部放进去就可以了。

最近邻搜索的函数在激光点云匹配中找最近点的时候用的比较多:

//头文件

其中,当k为1的时候,就是最近邻搜索。当k大于1的时候,就是多个最近邻搜索。

距离范围搜索:

//在点云中寻找和点searchPoint满足radius距离的点和距离,返回下标pointIdxRadiusSearch和距离pointRadiusSquaredDistance

其完整的使用代码可以参考PCL的官方文件

:
#include 

4、参考文献

[1] https://en.wikipedia.org/wiki/K-d_tree

[2] https://www.cnblogs.com/maxlpy/p/4297254.html

[3] http://pointclouds.org/documentation/tutorials/kdtree_search.php

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值