PCL KD树的原理及应用(K邻域搜索、半径搜索)(Kdtree_kdtree)

PCL专栏目录及须知

注意:KD树常用来进行K邻域搜索、半径搜索

本文章中3.注意事项的内容为工作中常犯的错误,需留意。

1.原理

1.1 KD树数据结构

(1)又称K维树,用来组织表示K维空间中的点集合。是一种带有约束条件的二分查找树。在PCL中,通常只使用三个维度(xyz),因此PCL中的KD树可直接看做三维KD树。

(2)构造KD树时,如下图所示,不断使用垂直于坐标轴的超平面将K维空间一分为二,切分之后,节点左边的子树代表在超平面左边的点,节点右边的子树代表在超平面右边的点。

1.2 构造KD树

如:我们需对二维平面上的一些点组织KD树。点位如下:(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)。

(1)组织结果如下图:

(2)组织步骤:

1)将上述六个点的点集按照二维平面的第一维(x轴)对数据进行排序,排序结果为(2,3),(4,7),(5,4),(7,2),(8,1),(9,6)

2)取得上述点集的中位数处的点,偶数个数的中位数一般取大的那个,在上述点集中取到的为(7,2),在该点处对平面进行划分,如图1中(7,2)位置画上一条竖线

3)将由(7,2)划分的左右两平面中的剩余点按照二维平面的第二维(y轴)对数据排序,排序结果为左枝:(2,3),(5,4),(4,7)和右枝(8,1),(9,6)

4)将左枝和右枝分别取中位数点作为新的节点,按照第一维继续排序,直致每一个子枝上只剩一个点,这个点被称作叶子。

5)得到KD树。

组织步骤图如下:

1.3 KD树的最邻近查找

以查询数据Q举例:

(1)将查询数据Q从根结点开始,按照Q与各个结点的比较结果向下访问Kd-Tree,直至达到叶子结点。

Q与结点的比较:将Q对应于结点中的k维度上的值与中值m进行比较,若Q(k) < m,则访问左子树,否则访问右子树。达到叶子结点时,计算Q与叶子结点上保存的数据之间的距离,记录下最小距离对应的数据点,记为当前最近邻点nearest和最小距离dis。

(2)进行回溯操作,已查询是是否有离Q更近的“最近邻点”。即判断未被访问过的分支里是否还有离Q更近的点,它们之间的距离小于dis。

1)如果Q与其父结点下的未被访问过的分支之间的距离小于dis,则认为该

在点云处理中,**八叉(Octree)**和**KDKDTree)**是两种常见的空间索引结构,它们在CloudCompare等点云处理软件中被广泛使用,用于加速最近邻搜索、点云压缩、空间划分等任务。尽管它们在某些方面有相似之处,但在结构特性和适用场景上存在显著差异。 ### 八叉(Octree) 八叉是一种状数据结构,适用于三维空间的递归划分。其核心思想是将空间划分为八个子立方体(即“八叉”),每个节点最多有八个子节点。这种结构特别适合处理大规模点云数据,因为它可以有效地减少需要直接处理的数据量。 - 八叉的划分是各向同性的,即每个节点的子空间在x、y、z三个方向上均等地被分割。 - 在点云压缩和降采样中,八叉能够通过合并空节点来减少数据量。 - 在空间查询中,八叉支持快速的空间邻域搜索和包围盒检测[^5]。 ### KDKDTreeKD是一种二叉结构,适用于多维空间的划分。在三维点云处理中,KD通过在不同维度上交替划分空间,每次将空间划分为两个子空间。 - KD的划分是各向异性的,每次划分只沿一个维度进行。 - 它在最近邻搜索(如KNN)和点云配准中表现优异,尤其是当数据分布稀疏时。 - 相较于八叉KD的构建速度通常更快,但在高维空间中可能会出现“维度灾难”问题[^3]。 ### 选择依据 - **数据分布**:如果点云分布较为均匀,八叉可能更适合;如果数据分布稀疏且需要高效最近邻搜索KD更具优势。 - **查询类型**:对于空间范围查询或包围盒检测,八叉更优;对于点对点的最近邻查询,KD通常更快。 - **内存占用**:八叉通常占用更多内存,尤其是在深度较大的情况下;而KD相对更节省内存。 ### 在CloudCompare中的应用 在CloudCompare中,八叉常用于点云的可视化加速和空间划分,而KD则用于高效的最近邻搜索和配准算法。用户可以根据具体任务需求选择合适的数据结构: - 使用`Octree`进行点云压缩或空间划分时,可以通过设置最大深度控制精度。 - 使用`KDTree`进行最近邻搜索时,可通过`kdtree`模块实现高效的点云匹配和配准操作[^5]。 ```cpp // 示例:使用PCL库构建KDTree进行最近邻搜索 #include <pcl/kdtree/kdtree_flann.h> pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // 填充点云数据... pcl::KdTreeFLANN<pcl::PointXYZ> kdtree; kdtree.setInputCloud(cloud); pcl::PointXYZ searchPoint; searchPoint.x = 1.0; searchPoint.y = 2.0; searchPoint.z = 3.0; int K = 5; std::vector<int> pointIdxNKNSearch(K); std::vector<float> pointNKNSquaredDistance(K); if (kdtree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0) { for (size_t i = 0; i < pointIdxNKNSearch.size(); ++i) std::cout << " " << cloud->points[pointIdxNKNSearch[i]].x << " " << cloud->points[pointIdxNKNSearch[i]].y << " " << cloud->points[pointIdxNKNSearch[i]].z << " (squared distance: " << pointNKNSquaredDistance[i] << ")" << std::endl; } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值