一、最邻近问题 00:06
三维点云处理中的最邻近问题是指对于点云中的每一个点,如何快速找到离其最近的其他点。常见的解决方法包括kd树和八叉树。
1.二叉树 00:24
二叉树是其他树结构的基础,主要用于处理一维数据点。
1) 最邻近问题 00:33
最邻近查找包括两种方法:
- k近邻(kNN):对于目标点(红色),查找距离最近的k个点(绿色)。
- 半径近邻(radius NN):以目标点为圆心,查找半径范围内的所有点(蓝色)。
2) 最邻近问题的重要性 01:11
最邻近问题在点云处理中应用广泛,包括:
- 法向量分析:需选择邻域点。
- 上采样、下采样及噪声去除:均依赖邻域查找。
- 聚类、深度学习和特征提取:后续课程将涉及。
- 现有开源库(如PCL、FLANN)的实现效率较低,尤其在GPU上表现不佳。
3) 点云最邻近问题困难 02:47
点云最邻近问题的难点包括:
- 不规则性:点云分布无固定规律。
- 三维数据量指数增长:网格法存在内存与分辨率矛盾。
- 海量数据处理需求:以64线激光雷达为例,每秒需处理220万点,暴力搜索复杂度达60亿次运算/50毫秒。
- 传统超级计算机(如曙光4000A)也难以满足实时处理需求,因此需依赖高效算法(如kd树、八叉树)。
4) 内容结构 05:28
本节课程结构如下:
- 二叉树:处理一维数据。
- kd树:适用于任意维度(以二维为例),通过超平面分割空间。
- 八叉树:专为三维数据设计,优于kd树的三维适应性。
5) 共同核心思想 06:32
空间分割是核心思想,具体包括:
- 跳过无关区域:通过worst distance(如根号2)排除远距离区间。
- 快速终止搜索:若目标邻域已确定,可提前结束搜索。
2.二叉树 08:35
1) 二叉树的定义 08:43
二叉树的特性:
- 左子节点值小于根节点。
- 右子节点值大于根节点。
- 左右子树均为二叉树。
- 节点结构包含key、左子节点、右子节点及附加信息(如value)。
2) 二叉树的构建或插入 10:50
-
构建二叉树的步骤
10:57
构建二叉树的步骤:
-
初始插入根节点(如100)。
-
后续节点按规则比较:
- 小于当前节点则向左子树插入。
- 大于当前节点则向右子树插入。
-
递归直至找到空位。
-
插入元素的代码实现
12:22
代码实现通过递归完成,核心逻辑为:
-
若key小于当前节点,递归插入左子树。
-
若key大于当前节点,递归插入右子树。
-
数据生成与插入过程
12:35
插入过程示例:随机数组通过逐节点比较完成构建,value字段可存储原始索引。
3) 二叉树插入复杂度 14:07
复杂度分析:
- 不平衡二叉树:退化为链表,复杂度O(n)。
- 平衡二叉树:深度为log(n),复杂度O(log n)。
- 理想情况下,平衡二叉树显著提升效率。
4) 二叉树搜索 16:21
查找数据点是否存在于二叉树中可通过递归或循环实现。存在时返回对应数据点,不存在时返回空值。
-
二叉树搜索递归
16:44
递归实现步骤如下:
-
比较关键字key与根节点值:若相等则直接返回该节点
-
根据二叉树性质选择查找方向:若key小于当前节点值则仅需查找左子树,反之仅需查找右子树
-
递归终止条件:当查找到空节点时返回空值
-
二叉树搜索迭代
17:45
迭代实现需借助栈结构:
-
使用current_node变量替代递归中的root参数:动态记录当前查找节点
-
比较逻辑与递归完全一致:通过循环实现节点值的比较与方向选择
-
时间复杂度与递归相同:均为二叉树深度O(h)
-
二叉树搜索的优缺点
19:26
递归与迭代特性对比:
| 特性 | 递归实现 | 迭代实现 |
|---|---|---|
| 实现难度 | 更简单直观 | 需手动维护状态 |
| 空间复杂度 | O(n)栈空间 | O(1)额外空间 |
| 适用场景 | CPU环境 | GPU环境 |
| 编译器优化 | 可自动转为迭代 | 无优化空间 |
现代CPU环境下推荐使用递归实现,但GPU环境需采用迭代方式。
5) 二叉树的深度优先遍历 21:34
深度优先遍历分为三种类型:
- 中序遍历(In-order):按左子树-根节点-右子树顺序访问,输出结果为有序序列
- 前序遍历(Pre-order):按根节点-左子树-右子树顺序访问,适用于树结构复制
- 后序遍历(Post-order):按左子树-右子树-根节点顺序访问,适用于节点删除操作
6) 二叉树的1NN搜索 24:16
-
1NN搜索的目标与定义
24:21
1NN搜索目标是在二叉树中查找与给定查询点距离最近的节点。查询点存在与否不影响算法逻辑。
-
搜索方法的引入与比较
24:53
传统排序二分查找法虽有效,但为引入后续kd树等数据结构,采用基于二叉树特性的搜索方法。
-
二叉树1NN搜索的具体步骤
25:32
搜索流程如下:
-
初始化最坏距离(Worst Distance):根节点与查询点的距离
-
方向选择:根据查询点与当前节点值的比较结果选择子树
-
距离更新:发现更近节点时更新最坏距离
-
剪枝优化:当某子树不可能存在更近节点时跳过搜索
-
算法优化:跳过区域的策略
28:26
空间划分策略是算法核心:
- 根据二叉树性质将搜索空间划分为左右子区域
- 通过最坏距离判断可跳过的区域
- 显著减少不必要的节点比较操作
7) 二叉树的kNN搜索 29:00
-
kNN搜索与1NN搜索的区别
29:05
kNN与1NN算法框架完全一致,区别仅在于最坏距离的计算方式。
-
kNN搜索中的最快距离(Worst Distance)
29:20
最坏距离确定方法:
-
维护容量为k的有序结果容器
-
容器末尾元素值即为当前最坏距离
-
随着搜索进行动态更新容器内容
-
kNN搜索算法的实现
30:26
实现要点:
- 结果容器初始化:预填充极大值,容量固定为k
- 节点插入机制:保持容器元素有序性
- 搜索方向优化:优先搜索更可能包含近邻点的子树
- 提前终止条件:当最坏距离降为0时可提前终止
8) 二叉树的Radius NN搜索 35:37
Radius NN搜索与KNN搜索相比更为简单,原因在于搜索半径已预先给定。KNN搜索需要通过动态调整容器来确定最近距离,而Radius NN搜索仅需收集所有距离小于给定半径的点即可。两者代码结构高度相似,主要差异体现在以下三点:
- 函数命名不同(KNN与Radius NN)
- Radius NN不存在距离为零的特殊情况(半径参数不会为零)
- 结果容器设计使得两种算法的核心逻辑完全一致
9) 应用案例 37:31
- 例题:二叉树kNN/Radius NN搜索
实验采用包含100个数字的数据库,分别执行以下操作:
-
KNN搜索:查找与目标点最近的5个点,计算次数从暴力搜索的100次降至7次
-
Radius NN搜索:查找半径20范围内的所有点,同样仅需7次对比运算
-
时间复杂度分析
:
- 最优情况:平衡二叉树下为O(log n)
- 最差情况:退化为链式结构时达O(n)
- 实际应用:二叉树结构通常不会极端退化
3.内容总结 38:57
二叉树结构仅适用于一维数据的最近邻搜索,原因如下:
- 依赖维度可比性:一维数据可直接通过大小关系判断距离,而高维数据缺乏此类直接关联
- 分支定界算法本质:最近邻搜索可视为最小化问题,二叉树通过计算距离下界(如查询点9与节点3的距离6)决定是否剪枝分支
- 扩展局限性:原始二叉树无法直接应用于KD树、八叉树等高维数据结构的最邻近搜索场景