CloudCompare 中的 KDTree
详解
1. 什么是 KDTree
?
KDTree
是 K 维空间划分树(K-Dimensional Tree),它是一种 用于高效查找最近邻点 的数据结构。
CloudCompare 中的 KDTree
主要用于:
- 最近邻搜索(Nearest Neighbor Search)
- 点云匹配和 ICP(Iterative Closest Point)配准
- 点云去噪
- 半径范围搜索
- 点云加速索引
相比 DgmOctree
(八叉树),KDTree
在 高维数据查找 方面更高效,特别是在 点云数据较大 时。
2. KDTree
的核心数据结构
KDTree
主要由 KdCell
结构体和 KD 树递归构建、搜索等方法 组成。
class CC_CORE_LIB_API KDTree
{
public:
//! 默认构造函数
KDTree();
//! 析构函数
virtual ~KDTree();
//! 构建 KD 树
bool buildFromCloud(GenericIndexedCloud* cloud, GenericProgressCallback* progressCb = nullptr);
//! 获取构建 KD 树的点云
GenericIndexedCloud* getAssociatedCloud() const { return m_associatedCloud; }
//! 进行最近邻搜索
bool findNearestNeighbour( const PointCoordinateType* queryPoint,
unsigned& nearestPointIndex,
ScalarType maxDist );
//! 进行带最大距离约束的最近邻搜索
bool findNearestNeighbourWithMaxDist( const PointCoordinateType* queryPoint,
ScalarType maxDist );
//! 在给定距离范围内查找点
unsigned radiusSearch( const PointCoordinateType* queryPoint,
ScalarType distance,
ScalarType tolerance,
std::vector<unsigned>& pointIndexes );
protected:
struct KdCell
{
unsigned cuttingDim; // 划分维度(x/y/z)
PointCoordinateType cuttingCoordinate; // 划分位置
struct KdCell* leSon; // 左子节点
struct KdCell* gSon; // 右子节点
struct KdCell* father; // 父节点
unsigned startingPointIndex; // 该单元格中的起始点索引
unsigned nbPoints; // 该单元格包含的点数
CCVector3 inbbmax; // 内部包围盒最大坐标
CCVector3 inbbmin; // 内部包围盒最小坐标
CCVector3 outbbmax; // 外部包围盒最大坐标
CCVector3 outbbmin; // 外部包围盒最小坐标
};
KdCell* m_root; // 根节点
std::vector<unsigned> m_indexes; // 点索引
GenericIndexedCloud* m_associatedCloud; // 关联的点云数据
unsigned m_cellCount; // 树中的单元格数
};
3. KDTree
的主要功能
(1)构建 KD 树
CloudCompare 通过 KDTree::buildFromCloud()
方法来 构建 KD 树:
CCCoreLib::KDTree kdTree;
kdTree.buildFromCloud(&cloud);
构建 KD 树后,点云数据被组织成 层级化的树结构,便于加速最近邻搜索。
(2)最近邻搜索
🔹 findNearestNeighbour()
方法
查找最近邻点:
CCCoreLib::KDTree kdTree;
unsigned nearestPointIndex;
CCVector3 queryPoint(1.0, 2.0, 3.0);
bool found = kdTree.findNearestNeighbour(queryPoint.u, nearestPointIndex, 10.0);
queryPoint
是查询点nearestPointIndex
返回找到的最近邻点索引10.0
是搜索的最大距离阈值
返回值:
true
:找到最近点,且其距离≤ maxDist
false
:未找到
🔹 findNearestNeighbourWithMaxDist()
方法
优化的最近邻搜索,仅判断是否存在某个点在 maxDist
以内:
bool exists = kdTree.findNearestNeighbourWithMaxDist(queryPoint.u, 10.0);
比 findNearestNeighbour()
速度更快,因为它不需要返回最近点的具体索引。
(3)半径范围搜索
radiusSearch()
方法用于 查找所有位于给定半径范围内的点:
std::vector<unsigned> neighbors;
float searchRadius = 5.0;
float tolerance = 0.1;
unsigned count = kdTree.radiusSearch(queryPoint.u, searchRadius, tolerance, neighbors);
返回 位于 [radius - tolerance, radius + tolerance]
之间的所有点的索引。
(4)递归 KD 树操作
KD 树的搜索和索引操作涉及递归遍历:
🔹 计算点到单元格的距离
ScalarType distance = kdTree.pointToCellSquareDistance(queryPoint.u, kdCell);
计算点到 KD 树单元格的平方距离。
🔹 递归遍历 KD 树查找最近点
int closestIndex = kdTree.checkClosestPointInSubTree(queryPoint.u, maxDist, kdCell);
- 递归遍历 KD 树
- 仅返回 比
maxDist
更近的点 - 用于优化搜索速度
4. KDTree
vs DgmOctree
数据结构 | KDTree | DgmOctree |
---|---|---|
主要用途 | 最近邻搜索 | 点云索引、邻域搜索 |
适用数据 | 任意维度的点云数据 | 三维点云 |
构建复杂度 | O(n log n) | O(n) |
查询速度 | O(log n) | O(log n) |
适用场景 | ICP、点匹配、密集点云处理 | 点云分割、降采样、大规模点云 |
5. KDTree
的应用
(1)ICP(迭代最近点)配准
CloudCompare 使用 KDTree
来 加速 ICP 计算最近邻点:
CCCoreLib::ICPRegistrationTools::Parameters params;
params.kdTree = &kdTree; // 使用 KD 树加速
CCCoreLib::ICPRegistrationTools::Result result;
CCCoreLib::ICPRegistrationTools::Register(&sourceCloud, &targetCloud, params, result);
(2)点云去噪
在 CloudCompare 进行 统计滤波 时,可用 KDTree
进行 K 近邻搜索:
std::vector<unsigned> neighbors;
unsigned k = 10; // 查找最近的 10 个邻居
for (size_t i = 0; i < cloud.size(); ++i)
{
kdTree.findNearestNeighbour(cloud.getPoint(i).u, k, neighbors);
}
- 计算点周围的 均值和标准差
- 过滤掉离群点(噪声)
(3)点云匹配
CloudCompare 进行 点云配准时,可以使用 KDTree
加速最近邻搜索,从而提高计算效率。
6. 总结
✅ KDTree
是 加速最近邻搜索 的核心数据结构
✅ 适用于 ICP、点云去噪、K 近邻搜索、半径范围查询
✅ 对于 大规模点云数据,KDTree
比 DgmOctree
更高效
✅ CloudCompare 通过 KDTree
优化 ICP 配准、点云匹配和点云降噪