本文讲解旨在讲解Kd-Tree(K-demension tree)的一些粗浅的原理,以及其在计算机视觉的一些应用,既是总结了自己,也是分享给大家,希望有所帮助。
Kd-Tree是从BST(Binary search tree)发展而来,是一种高维索引树形数据结构,常用于大规模高维数据密集的查找比对的使用场景中,主要是最近邻查找(Nearest Neighbor)以及近似最近邻查找(Approximate Nearest Neighbor)。在计算机视觉(CV)中主要是图像检索和识别中的高维特征向量的查找和比对。
在介绍Kd-Tree之前,首先介绍下它的父系结构——BST。二叉查找树,是一种具有如下性质的二叉树:
- 若它的左子树不为空,则它的左子树节点上的值皆小于它的根节点。
- 若它的右子树不为空,则它的右子树节点上的值皆大于它的根节点。
- 它的左右子树也分别是二叉查找树。
构造BST很简单:
- 在现有的数据中选定一个数据作为根节点的存储数值。(要求尽可能保证左右子树的集合的数量相等,优化查找速度)
- 将其它数据按照左小右大的规则往深层递归,直到叶节点,然后开辟新的叶节点,并存储当前值。
- 新的数据按照上一条进行存储。
以下就是一种二叉查找树结构示例:
如果是一维数据,我们可以用二叉查找树来进行存储,但是如果是多维的数据,用传统的二叉查找树就不能够满足我们的要求了,因此后来才发展出了满足多维数据的Kd-Tree数据结构。
Kd-tree的构造是在BST的基础上升级:
- 选定数据X1的Y1维数值a1做为根节点比对值,对所有的数值在Y1维进行一层BST排列。相当于根据Y1维数值a1对数据集进行分割。
- 选定数据X2的Y2维数值a2做为根节点比对值,对所有的数值在Y2维进行一层BST排列。也即将数据集在Y2维上又做了一层BST。
下图是一个简单的示例:
那么问题是:
- 如何决定每次根据哪个维度对子空间进行划分呢?
- 如何选定根节点的比对数值呢?
第一个问题:
- 直观的来看,我们一般会选择轮流来。先根据第一维,然后是第二维,然后第三……,那么到底轮流来行不行呢,这就要回到最开始我们为什么要研究选择哪一维进行划分的问题。我们研究Kd-Tree是为了优化在一堆数据中高频查找的速度,用树的形式,也是为了尽快的缩小检索范围,所以这个“比对维”就很关键,通常来说,更为分散的维度,我们就更容易的将其分开,是以这里我们通过求方差,用方差最大的维度来进行划分——这也就是最大方差法(max invarince)。
第二个问题:
- 选择何值未比对值,目的也是为了要加快检索速度。一般来说我们在构造一个二叉树的时候,当然是希望它是一棵尽量平衡的树,即左右子树中的结点个数相差不大。所以这里用当前维度的中值是比较合理的。
Kd-Tree和BST的区别:
- BST的每个节点存储的是值,而Kd-Tree的根节点和中间节点存储的是对某个维度的划分信息,只有叶节点里才是存储的值。
在计算机视觉领域应用Kd-Tree较多的是在特征点匹配的时候,例如SIFT特征点匹配的时候,需要两两比对特征描述子的128位特征描述向量,选取汉明距离最小的做为最佳匹配点,这个时候因为要将多个特征描述向量进行大量的查找比对,Kd-Tree就能够发挥它的大作用了。当然Kd-Tree的相关知识还有最近邻查找以及怎样在回溯查找的时间复杂度和查找准确度中取舍等等,留待以后再记录。