PCL KD树的使用

目录

一、概述

1.1原理

1.1.1 数据拆分过程

1.1.2 树的构建示例

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

2.1.1KD树构建与查询:

2.1.2 k近邻搜索

 2.1.3半径搜索

2.2完整代码

三、实现效果

3.1处理后点云

3.2数据显示


PCL点云算法汇总及实战案例汇总的目录地址链接:

PCL点云算法与项目实战案例汇总(长期更新)


一、概述

        KD树(K-D Tree)是一种用于组织k维空间中的点的数据结构,常用于高效的最近邻搜索、范围查询等操作。KD树通过递归地将空间划分成k维的超矩形,使得在高维空间中的搜索变得更加高效。本文将详细介绍KD树的构建原理及其在PCL中的应用。

1.1原理

        KD树的全称是k维树(k-Dimensional Tree),它是一种二叉树,用于对k维空间中的点进行组织,以便于快速地进行点的查询操作(如最近邻搜索)。KD树的基本思想是通过递归地将数据空间划分为两个部分,从而形成一棵二叉树。每个节点代表一个k维超矩形,划分过程直到节点包含的数据点数目低于某个阈值或不能再划分为止。

1.1.1 数据拆分过程

1.选择维度:
    - 在构建KD树时,选择一个维度来划分数据空间。通常,使用循环选择的方法,即在每一层递归中,依次选择数据的不同维度。例如,在三维空间(k=3)中,第一层选择x维度,第二层选择y维度,第三层选择z维度,第四层再回到x维度,以此类推。
2.选择分割点:
    - 在选定的维度上,通过找到数据在该维度上的中位数,将数据空间划分为两个部分。中位数的选择保证了数据点被尽量均匀地分割开。
3.递归构建:
    - 将数据空间划分后,左子树包含小于或等于中位数的数据点,右子树包含大于中位数的数据点。递归地对每个子空间构建KD树,直到满足终止条件(如节点数据点数目小于某个阈值)。

1.1.2 树的构建示例

假设我们有一组二维点 (x, y),要将其构建为一棵KD树:

  • 第一层(根节点):选择x维度进行划分,找到x维度的中位数,作为根节点的分割点。左子树包含所有x值小于或等于中位数的点,右子树包含所有x值大于中位数的点。
  • 第二层:对左子树和右子树,选择y维度进行划分,找到y维度的中位数,分别作为左右子树的分割点。继续递归划分。
  • 第三层:再回到x维度进行划分,依次类推,直到不能再划分为止。

1.2实现步骤

        KD树的搜索过程通常是以递归的方式进行的,主要分为最近邻搜索和范围搜索两种常见的操作。
1.最近邻搜索:
    - 从根节点开始,沿树向下递归搜索,比较查询点与节点的分割点,决定搜索左子树还是右子树。
    - 在找到一个叶节点后,记录下该叶节点的点,并计算它与查询点的距离。
    - 回溯检查其他可能包含更近点的子树。
2.范围搜索:
    - 同样从根节点开始,根据分割维度的值,判断是否需要搜索左右子树。
    - 判断当前节点的分割点是否在查询范围内,如果是,则将其纳入结果集。
    - 继续递归地检查子树,直到所有符合条件的节点都被搜索到。
通过这种分割和搜索方法,KD树能够有效地减少高维空间中的搜索范围,从而加快查询速度。

1.3应用场景

KD树广泛应用于以下场景:

  1. 最近邻搜索:用于查找点云中距离某点最近的邻居点,常用于点云配准。
  2. k近邻搜索:用于查找点云中某点的k个最近邻点,适用于点云平滑、特征计算等。
  3. 范围搜索:用于查找在一定范围内的所有邻居点,适用于聚类、边界检测等。

二、代码实现

2.1关键函数

2.1.1KD树构建与查询:

  • pcl::KdTreeFLANN:用于创建KD树对象,支持最近邻、k近邻、范围搜索。
  • setInputCloud:将点云数据输入到KD树中进行构建。
  • nearestKSearch:执行k近邻搜索,找到指定点的k个最近邻点。
  • radiusSearch:执行范围搜索,找到指定点在给定半径内的所有邻居点。

2.1.2 k近邻搜索

int pcl::KdTreeFLANN< PointT, Dist >::nearestKSearch  ( const PointT &  point,  unsigned int  k,  Indices &  k_indices,  std::vector< float > &  k_sqr_distances  )  const 

 2.1.3半径搜索

int pcl::KdTreeFLANN< PointT, Dist >::radiusSearch  ( const PointT &  point,  double  radius,  Indices &  k_indices,  std::vector< float > &  k_sqr_distances,  unsigned int  max_nn = 0  )  const 

2.2完整代码

#include <pcl/io/pcd_io.h>  // 用于加载PCD文件
#include <pcl/point_types.h>  // PCL点类型定义
#include <pcl/kdtree/kdtree_flann.h>  // PCL中的KD树实现
#include <pcl/visualization/pcl_visualizer.h>  // 用于可视化点云
#include <vector>
#include <iostream>// 将搜索到的结果渲染为红色,并在可视化窗口中显示
void visualizeResult(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, const std::vector<int>& indices)
{// 创建一个带颜色信息的点云对象,用于存储带有颜色信息的点云pcl::PointCloud<pcl::PointXYZRGB>::Ptr coloredCloud(new pcl::PointCloud<pcl::PointXYZRGB>);// 遍历原始点云中的每个点for (size_t i = 0; i < cloud->points.size(); ++i){// 创建一个带有RGB颜色信息的点对象pcl::PointXYZRGB point;point.x = cloud->points[i].x;  // 复制点的X坐标point.y = cloud->points[i].y;  // 复制点的Y坐标point.z = cloud->points[i].z;  // 复制点的Z坐标// 判断当前点是否在搜索到的索引列表中if (std::find(indices.begin(), indices.end(), i) != indices.end()){// 如果是搜索到的点,将颜色设置为红色point.r = 255;point.g = 0;point.b = 0;}else{// 如果不是搜索到的点,将颜色设置为白色point.r = 255;point.g = 255;point.b = 255;}// 将带颜色的点添加到新的点云对象中coloredCloud->points.push_back(point);}// 设置点云的基本属性coloredCloud->width = coloredCloud->points.size();  // 设置点云宽度为点的数量coloredCloud->height = 1;  // 设置点云高度为1(无序点云)coloredCloud->is_dense = true;  // 设置点云为稠密点云// 创建一个PCLVisualizer对象,用于显示带颜色的点云pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));viewer->setBackgroundColor(0, 0, 0);  // 设置背景颜色为黑色viewer->addPointCloud<pcl::PointXYZRGB>(coloredCloud, "result");  // 将带颜色的点云添加到可视化窗口viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "result");  // 设置点的大小// 启动可视化主循环,保持窗口打开直到用户关闭while (!viewer->wasStopped()){viewer->spinOnce(100);  // 刷新窗口,间隔100ms}
}int main(int argc, char** argv)
{// 1. 创建PointCloud对象,用于存储点云数据pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);// 2. 读取点云数据,加载PCD文件if (pcl::io::loadPCDFile("bunny.pcd", *cloud) == -1){PCL_ERROR("Couldn't read file input.pcd \n");  // 如果文件加载失败,输出错误信息return -1;  // 返回错误代码并退出程序}// 3. 创建KD树对象,并将点云数据输入到KD树中进行构建pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;  // 创建KD树对象kdtree.setInputCloud(cloud);  // 将点云数据设置为KD树的输入// 4. 定义一个查询点,用于进行搜索pcl::PointXYZ searchPoint(-0.0208042, 0.125974, 0.0209606);  // 查询点的坐标// 5. k近邻搜索(K Nearest Neighbor Search)int k = 1000;  // 设置k值,表示要查找的最近邻点的数量std::vector<int> pointIdxNKNSearch(k);  // 用于存储最近邻点的索引std::vector<float> pointNKNSquaredDistance(k);  // 用于存储最近邻点的距离平方值std::cout << "K nearest neighbor search at (" << searchPoint.x<< " " << searchPoint.y<< " " << searchPoint.z << ") with K=" << k << std::endl;// 使用KD树进行k近邻搜索,找到距离查询点最近的k个点if (kdtree.nearestKSearch(searchPoint, k, pointIdxNKNSearch, pointNKNSquaredDistance) > 0){// 如果搜索成功,将搜索结果进行可视化visualizeResult(cloud, pointIdxNKNSearch);}// 6. 半径搜索(Radius Search)float radius = 0.03;  // 设置搜索半径std::vector<int> pointIdxRadiusSearch;  // 用于存储在指定半径范围内的点的索引std::vector<float> pointRadiusSquaredDistance;  // 用于存储在指定半径范围内的点的距离平方值std::cout << "Neighbors within radius " << radius << " around point ("<< searchPoint.x << " " << searchPoint.y << " " << searchPoint.z << ")" << std::endl;// 使用KD树进行半径搜索,找到查询点在给定半径范围内的所有点if (kdtree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0){// 如果搜索成功,将搜索结果进行可视化visualizeResult(cloud, pointIdxRadiusSearch);}// 7. 混合搜索(k近邻搜索 + 半径搜索)std::vector<int> hybridSearchIndices;  // 存储混合搜索结果的索引for (size_t i = 0; i < pointIdxNKNSearch.size(); ++i){// 判断k近邻搜索的点是否也在指定半径范围内if (pointNKNSquaredDistance[i] <= radius * radius){hybridSearchIndices.push_back(pointIdxNKNSearch[i]);  // 如果满足条件,将索引添加到结果中}}std::cout << "Hybrid search results within K=" << k << " and radius " << radius << std::endl;// 如果混合搜索结果不为空,将结果进行可视化if (!hybridSearchIndices.empty()){visualizeResult(cloud, hybridSearchIndices);}return 0;
}

三、实现效果

3.1处理后点云

3.2数据显示

K nearest neighbor search at (-0.0208042 0.125974 0.0209606) with K=1000
Neighbors within radius 0.03 around point (-0.0208042 0.125974 0.0209606)
Hybrid search results within K=1000 and radius 0.03

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1540307.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

neo4j导入csv数据

neo4j数据可视化实践 手动输入数据 - 官方democsv数据导入准备数据数据处理导入步骤① 导入疾病表格② 导入药物表格③导入疾病-药物关系表格 爬虫的csv文件 手动输入数据 - 官方demo 点击之后&#xff0c;按照左边10张图中的代码&#xff0c;复制粘贴熟悉语法 效果如下 csv数据…

(十六)Ubuntu 20.04 下搭建PX4+MATLAB 仿真环境(HITL)

在文章&#xff08;十五&#xff09;Ubuntu 20.04 下搭建PX4MATLAB 仿真环境我们学习了如何配置仿真环境&#xff0c;在本节&#xff0c;主要进行HITL的仿真环境搭建。 根据&#xff08;十五&#xff09;Ubuntu 20.04 下搭建PX4MATLAB 仿真环境完成配置到如下界面&#xff1a;…

STM32F1+HAL库+FreeTOTS学习11——延时函数API

STM32F1HAL库FreeTOTS学习11——延时函数API 延时函数API1. vTaskDelay()2. vTaskDelayUntil()3. xTaskDelayUntil()相对延时和绝对延时的区别4. xTaskAbortDelay() 上一期&#xff0c;我们学习了任务相关API使用&#xff0c;这一期我们开始学习FreeRTOS延时函数的API使用 延时…

MySQL--导入SQL文件(命令行导入)

MySQL--导入SQL文件 一、前言二、导入SQL文件 一、前言 用可视化编辑工具编写&#xff0c;并且在控制台输入命令行在MySQL中导入SQL文件。 在导入SQL文件之前查看了目前存在的数据库 **目标&#xff1a;**在可视化编辑工具(这里以word文档为例&#xff09;中编写SQL语句&…

【算法竞赛】栈

栈的特点是"先进后出"。 栈在生活中的原型有:坐电梯,先进电梯的被挤在最里面,只能最后出来&#xff1b;一管泡腾片,最先放进管子的药片位于最底层&#xff0c;最后被拿出来。 栈只有唯一的出入口,从这个口进入,也从这个口弹出,这是它与队列最大的区别。 队列有一个入…

【动态规划】最大正方形

最大正方形&#xff08;难度&#xff1a;中等&#xff09; 该题对应力扣网址 思路 min_valuemin({dp[i-1][j-1],dp[i-1][j],dp[i][j-1]}) dp[i][j]min_value 关键点是正方形的右下角(n>1时)&#xff0c;通过画图&#xff0c;可以看出&#xff0c;在基础正方形22中&#x…

unordered_map/set(底层实现)——C++

目录 前言&#xff1a; 1.开散列 1. 开散列概念 2. 开散列实现 2.1哈希链表结构体的定义 2.2哈希表类即私有成员变量 2.3哈希表的初始化 2.4迭代器的实现 1.迭代器的结构 2.构造 3.* 4.-> 5. 6.&#xff01; 2.5begin和end 2.6插入 2.7Find查找 2.8erase删除 3.unordered_ma…

在vue中:style 的几种使用方式

在日常开发中:style的使用也是比较常见的&#xff1a; 亲测有效 1.最通用的写法 <p :style"{fontFamily:arr.conFontFamily,color:arr.conFontColor,backgroundColor:arr.conBgColor}">{{con.title}}</p> 2.三元表达式 <a :style"{height:…

Gitlab学习(006 gitlab操作)

尚硅谷2024最新Git企业实战教程&#xff0c;全方位学习git与gitlab 总时长 5:42:00 共40P 此文章包含第21p-第24p的内容 文章目录 git登录修改root密码 设置修改语言取消相对时间勾选 团队管理创建用户创建一个管理员登录管理员账号创建一个普通用户登录普通用户账号 群组管理…

第6天:趋势轮动策略开发(年化18.8%,大小盘轮动加择时)

原创内容第655篇&#xff0c;专注量化投资、个人成长与财富自由。 轮动策略是一种投资策略&#xff0c;它涉及在不同的资产类别、行业或市场之间进行切换&#xff0c;以捕捉市场机会并优化投资组合的表现。 这种策略的核心在于识别并利用不同资产或市场的相对强弱&#xff0c…

自然语言处理-基于注意力机制的文本匹配

背景&#xff1a; 任务三&#xff1a;基于注意力机制的文本匹配 输入两个句子判断&#xff0c;判断它们之间的关系。参考ESIM&#xff08;可以只用LSTM&#xff0c;忽略Tree-LSTM&#xff09;&#xff0c;用双向的注意力机制实现。 参考 《神经网络与深度学习》 第7章 Reaso…

clousx6整点报时指令怎么写?

&#x1f3c6;本文收录于《全栈Bug调优(实战版)》专栏&#xff0c;主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&am…

大模型的实践应用30-大模型训练和推理中分布式核心技术的应用

大家好,我是微学AI,今天给大家介绍一下大模型的实践应用30-大模型训练和推理中分布式核心技术的应用。本文深入探讨了大模型训练和推理中分布式核心技术的应用。首先介绍了项目背景,阐述了大模型发展对高效技术的需求。接着详细讲解了分布式技术的原理,包括数据并行、模型并…

SAP-MM-变式的设置

1、报表变式 业务需求: 业务人员查询报表时有些值是需要经常输入的,能不能设置成默认值?能不能设置成每次进入报表不选择变式直接是默认值? 解决措施: 1、事物码:MB51 以MB51物料凭证查询为例,其他报表自行举一反三 2、设置变式 首先进入MB51入下图 上图是没有选…

ros2编译RTSP驱动打开网络摄像头

按照这个链接里面的方法即可实现如下效果。

consul服务注册发现与配置中心

目录 1 consul安装与运行 1.1 下载方式 1.2 安装 1.3 启动 1.4 访问方式 2 consul 实现服务注册与发现 2.1 引入 2.2 服务注册 2.3 服务发现 3 consul配置中心 3.1 基础配置 Eureka已经停止更新了&#xff0c;consul是独立且和微服务功能解耦的注册中心&#xff0c;…

Tomcat 后台弱⼝令部署war包

漏洞原理 在tomcat8环境下默认进⼊后台的密码为 tomcat/tomcat &#xff0c;未修改造成未授权即可进⼊后台&#xff0c;或者管理员把密码设置成弱⼝令。 影响版本 全版本(前提是⼈家存在弱⼝令) 环境搭建 8 cd vulhub-master/tomcat/tomcat8 docker-compose up -d 漏洞复…

Python基于flask框架的智能停车场车位系统 数据可视化分析系统fyfc81

目录 技术栈和环境说明解决的思路具体实现截图系统设计python语言django框架介绍flask框架介绍性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示技术路线操作可行性详细视频演示源码获取 技术栈和环境说明 结合用户的使用需求&…

引领长期投资新篇章:价值增长与财务安全的双重保障

随着全球金融市场的不断演变&#xff0c;长期投资策略因其稳健性和对价值增长的显著推动作用而日益受到投资者的重视。在这一背景下&#xff0c;Zeal Digital Shares&#xff08;ZDS&#xff09;项目以其创新的数字股票产品&#xff0c;为全球投资者提供了一个全新的长期投资平…

flutter遇到问题及解决方案

目录 1、easy_refresh相关问题 2、 父子作用域关联问题 3. 刘海屏底部安全距离 4. 了解保证金弹窗 iOS端闪退 &#xff08;待优化&#xff09; 5. loading无法消失 6. dialog蒙版问题 7. 倒计时优化 8. scrollController.offset报错 9. 断点不走 10.我的出价报红 11…