• 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 库

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

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

    1. #include
    2. #include
    3. #include

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

    1. //创建6个点的点云
    2. pcl::PointCloudpcl::PointXYZ::Ptr clound(new pcl::PointCloudpcl::PointXYZ());
    3. clound->width = 6;
    4. clound->height = 1;
    5. clound->resize(clound->width *clound->height);
    6. for(int i = 0; i < clound->points.size(); ++i)
    7. {
    8. clound->points[i].x = (i * 3) + 1;
    9. clound->points[i].y = (i * 3) + 10;
    10. clound->points[i].z = (i * 3) + 100;
    11. }
    12. //打印点云
    13. qDebug() << "Clound : ";
    14. for(int i = 0; i < clound->points.size(); ++i)
    15. {
    16. qDebug() << clound->points[i].x << "," << clound->points[i].y << "," << clound->points[i].z;
    17. }
    18. //创建kd-tree对象,并将点云对象赋值给它
    19. pcl::KdTreeFLANNpcl::PointXYZ tree;
    20. tree.setInputCloud(clound);
    21. //最近邻搜索
    22. //要搜索的点
    23. pcl::PointXYZ pt;
    24. pt.x = 1.5;
    25. pt.y = 10.5;
    26. pt.z = 100.5;
    27. //k近邻搜索
    28. int K = 3;//最近的3个点
    29. std::vector<int> indices;//最近的点的索引
    30. std::vector<float> sqr_distance;//最近的点离搜索点的平方距离
    31. //执行k近邻搜索
    32. tree.nearestKSearch(pt, K, indices, sqr_distance);
    33. //打印搜索结果
    34. qDebug() << "Indices : ";
    35. for(int i = 0; i < indices.size(); ++i)
    36. {
    37. qDebug() << indices[i];
    38. }
    39. qDebug() << "sqr_distance : ";
    40. for(int i = 0; i < sqr_distance.size(); ++i)
    41. {
    42. qDebug() << sqr_distance[i];
    43. }
    44. //半径近邻搜索
    45. double raius = 5;//距离为5
    46. indices.clear();//最近的点的索引
    47. sqr_distance.clear();//最近的点离搜索点的平方距离
    48. //执行半径近邻搜索
    49. tree.radiusSearch(pt, raius, indices, sqr_distance);
    50. //打印搜索结果
    51. qDebug() << "Indices : ";
    52. for(int i = 0; i < indices.size(); ++i)
    53. {
    54. qDebug() << indices[i];
    55. }
    56. qDebug() << "sqr_distance : ";
    57. for(int i = 0; i < sqr_distance.size(); ++i)
    58. {
    59. qDebug() << sqr_distance[i];
    60. }

    我使用的是编译器是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 函数调用:

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

    1. Clound :
    2. 1 , 10 , 100
    3. 4 , 13 , 103
    4. 7 , 16 , 106
    5. 10 , 19 , 109
    6. 13 , 22 , 112
    7. 16 , 25 , 115
    8. Indices :
    9. 0
    10. 1
    11. 2
    12. sqr_distance :
    13. 0.75
    14. 18.75
    15. 90.75
    16. Indices :
    17. 0
    18. 1
    19. sqr_distance :
    20. 0.75
    21. 18.75

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

  • 相关阅读:
    剑指JUC原理-17.CompletableFuture
    【电源专题】LDO噪声来源
    Redis理解
    深度讲解风险策略的调优|附实操案例
    融合GPT大模型产品,WakeData新一轮产品升级
    SpringBoot快速入门
    nginx的ip_hash算法
    如何挑选自媒体平台进行创作?这3个关键需要把握
    Kruskal算法
    实践篇2:深度学习之----LetNet之tensorflow2的实现
  • 原文地址:https://blog.csdn.net/liuyangwuhan1980/article/details/126777614