简介:

算法原理

1、建立kdtree

主要有两步操作:选择合适的分割维度,选择中值节点作为分割节点

  • 分割维度的选择遵循的原则是,选择范围最大的纬度,也即是方差最大的纬度作为分割维度;
  • 分割节点的选择原则是,将这一维度的数据进行排序,选择正中间的节点作为分割节点,确保节点左边的点的维度值小于节点的维度值,节点右边的点的维度值大于节点的维度值。

建立kdtree可遵循以下步骤:

1)  建立一维数组,存储每一个点的索引,并进行随机打乱。

2)  定义合适的kdtree函数定义,方便进行递归建树。

3)  分割维度函数,计算当前空间的所有数据每一维度的方差,选择方差最大的维度作为分割维度,并计算出维度均值;

4) 分割节点函数,选择中值节点,但是并不是说要把全部数据进行排序,排序太费时了。使用步骤3选择的维度的均值进行一趟快速排序,将该维度的数据分为两部分,大于均值的数据、小于均值的数据,然后从小于均值的空间中选择最大的节点作为父节点,这样就保证左子树所有节点小于父节点,右子树所有节点大于父节点。

5)  kdtree函数功能实现:选择分割维度,选择分割节点,将节点左边的数据进行递归建立左子树,将节点右边的数据进行递归建立右子树

 2、k近邻搜索

最临近搜索即是查找距离查找点最近的k个点。在讲述k临近搜索之前,先讲述下最近邻搜索的概念。

最近邻搜索的基本思路是:从根节点开始,通过二叉树搜索,如果节点的分割维度值小于查找点的维度值表示查找点位于左子树空间中,则进入左子树,如果大于则进入右子树,直到达到叶子节点为止,将搜索路径上的每一个节点都加入到路径中;然后再回溯搜索路径,并判断未加入路径的其他子节点空间中是否可能有距离搜索点更近的节点,如果有可能,则遍历子节点空间,并将遍历到的节点加入到搜索路径中,重复这个过程直到搜索路径为空。

k近邻搜索的思路是:同样是先遍历kdtree,将遍历到的节点加入到搜索路径中,然后回溯路径;建立最大堆,在回溯路径中,将小于堆顶最大距离的节点加入堆,直到搜索路径为空。实际实现过程中,需要注意的是,先出队列的是叶子节点,距离查找点比较近,最先加入最大堆,从而堆顶距离比较小,在最大堆不满时,进行距离判断,可能会将在k近邻范围内的节点排除掉,因此预先加入一个极大距离节点可避免最大堆不满时,排除掉正确的节点。

举一些例子来说明上面的最近邻搜索算法,假设我们的k-d tree就是上面通过样本集{(2,3), (5,4), (9,6), (4,7), (8,1), (7,2)}创建的。将上面的图转化为树形图的样子如下:

我们来查找点(2.1,3.1),在(7,2)点测试到达(5,4),在(5,4)点测试到达(2,3),然后search_path中的结点为<(7,2), (5,4), (2,3)>,从search_path中取出(2,3)作为当前最佳结点nearest, dist为0.141;

然后回溯至(5,4),以(2.1,3.1)为圆心,以dist=0.141为半径画一个圆,并不和超平面y=4相交,如下图,所以不必跳到结点(5,4)的右子空间去搜索,因为右子空间中不可能有更近样本点了。

于是在回溯至(7,2),同理,以(2.1,3.1)为圆心,以dist=0.141为半径画一个圆并不和超平面x=7相交,所以也不用跳到结点(7,2)的右子空间去搜索至此,search_path为空,结束整个搜索,返回nearest(2,3)作为(2.1,3.1)的最近邻点,最近距离为0.141。

再举一个稍微复杂的例子,我们来查找点(2,4.5),在(7,2)处测试到达(5,4),在(5,4)处测试到达(4,7),然后search_path中的结点为<(7,2), (5,4), (4,7)>,从search_path中取出(4,7)作为当前最佳结点nearest, dist为3.202;

然后回溯至(5,4),以(2,4.5)为圆心,以dist=3.202为半径画一个圆与超平面y=4相交,如下图,所以需要跳到(5,4)的左子空间去搜索。所以要将(2,3)加入到search_path中,现在search_path中的结点为<(7,2), (2, 3)>;另外,(5,4)与(2,4.5)的距离为3.04 < dist = 3.202,所以将(5,4)赋给nearest,并且dist=3.04。

回溯至(2,3),(2,3)是叶子节点,直接判断(2,3)是否离(2,4.5)更近,计算得到距离为1.5,所以nearest更新为(2,3),dist更新为(1.5)。回溯至(7,2),同理,以(2,4.5)为圆心,以dist=1.5为半径画一个圆并不和超平面x=7相交, 所以不用跳到结点(7,2)的右子空间去搜索。至此,search_path为空,结束整个搜索,返回nearest(2,3)作为(2,4.5)的最近邻点,最近距离为1.5。

from:https://www.cnblogs.com/bwin/p/5247416.html

算法编程:https://www.cnblogs.com/xingzhensun/p/9693362.html

算法详解:https://blog.csdn.net/silangquan/article/details/41483689

实例:

代码如下,其实就是照着教程自己敲进去,不过就这样,也会出不少错,当然只有这样才能进步,各位小伙伴最好别直接复制粘贴,有时间还是敲代码比较好!

#include<pcl\kdtree\kdtree_flann.h>
#include<pcl\point_cloud.h>
#include<pcl\point_types.h>    //用来定义点云类型
#include<pcl\io\io.h>
#include<iostream>
#include<ctime>
#include<vector>
using namespace std;int main()
{srand(time(NULL));pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);//初始点云对象cloud->width = 100;cloud->height = 1;cloud->resize(cloud->width*cloud->height);for (int i = 0; i < cloud->width*cloud->height; i++) //随机数填充点云数据{cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);}pcl::KdTreeFLANN<pcl::PointXYZ>kdtree; //创建kdtree搜索对象kdtree.setInputCloud(cloud);           //载入点云pcl::PointXYZ searchPoint;              //设置查询点并赋随机值searchPoint.x = 1024.0f* rand() / (RAND_MAX + 1.0f);searchPoint.y = 1024.0f* rand() / (RAND_MAX + 1.0f);searchPoint.z = 1024.0f* rand() / (RAND_MAX + 1.0f);int K = 10;                             //搜索最近邻的点数vector<int>pointIdxNKNSearch(K);        //存放最近邻点的索引vector<float>pointNKNSquaredDistance(K);//对应的距离平方cout << "K nearest neighbor search at (" << searchPoint.x<< " " << searchPoint.y<< " " << searchPoint.z<< ") with K=" << K << std::endl;if (kdtree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance)>0){for (int i=0; i < pointIdxNKNSearch.size(); ++i){cout << "  " << cloud->points[pointIdxNKNSearch[i]].x<< "  " << cloud->points[pointIdxNKNSearch[i]].y<< "  " << cloud->points[pointIdxNKNSearch[i]].z<< " (squared distance: " << pointNKNSquaredDistance[i] << ")" << endl;}}// 在半径r内搜索近邻std::vector<int> pointIdxRadiusSearch;std::vector<float> pointRadiusSquaredDistance;float radius = 256.0f* rand() / (RAND_MAX + 1.0f); //定义搜索半径std::cout << "Neighbors within radius search at (" << searchPoint.x<< " " << searchPoint.y<< " " << searchPoint.z<< ") with radius=" << radius << std::endl;if (kdtree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) >0){for (size_t i = 0; i<pointIdxRadiusSearch.size(); ++i)std::cout << "    " << cloud->points[pointIdxRadiusSearch[i]].x<< " " << cloud->points[pointIdxRadiusSearch[i]].y<< " " << cloud->points[pointIdxRadiusSearch[i]].z<< " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;}system("pause");return 0;
}

说几点自己在敲代码过程中遇到的问题:生成解决文件失败:

error C2079: “pcl::KdTreeFLANN::param_radius_”使用未定义的 struct“flann::SearchParams”

解决方法:

PCL版本为1.8.1

我的问题出在了包含目录设置上。具体解决方案是在 属性->C++目录->包含目录 中。

一开始包含目录的路径为D:\PCL 1.8.1\3rdParty\FLANN\include\flann

请把它改为:D:\PCL 1.8.1\3rdParty\FLANN\include,如下图所示:

PCL学习(3)——kdtree搜索(error C2079: “pcl::KdTreeFLANN::param_radius_)相关推荐

  1. PCL学习笔记(二):PCL官方教程学习

    PCL学习笔记(二):PCL官方教程学习 PCD文件制作 Features 表面法线提取 Keypoints 提取NARF关键点 KdTree Range Image How to create a ...

  2. PCL中利用KD-Tree搜索空间点云最临近点源码

    0 关于KD-Tree 关于kd-tree的基本原理和构造实现情况可以参考博文:<KD-Tree结构与算法原理> 1 PCL中使用kd-tree进行最近邻点搜索 先分部解释,完整代码见第二 ...

  3. PCL学习一:点云与PCL基础

    参考引用 黑马机器人 | PCL-3D点云 PCL(Point Cloud Library)学习记录 PCL点云库学习笔记(文章链接汇总) 1. 点云概述 点云(Point Cloud)是三维空间中, ...

  4. PCL中使用KdTree在点云中进行K近邻及半径查询

    KdTree背景知识 KdTree(也称k-d树)是一种用来分割k维数据空间的高维空间索引结构,其本质就是一个带约束的二叉搜索树,基于KdTree的近似查询的算法可以快速而准确地找到查询点的近邻,经常 ...

  5. PCL学习笔记(八)-- PCL实现快速邻域搜索

    一.简介 学习如何用k-d tree树找到具体点或空间位置的k近邻,然后学习如何找到用户指定的(本例中是随机的)某一半径内的所有近邻. Vector: C++标准库提供了被封装的动态数组--Vecto ...

  6. 第七周PCL学习--点云配准(七)

    目录 引言 一.点云配准 1.1.定义 1.2.含义 1.3.配准过程 1.4.算法原理 1.5.实验 二.总结 三.参考 引言 随着计算机辅助设计技术的发展,通过实物模型产生数字模型的逆向工程技术, ...

  7. PCL学习九:Registration-配准

    参考引用 Point Cloud Library 黑马机器人 | PCL-3D点云 PCL点云库学习笔记(文章链接汇总) 1. 点云中的数学 函数求导 对于函数 f ( x ) = x 2 f(x)= ...

  8. 点云PCL学习笔记-分割segmentation-RANSAC随机采样一致性算法欧式聚类提取

    随机采样一致性算法RANSAC 程序实例参考网址: https://pcl.readthedocs.io/projects/tutorials/en/latest/random_sample_cons ...

  9. PCL学习笔记(35)——3D物体识别

    源码 #include <pcl/io/pcd_io.h> #include <pcl/point_cloud.h> #include <pcl/corresponden ...

最新文章

  1. 《C++ primer》--第1,2章小结
  2. C++异常实现与longjmp, setjmp,栈指针EBP, Active Record
  3. Android studio 使用Gradle发布Android开源项目到JCenter 总结
  4. Debian耳机声音问题
  5. 每个程序员都应该知道的基础数论
  6. 双击程序后系统弹框“您无权访问此程序”的解决办法
  7. 使用SpringTest测试,默认情况事务是不会提交的
  8. python的高级特性3:神奇的__call__与返回函数
  9. vue样式控制的方式
  10. index.php p=,弃用p值:你准备好了吗?
  11. 数据结构(主席树):HZOI 2016 采花
  12. JSTL—fn使用方法总结
  13. cannot import name ‘Imputer‘ from ‘sklearn.preprocessing‘
  14. 华为机顶盒视频播放代码
  15. mysql处理微信表情
  16. JAVA SE程序设计及实践
  17. 内网渗透DC-1靶场通关(CTF)
  18. 最好的android智能手表,安卓智能手表推荐?十款好用的安卓智能手表排行榜
  19. 小傻蛋的妹妹跟随小甲鱼学习Python的第一节001
  20. 一文读懂,WMS仓储管理系统与ERP有什么区别

热门文章

  1. php 数组改成索引数组_PHP 自定义集合与数组规范
  2. ap心理可以用计算机吗,AP考试哪些科目需要使用计算器
  3. android LinearLayout和RelativeLayout实现精确布局
  4. vue 导入excel解析_VUE中导入excel文件
  5. Java基础---File类,就是这么简单
  6. 0.接口测试学习路径
  7. vim系统配置文件,配置专属自己的环境
  8. 如何实现绑定进程到指定核上?如何实现绑定某个中断到指定核上?
  9. HTML/CSS/JavaScript学习笔记【持续更新】
  10. subprocss模块