点云数据下的KD-tree

2023-10-26

点云数据下的KD-tree检索

KD-tree简称K维树,是一种空间划分的数据结构。常被用于高维空间中的搜索,比如范围搜索最近邻搜索。kd-tree是二进制空间划分树的一种特殊情况。
在激光雷达SLAM中,一般使用的是三维点云。所以,kd-tree的维度是3。
由于三维点云的数目一般都比较大,所以,使用kd-tree来进行检索,可以减少很多的时间消耗,可以确保点云的关联点寻找和配准处于实时的状态

数据结构

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

struct kdtree{
    Node-data - 数据矢量   数据集中某个数据点,是n维矢量(这里也就是k维)
    Range     - 空间矢量   该节点所代表的空间范围
    split     - 整数       垂直于分割超平面的方向轴序号
    Left      - kd树       由位于该节点分割超平面左子空间内所有数据点所构成的k-d树
    Right     - kd树       由位于该节点分割超平面右子空间内所有数据点所构成的k-d树
    parent    - kd树       父节点  
}

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

构建KD-tree

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

构建算法:

Input: 无序化的点云,维度k
Output:点云对应的kd-tree
Algorithm:
1、初始化分割轴:对每个维度的数据进行方差的计算,取最大方差的维度作为分割轴,标记为 r;
2、确定节点:对当前数据按分割轴维度进行检索,找到中位数数据,并将其放入到当前节点上;
3、划分双支:
划分左支:在当前分割轴维度,所有小于中位数的值划分到左支中;
划分右支:在当前分割轴维度,所有大于等于中位数的值划分到右支中。
4、更新分割轴:r = (r + 1) % k;
5、确定子节点:
确定左节点:在左支的数据中进行步骤2;
确定右节点:在右支的数据中进行步骤2;

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

例如一个python实现的二维样例:

from collections import namedtuple
from operator import itemgetter
from pprint import pformat

class Node(namedtuple("Node", "location left_child right_child")):
    def __repr__(self):
        return pformat(tuple(self))

def kdtree(point_list, depth: int = 0):
    if not point_list:
        return None

    k = len(point_list[0])  # assumes all points have the same dimension
    # Select axis based on depth so that axis cycles through all valid values
    axis = depth % k

    # Sort point list by axis and choose median as pivot element
    point_list.sort(key=itemgetter(axis))
    median = len(point_list) // 2

    # Create node and construct subtrees
    return Node(
        location=point_list[median],
        left_child=kdtree(point_list[:median], depth + 1),
        right_child=kdtree(point_list[median + 1 :], depth + 1),
    )

def main():
    """Example usage"""
    point_list = [(7, 2), (5, 4), (9, 6), (4, 7), (8, 1), (2, 3)]
    tree = kdtree(point_list)
    print(tree)

if __name__ == "__main__":
    main()

输出结果为

((7, 2),
 ((5, 4), ((2, 3), None, None), ((4, 7), None, None)),
 ((9, 6), ((8, 1), None, None), None))

生成的kd-tree检索图示:
在这里插入图片描述
将实验中的7个点展示在坐标轴上:(7, 2), (5, 4), (9, 6), (4, 7), (8, 1), (2, 3)
x方向维度方差较大,取x轴坐标中位数2 4 5 7 8 9,取5或者7都可以,这里取7;
取 x=7 为分割轴,则 x<7 的点为左分支, x>7 的点为右分支;
左分支:(5, 4), (4, 7), (2, 3)
右分支:(9, 6),(8, 1)

更新分割轴:下一个维度为y轴。
在左支中找到y轴的中位数(5,4),左支数据更新为{(2,3)},右支数据更新为{(4,7)}
在右支中找到y轴的中位数(9,6),左支数据更新为{(8,1)},右支数据为null。

更新分割轴:下一个维度为x轴。
确定(5,4)的子节点:
由于只有一个数据,所以,左节点为(2,3)
由于只有一个数据,所以,右节点为(4,7)
确定(9,6)的子节点:
由于只有一个数据,所以,左节点为(8,1)
右节点为空。

最终,就可以构建整个的kd-tree了。
在点云数据下,为三维环境,在三维空间x y z 轴进行空间分割;
在这里插入图片描述
相关资料可参考:https://en.wikipedia.org/wiki/K-d_tree

最近邻检索

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

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

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

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

点云数据下的KD-tree 的相关文章

随机推荐

  • node多版本安装--nvm丝滑切换node版本

    以下是我总结得俩种nvm切换node版本的方式 首先是第一种 需要手动配置的 第一步把自己电脑上面的node卸载 在本机应用程序中卸载 然后手动本机目录删除剩余残留node npm等文件 C Users 86184 AppData C Us
  • 函数的极值点、零点、驻点、拐点的理解

    总结 零点 函数值为0的点 极值点 函数单调性发生变化的点 驻点 函数的一阶导数为0的点 拐点 函数凹凸性变化的点 学习链接 https wenku baidu com view 4a009cf5650e52ea5418982e html
  • [工程数学]1_特征值与特征向量

    首先向b站up DR CAN致敬 视频二刷了 为了收获 理解更多 用极慢的方式 把笔记抄了下来 整理一遍 为了好翻阅 后续会转成pdf格式 放微信公众号后台获取 现代控制理论 2 state space状态空间方程 在state space
  • java是什么_Java是什么?Java有什么用?

    我们经常提到Java 很多小白只听说过但对其并没有太多具体的了解 那么Java是什么 Java有什么用 今天就来探讨一下 我们常常会听说 Java是世界第一语言 很多应用软件的开发都离不开Java Java真的这么强大吗 其实 Java的内
  • 多链路传输技术在火山引擎 RTC 的探索和实践

    动手点关注 干货不迷路 传统的数据传输方式大多是利用一个链路 选择设备的默认网卡进行传输 使用这种方式实现实时音视频通话时 如果默认网络出现问题 如断网 弱网等 用户的通信就会发生中断或者卡顿 影响用户体验 多链路传输 顾名思义 就是使用多
  • electron_vue—实现消息通知 及 解决通知不显示问题

    实现消息通知 window linux macOS 这三个操作系统都为应用程序提供了向用户发送通知的方法
  • python使用pip安装出现pip is configured with locations that require TLS/SSL异常处理方法

    问题描述 最近给服务器安装python环境 通过源码方式安装Python3 8之后 使用pip功能出现异常 提示 root localhost pip3 install you get pip is configured with loca
  • 大数据处理中的关键算子:分割(Split)和选择(Select)

    在大数据处理中 分割 Split 和选择 Select 是两个常用的算子 它们在数据转换和处理过程中发挥着重要的作用 本文将详细介绍这两个算子的功能和使用方法 并附上相应的源代码示例 1 分割 Split 分割算子用于将一个数据集拆分成多个
  • 图的深度遍历和广度遍历

    理论部分 图的深度遍历和广度遍历都不算很难像极了二叉树的前序遍历和层序遍历 如下面的图 可以用右边的邻接矩阵进行表示 假设以顶点0开始对整幅图进行遍历的话 两种遍历方式的思想如下 1 深度优先遍历 depthFirstSearch DFS
  • LISN到底是啥?干啥用的?

    LISN到底是啥 干啥用的 LISN是在EMC测试的时候 会被使用的设备 如下图所示 双路V型电源阻抗稳定网络 它完全符合CISPR16 1 2 MIL STD 461F VDE 0876 FCC Part 15标准的要求 其等效电路为50
  • 20191004

    A 解 1 我们发现只需要关心处于结果字符串前 k 位的字符 因此考虑从后往前处理 对于一个询问区间 我们暴力连边 用并查集维护 x 的父亲等于 y 相当于位于 x 的字符是从位于 y 的字符处复制过来的 然后删掉这个区间 更新其他元素的排
  • Hutool BeanUtils.copyProperties的四种用法 空不拷贝/忽略拷贝/空不和忽略拷贝/全拷贝

    关注公众号 奇叔码技术 回复 java面试题大全 或者 java面试题 即可领取资料 一 Hutool BeanUtils copyProperties的四种用法 空不拷贝 忽略拷贝 空不和忽略拷贝 全拷贝 1 第一种用法 BeanUtil
  • STM32-CubeMX学习笔记

    例程参考链接 http bbs elecfans com jishu 714935 1 1 html 1 首次使用参见文档 http blog csdn net tq384998430 article details 53466263 2
  • 彻底搞懂Java中的synchronized关键字

    synchronized的作用 synchronized 的作用主要有三 原子性 所谓原子性就是指一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断 要么就都不执行 被synchronized修饰的类或对象的所有操作都是原子
  • 【歪门邪道】懒得麻烦UI同学切图所以用AndroidStudio生成icon

    每次新建项目 是不是都默认生成一个 ic launcher 对于这个icon 你是不是从来都是一删了事 你有没有一次 打开并留意过里头 ic launcher foreground 和 ic launcher background 文件 如
  • 关于以太坊的nonce值

    文章目录 每笔交易nonce值的各个情况 总结 关于Nonce的保管 依赖节点 自行管理nonce 参考代码 nonce在区块链中是一个非常重要的概念 从比特币到以太坊都有nonce的身影 在比特币中 nonce主要用于调整pow挖矿的难度
  • Go语言学习——4、数据存储:数组,切片,映射

    目录 一 数组 1 声明数组 2 初始化数组 3 遍历数组 二 切片 1 从数组或切片生成新的切片的语法格式 2 直接生成一个新的切片 3 切片添加元素 4 从切片删除元素 5 遍历切片 三 映射 1 声明映射 2 初始化映射 3 遍历映射
  • Linux--僵死进程(僵尸进程)

    1 僵死进程产生的原因或者条件 当子进程先于父进程结束 父进程没有获取子进程的退出码 此时子进程变成僵死进程 即就是子进程结束了 但父进程还没有结束的时候才会出现僵死进程 代码中 子先于父 后台运行 当一个进程结束的时候 只有进程的退出码被
  • 前端 token 应该放在哪里呢?

    总结 反正是服务端加密的传过来让前端存着的 通常的存储都可以放 只不过需要防范攻击就是了 风险 放在 webStorage 里的话 因为同源策略 可以在当前页面中注入脚本进行 xss 攻击来获取信息 比如在一个帖子下面回复了一串 js 脚本
  • 点云数据下的KD-tree

    点云数据下的KD tree检索 数据结构 构建KD tree 最近邻检索 KD tree简称K维树 是一种空间划分的数据结构 常被用于高维空间中的搜索 比如范围搜索和最近邻搜索 kd tree是二进制空间划分树的一种特殊情况 在激光雷达SL