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

简介:

算法原理

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,如下图所示:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值