PCL中 的 kd-tree

PCL 中的 kd-tree ,使用的是 FLANN 项目中的数据结构,支持《快速最近邻搜索》。

 

kd-tree 简称k维树,它是一种空间划分数据结构,它将一组 k 维点存储在一个树结构中,可以理解是 k 维的二叉树。

kd-tree 可以实现有效的《范围搜索》和《最近邻搜索》。

《最近邻搜索》是处理点云数据的核心操作,可用于查找点组或特征描述符之间的对应关系,或者,定义一个或多个点周围的局部邻域。

PCL 中的 kd-tree 位于 common 模块(pcl_common.dll)。

使用时要引用以下头文件:

#include pcl/kdtree/kdtree_flann.h>

以下用一个例子练习一下如何使用 kd-tree 进行点云的《最近邻搜索》。

打开 QT Creator ,然后,新建 QT Application 项目。

在项目文件 .pro 文件中添加如下包含目录和引用的 lib 库

INCLUDEPATH += C:\PCL1.12.1\include\pcl-1.12 
  C:\PCL1.12.1\3rdParty\FLANN\include \
  C:\PCL1.12.1\3rdParty\Boost\include\boost-1_78 \
  C:\PCL1.12.1\3rdParty\Eigen\eigen3 \
win32:LIBS += $$quote(C:\PCL1.12.1\lib\pcl_commond.lib)
win32:LIBS += $$quote(C:\PCL1.12.1\3rdParty\FLANN\lib\flann_s.lib)
win32:LIBS += $$quote(C:\PCL1.12.1\3rdParty\FLANN\lib\flann_cpp_s.lib)

在 main.cpp 的顶部添加头文件引用:

#include <QApplication>
#include <pcl/point_cloud.h>
#include <pcl/kdtree/kdtree_flann.h>

在 main.cpp 的 main 函数中输入如下代码:

//创建6个点的点云
pcl::PointCloudpcl::PointXYZ::Ptr clound(new pcl::PointCloudpcl::PointXYZ());
clound->width = 6;
clound->height = 1;
clound->resize(clound->width *clound->height);
for(int i = 0; i < clound->points.size(); ++i)
{
    clound->points[i].x = (i * 3) + 1;
    clound->points[i].y = (i * 3) + 10;
    clound->points[i].z = (i * 3) + 100;
}
//打印点云
qDebug() << "Clound : ";
for(int i = 0; i < clound->points.size(); ++i)
{
    qDebug() << clound->points[i].x << "," << clound->points[i].y << "," << clound->points[i].z;
}

//创建kd-tree对象,并将点云对象赋值给它
pcl::KdTreeFLANNpcl::PointXYZ tree;
tree.setInputCloud(clound);

//最近邻搜索

//要搜索的点
pcl::PointXYZ pt;
pt.x = 1.5;
pt.y = 10.5;
pt.z = 100.5;

//k近邻搜索
int K = 3;//最近的3个点
std::vector<int> indices;//最近的点的索引
std::vector<float> sqr_distance;//最近的点离搜索点的平方距离
//执行k近邻搜索
tree.nearestKSearch(pt, K, indices, sqr_distance);
//打印搜索结果
qDebug() << "Indices : ";
for(int i = 0; i < indices.size(); ++i)
{
    qDebug() << indices[i];
}
qDebug() << "sqr_distance : ";
for(int i = 0; i < sqr_distance.size(); ++i)
{
    qDebug() << sqr_distance[i];
}

//半径近邻搜索
double raius = 5;//距离为5
indices.clear();//最近的点的索引
sqr_distance.clear();//最近的点离搜索点的平方距离
//执行半径近邻搜索
tree.radiusSearch(pt, raius, indices, sqr_distance);
//打印搜索结果
qDebug() << "Indices : ";
for(int i = 0; i < indices.size(); ++i)
{
    qDebug() << indices[i];
}
qDebug() << "sqr_distance : ";
for(int i = 0; i < sqr_distance.size(); ++i)
{
    qDebug() << sqr_distance[i];
}

我使用的是编译器是MSC++Compiler16(VS2019):

用该编译器时,PCL中有1个位置有一个bug,对vs的编译器漏写了一个变量,编译项目时,会提示错误,这时,需要修改后才能通过编译:

(1)修改 dist.h 文件

文件路径:C:\PCL1.12.1\3rdParty\FLANN\include\flann\algorithms\dist.h。

另外,QT6.3 创建的项目,默认使用 C++17,.pro文件中有如下行:

PCL1.12.1 使用的 FLANN 项目代码中有2处被C++17弃用的STL函数,项目编译时也会提示错误,这时,需要手动修改:

(1)std::binary_function 函数

调用该函数的文件是:

C:\PCL1.12.1\3rdParty\FLANN\include\flann\util\heap.h

直接注释掉即可:

(2)std::random_shuffle 函数

调用该函数的文件有3个:

C:\PCL1.12.1\3rdParty\FLANN\include\flann\util\random.h

C:\PCL1.12.1\3rdParty\FLANN\include\flann\algorithms\kdtree_index.h

C:\PCL1.12.1\3rdParty\FLANN\include\flann\util\lsh_table.h

三个文件中都把 std::random_shuffle 函数调用改为 std::shuffle 函数调用即可,如下:

(2.1)修改 random.h

第一步,头文件添加 #include :

第二步,把 std::random_shuffle 函数调用改为 std::shuffle 函数调用:

(2.2)修改 kdtree_index.h

第一步,头文件添加 #include :

第二步,把 std::random_shuffle 函数调用改为 std::shuffle 函数调用:

(2.3)修改 lsh_table.h

第一步,头文件添加 #include :

第二步,把 std::random_shuffle 函数调用改为 std::shuffle 函数调用:

以上的例子编译成功后,运行可以得到如下输出:

Clound :
1 , 10 , 100
4 , 13 , 103
7 , 16 , 106
10 , 19 , 109
13 , 22 , 112
16 , 25 , 115
Indices :
0
1
2
sqr_distance :
0.75
18.75
90.75
Indices :
0
1
sqr_distance :
0.75
18.75

 如上所示,K近邻搜索得到,离搜索点最近的3个点的平方距离是 0.75、18.75、90.75 ,可见之后的半径为 5 的半径搜索只能搜索到最大 5*5=25 距离的点,因此,结果就是如图所示的 0.75 和 18.75 这 2 个点。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值