首页 > 其他分享 >KD-Tree 学习笔记

KD-Tree 学习笔记

时间:2024-07-23 16:29:31浏览次数:11  
标签:std kdtree KD Tree 笔记 PointT pcl KdTree cloud

学习资料:

1.B站 - 一只叫小花的猫
2.语雀 - 双愚:kdtree
3.B站视频:学习kdtree的前置知识:KNN算法

KD树简介与背景

  k-d树,是一种分割k维数据空间的数据结构。主要应用于多维空间关键数据的搜索。关于kd树的背景,它主要是一种解决特征点匹配问题的算法,kd树就是一种高维空间索引结构和近似查询的算法。
  关于特征匹配算子,可以分为两类,第一种就是线性扫描法,但是这种方法将数据集中的点与查询点逐一进行距离比较,也就是穷举,缺点很明显,搜索效率较低。其次就是建立数据索引,而kdtree正是这样一种方法,其基本思想就是对搜索空间进行层次划分,划分空间没有重叠。

KD树的结构

下面这段话选自语雀 - 双愚:kdtree
image
看似较为复杂,其实一点都不复杂,二叉排序树学过吧,其实kdtree有些地方与二叉排序树有点相似,即左小右大,但是严格上来讲,又不是完全的相似,来看下面的图:kdtree的构造过程:
image
有这样的一些点集,在坐标系中画出这些点,首先我们按照垂直于x轴进行划分,如图(1),找到每个点的横坐标,2、3、4、7、8、9,取中位数为(4+7)/ 2 = 5.5,那么既然与4和7的距离都是1.5,所以我们可以取7作为一个划分的标准,分成左右两块,这时就把点(7,2)加入到树中,接着我们就按照y轴进行划分,取左右两块分别划分,与上面的逻辑是相同的,划分完毕再把点加入到树中,要注意左小右大,以此类推即可划分成功。注意:当一科kdtree的子树结点只有一个孩子时,不存在左右孩子这种说法。

KD树查找最邻近点算法

如图(选自上面b站视频):imageimage

在这里我们想找(3, 4.5)的邻近点,分为以下几个步骤:

  1. 首先看树根,这里记为第1层,树根是x(1)(这里我们把x(1)看为x轴,x(2)看为y轴),因为要找横轴为3的点,故找比7小的,这时到达(5,4)。
  2. (5,4)在y的行中,所以这时我们看4,由于4.5>4, 这时进入到(4, 7)。
  3. 到达叶子结点(4, 7),这时我们把它作为当前最临近点,计算到(3, 4.5)的距离为2.69。
  4. 开始回溯,到(5, 4),距离为2.06,更新最邻近点。这时我们发现,(3, 4.5)与(5, 4)连线为半径做圆,与y=4超平面相交,那么这时还需要进入到另一个子空间进行查找,也就是得回溯到(2, 3)这里,计算后,距离为1.8。
  5. 再次做圆,此圆与x=7并不相交,故不用进入到根结点右子树进行查找。结束。

KD树上的KNN算法

image

KD树相关函数

PCL中类pcl::KdTree<PointT>是kd-tree数据结构的实现。并且提供基于FLANN进行快速搜索的一些相关子类与包装类。具体可以参考相应的API。下面给出2个类的具体用法。

  1. pcl::search::KdTree < PointT >
    pcl::search::KdTree<PointT>pcl::search::Search< PointT >的子类,是pcl::KdTree<PointT>的包装类。包含(1) k 近邻搜索;(2) 邻域半径搜索。
    示例代码:
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/search/kdtree.h> // 包含kdtree头文件
typedef pcl::PointXYZ PointT;
int main()
{
	pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
	pcl::io::loadPCDFile("read.pcd", *cloud);
	// 定义KDTree对象
	pcl::search::KdTree<PointT>::Ptr kdtree(new pcl::search::KdTree<PointT>);
	kdtree->setInputCloud(cloud); // 设置要搜索的点云,建立KDTree
	std::vector<int> indices; // 存储查询近邻点索引
	std::vector<float> distances; // 存储近邻点对应距离的平方
	PointT point = cloud->points[0]; // 初始化一个查询点
	
	// 查询距point最近的k个点
	int k = 10;
	int size = kdtree->nearestKSearch(point, k, indices, distances);
	std::cout << "search point : " << size << std::endl;
	// 查询point半径为radius邻域球内的点
	double radius = 2.0;
	size = kdtree->radiusSearch(point, radius, indices, distances);
	std::cout << "search point : " << size << std::endl;
	system("pause");
	return 0;
}
  1. pcl::KdTreeFLANN < PointT >
    pcl::KdTreeFLANN<PointT>pcl::KdTree<PointT>的子类,可以实现同样的功能。
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
// 包含相关头文件
#include <pcl/kdtree/kdtree_flann.h>
typedef pcl::PointXYZ PointT;
int main()
{
	pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
	pcl::io::loadPCDFile("read.pcd", *cloud);
	pcl::KdTreeFLANN<pcl::PointXYZ> kdtree; //创建KDtree
	kdtree.setInputCloud(cloud); // 设置要搜索的点云,建立KDTree
	std::vector<int> indices; // 存储查询近邻点索引
	std::vector<float> distances; // 存储近邻点对应距离的平方
	PointT point = cloud->points[0]; // 初始化一个查询点
	
	// 查询距point最近的k个点
	int k = 10;
	int size = kdtree.nearestKSearch(point, k, indices, distances);
	std::cout << "search point : " << size << std::endl;
	// 查询point半径为radius邻域球内的点
	double radius = 2.0;
	size = kdtree.radiusSearch(point, radius, indices, distances);
	std::cout << "search point : " << size << std::endl;
	system("pause");
	return 0;
}

标签:std,kdtree,KD,Tree,笔记,PointT,pcl,KdTree,cloud
From: https://www.cnblogs.com/kyszdsmz/p/18318805

相关文章

  • Living-Dream 系列笔记 第62期
    树的直径:定义:树上两个距离最远的点形成的简单路径(不重复走一条边/点)性质:不唯一。树的直径的端点一定是度数为\(1\)的点。证明:显然。树的直径若有多条,则必交汇于一点,即中心。证明:首先每条直径只能交于端点(因为是一棵树,一个节点不能有两个父节点),然后此交点必定......
  • 题解:P10717「KDOI-05」简单的树上问题
    \(\text{Link}\)题意给你一颗\(n\)个结点的树,有\(k\)次操作,第\(i\)次操作:每个点初始都处于未激活状态;以\(p_{i,j}\)的概率激活点\(j\);对于每个未激活的点\(i\),如果存在激活的结点\(j,k\)且\(i\)在\(j\)到\(k\)的路径上,则\(i\)也会被激活。给出\(v_{i......
  • Markdown语法彩色提示块
    什么是彩色提示块?如下:[!NOTE]这是‘’注意‘’区块[!TIP]这是‘’提示‘’区块[!IMPORTANT]这是‘’强调‘’区块[!WARNING]这是‘’警告‘’区块[!CAUTION]这是‘’小心‘’区块这样的提示块是怎么实现的?>[!NOTE]>这是注意区块>[!TIP]>这是提示区块......
  • ArchLinux使用笔记
    {%post_linkDistro/'免启动盘安装ArchLinux'%}{%post_linkDistro/'ArchLinux-TLP'%}安装NVIDIA驱动官方完整教程:https://wiki.archlinux.org/title/NVIDIA只要卡不是太老,一般情况下,如果用的是stable内核(linux),就安装nvidia,如果用的是LTS内核(linux-lts),就安装nvidia-lt......
  • Markdown语法
    Markdown语法:纯文本标记语言文件后缀xxx.md推荐文本编辑器:Typora样式:标题   字体样式链接、列表表格图片代码......      如何查看Markdown markdown格式文本,文件后缀是.md,只要打开编辑器基本上都能编辑。但是如果你想单独查看markdown......
  • 主席数学习笔记
    笛卡尔树太难了啊。主席树可持久化数据结构\((\text{Persistentdatastructure)}\)总是可以保留每一个历史版本,并且支持操作的不可变特性\(\text{(immutable)}\)。意思就是可以查询历史值,对于每一个历史版本\(k\),都是经过第\(k-1\)个版本、修改重连\(\logn\)个节点......
  • C4D2024软件下载+自学C4D 从入门到精通【学习视频教程全集】+【素材笔记】
    软件介绍与下载:链接:链接:https://pan.baidu.com/s/1n8cripcv6ZTx4TBNj5N04g?pwd=hfg5 提取码:hfg5 基础命令的讲解:掌握软件界面和基础操作界面。学习常用的基础命令,如建模、材质、灯光、摄像机等的基本设置和调整。注意快捷键的使用,可以安装插件来显示快捷键。建模案例......
  • 【笔记】学术英语写作
    小学期修了学术英语写作,老师是我们数分三的老师(啊这)。以下是课堂笔记汇总analogy类比constitute组成attenuate减少convention公约referee审阅sanitycheckOverview完整。把数学符号翻译成英文后,行文应当符合英文语法。简洁。Don'tshow.逻辑。Motivation。......
  • pymobiledevice3:如果没有抽象方法“_create_service_connection”的实现,则无法实例化
    全面披露:我不知道我在做什么。我没有编程经验。我已要求ChatGPT为我创建一个程序。ChatGPT为我创建的文件之一名为“device_detection.py”。这个特定文件应该检测通过USB端口连接到我的笔记本电脑的智能手机设备,然后在终端中打印结果。如果这就是我所需要的,那就太好了(并且......
  • 第十四天笔记(外键)
    数据库之外键==========================、一、外键的介绍1、外键的定义让一张表记录的数据不要太过于冗余,在数据库中对表的关系进行解耦,尽量让表的数据单一化。2、外键的作用保持数据的一致性和完整性3、msyql数据库中的存储引擎?myisam(默认)innodb(外键需要用到inno......