【点云处理技术之PCL】Octree

2023-10-25 09:20
文章标签 技术 处理 pcl 点云 octree

本文主要是介绍【点云处理技术之PCL】Octree,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 八叉树简介

八叉树是一种用于描述三维空间的树状数据结构,八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,将八个子节点所表示的体积元素加在一起就等于父节点的体积。

在这里插入图片描述
在这里插入图片描述

2. 点云的压缩

点云信息一般比较包含了丰富的信息而且点云数量也是比较多,这就需要我们对点云数据进行压缩。pcl中提供了点云压缩功能,而且还可以通过八叉树将两个不同的点云进行合并。

点云压缩的代码举例如下:

#include <pcl/point_cloud.h>                         // 点云类型
#include <pcl/point_types.h>                          //点数据类型
#include <pcl/io/openni_grabber.h>                    //点云获取接口类
#include <pcl/visualization/cloud_viewer.h>            //点云可视化类#include <pcl/compression/octree_pointcloud_compression.h>   //点云压缩类#include <stdio.h>
#include <sstream>
#include <stdlib.h>#ifdef WIN32
# define sleep(x) Sleep((x)*1000)
#endifclass SimpleOpenNIViewer
{
public:SimpleOpenNIViewer () :viewer (" Point Cloud Compression Example"){}
/************************************************************************************************在OpenNIGrabber采集循环执行的回调函数cloud_cb_中,首先把获取的点云压缩到stringstream缓冲区,下一步就是解压缩,它对压缩了的二进制数据进行解码,存储在新的点云中解码了点云被发送到点云可视化对象中进行实时可视化
*************************************************************************************************/void  cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr &cloud){if (!viewer.wasStopped ()){// 存储压缩点云的字节流对象// stringstream to store compressed point cloudstd::stringstream compressedData;// 存储输出点云// output pointcloudpcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloudOut (new pcl::PointCloud<pcl::PointXYZRGBA> ());// 压缩点云// compress point cloudPointCloudEncoder->encodePointCloud (cloud, compressedData);// 解压缩点云// decompress point cloudPointCloudDecoder->decodePointCloud (compressedData, cloudOut);// 可视化解压缩的点云// show decompressed point cloudviewer.showCloud (cloudOut);}}
/**************************************************************************************************************在函数中创建PointCloudCompression类的对象来编码和解码,这些对象把压缩配置文件作为配置压缩算法的参数所提供的压缩配置文件为OpenNI兼容设备采集到的点云预先确定的通用参数集,本例中使用MED_RES_ONLINE_COMPRESSION_WITH_COLOR配置参数集,用于快速在线的压缩,压缩配置方法可以在文件/io/include/pcl/compression/compression_profiles.h中找到,在PointCloudCompression构造函数中使用MANUAL——CONFIGURATION属性就可以手动的配置压缩算法的全部参数
******************************************************************************************************************/void run (){bool showStatistics = true;  //设置在标准设备上输出打印出压缩结果信息// 压缩选项详情在: /io/include/pcl/compression/compression_profiles.h// for a full list of profiles see: /io/include/pcl/compression/compression_profiles.hpcl::io::compression_Profiles_e compressionProfile = pcl::io::MED_RES_ONLINE_COMPRESSION_WITH_COLOR;// 初始化压缩和解压缩对象  其中压缩对象需要设定压缩参数选项,解压缩按照数据源自行判断// instantiate point cloud compression for encoding and decodingPointCloudEncoder = new pcl::io::OctreePointCloudCompression<pcl::PointXYZRGBA> (compressionProfile, showStatistics);PointCloudDecoder = new pcl::io::OctreePointCloudCompression<pcl::PointXYZRGBA> ();/***********************************************************************************************************下面的代码为OpenNI兼容设备实例化一个新的采样器,并且启动循环回调接口,每从设备获取一帧数据就回调函数一次,,这里的回调函数就是实现数据压缩和可视化解压缩结果。************************************************************************************************************///创建从OpenNI获取点云的抓取对象// create a new grabber for OpenNI devicespcl::Grabber* interface = new pcl::OpenNIGrabber ();// 建立回调函数// make callback function from member functionboost::function<void(const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&)> f = boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);//建立回调函数和回调信息的绑定// connect callback function for desired signal. In this case its a point cloud with color valuesboost::signals2::connection c = interface->registerCallback (f);// 开始接受点云的数据流// start receiving point cloudsinterface->start ();while (!viewer.wasStopped ()){sleep (1);}interface->stop ();// 删除压缩与解压缩的实例delete (PointCloudEncoder);delete (PointCloudDecoder);}pcl::visualization::CloudViewer viewer;pcl::io::OctreePointCloudCompression<pcl::PointXYZRGBA>* PointCloudEncoder;pcl::io::OctreePointCloudCompression<pcl::PointXYZRGBA>* PointCloudDecoder;
};int main (int argc, char **argv)
{SimpleOpenNIViewer v;  //创建一个新的SimpleOpenNIViewer  实例并调用他的run方法v.run ();return (0);
}

3. 八叉树的搜索

octree是一种用于管理稀疏3D数据的树形数据结构,每个内部节点都正好有八个子节点,pcl中的octree搜索有三种方式:

  • 实现“体素内*邻搜索(Neighbors within VOxel Search)”
  • “K*邻搜索(K Nearest Neighbor Search)”
  • “半径内*邻搜索”(Neighbors within Radius Search)

代码示例如下:

#include <pcl/point_cloud.h>
#include <pcl/octree/octree_search.h>#include <iostream>
#include <vector>
#include <ctime>int main (int argc, char** argv)
{srand ((unsigned int) time (NULL));pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);// Generate pointcloud data//生成点云cloud->width = 1000;cloud->height = 1;cloud->points.resize (cloud->width * cloud->height);for (std::size_t i = 0; i < cloud->size (); ++i){(*cloud)[i].x = 1024.0f * rand () / (RAND_MAX + 1.0f);(*cloud)[i].y = 1024.0f * rand () / (RAND_MAX + 1.0f);(*cloud)[i].z = 1024.0f * rand () / (RAND_MAX + 1.0f);}float resolution = 128.0f;//设置octree体素分辨率pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree (resolution);//初始化八叉树octree.setInputCloud (cloud);//输入点云octree.addPointsFromInputCloud ();//构建八叉树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);// Neighbors within voxel search
/***********************体素内邻搜索********************************/std::vector<int> pointIdxVec;if (octree.voxelSearch (searchPoint, pointIdxVec)){std::cout << "Neighbors within voxel search at (" << searchPoint.x << " " << searchPoint.y << " " << searchPoint.z << ")" << std::endl;for (std::size_t i = 0; i < pointIdxVec.size (); ++i)std::cout << "    " << (*cloud)[pointIdxVec[i]].x << " " << (*cloud)[pointIdxVec[i]].y << " " << (*cloud)[pointIdxVec[i]].z << std::endl;}// K nearest neighbor search
/***********************k近邻搜索********************************/int K = 10;std::vector<int> pointIdxNKNSearch;std::vector<float> pointNKNSquaredDistance;std::cout << "K nearest neighbor search at (" << searchPoint.x << " " << searchPoint.y << " " << searchPoint.z<< ") with K=" << K << std::endl;if (octree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0){for (std::size_t i = 0; i < pointIdxNKNSearch.size (); ++i)std::cout << "    "  <<   (*cloud)[ pointIdxNKNSearch[i] ].x << " " << (*cloud)[ pointIdxNKNSearch[i] ].y << " " << (*cloud)[ pointIdxNKNSearch[i] ].z << " (squared distance: " << pointNKNSquaredDistance[i] << ")" << std::endl;}// Neighbors within radius search/***********************半径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 (octree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0){for (std::size_t i = 0; i < pointIdxRadiusSearch.size (); ++i)std::cout << "    "  <<   (*cloud)[ pointIdxRadiusSearch[i] ].x << " " << (*cloud)[ pointIdxRadiusSearch[i] ].y << " " << (*cloud)[ pointIdxRadiusSearch[i] ].z << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;}
}

4. 无序点云数据集的空间变化检测

除了搜索功能,pcl中的八叉树还有一种功能,就是提取或检测两个点云数据集中,点云的非共同点云数据,也就是检测两个点云数据的变化部分。octree使用“双缓冲”技术实现这一功能。

代码示例:

#include <pcl/point_cloud.h>
#include <pcl/octree/octree_pointcloud_changedetector.h>#include <iostream>
#include <vector>
#include <ctime>int main (int argc, char** argv)
{srand ((unsigned int) time (NULL));// Octree resolution - side length of octree voxels//体素的大小float resolution = 32.0f;// Instantiate octree-based point cloud change detection classpcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZ> octree (resolution);pcl::PointCloud<pcl::PointXYZ>::Ptr cloudA (new pcl::PointCloud<pcl::PointXYZ> );// Generate pointcloud data for cloudA//生成点云cloudAcloudA->width = 128;cloudA->height = 1;cloudA->points.resize (cloudA->width * cloudA->height);for (std::size_t i = 0; i < cloudA->size (); ++i){(*cloudA)[i].x = 64.0f * rand () / (RAND_MAX + 1.0f);(*cloudA)[i].y = 64.0f * rand () / (RAND_MAX + 1.0f);(*cloudA)[i].z = 64.0f * rand () / (RAND_MAX + 1.0f);}//输出cloudA// std::cout<<"cloudA:"<<std::endl;// for (const auto& point: *cloudA)//   std::cerr << "    " << point.x << " "//                       << point.y << " "//                       << point.z << std::endl;// Add points from cloudA to octreeoctree.setInputCloud (cloudA);octree.addPointsFromInputCloud ();// Switch octree buffers: This resets octree but keeps previous tree structure in memory.octree.switchBuffers ();//双缓冲pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB (new pcl::PointCloud<pcl::PointXYZ> );// Generate pointcloud data for cloudB //生成点云cloudBcloudB->width = 128;cloudB->height = 1;cloudB->points.resize (cloudB->width * cloudB->height);for (std::size_t i = 0; i < cloudB->size (); ++i){(*cloudB)[i].x = 64.0f * rand () / (RAND_MAX + 1.0f);(*cloudB)[i].y = 64.0f * rand () / (RAND_MAX + 1.0f);(*cloudB)[i].z = 64.0f * rand () / (RAND_MAX + 1.0f);}//输出cloudB// std::cout<<"cloudB:"<<std::endl;// for (const auto& point: *cloudA)//   std::cerr << "    " << point.x << " "//                       << point.y << " "//                       << point.z << std::endl;// Add points from cloudB to octreeoctree.setInputCloud (cloudB);octree.addPointsFromInputCloud ();std::vector<int> newPointIdxVector;//索引// Get vector of point indices from octree voxels which did not exist in previous buffer// 获取前一cloudA对应八叉树在cloudB对应在八叉树中没有的点集octree.getPointIndicesFromNewVoxels (newPointIdxVector);// Output points//输出cloudB中,cloudA没有的点云std::cout << "Output from getPointIndicesFromNewVoxels:" << std::endl;for (std::size_t i = 0; i < newPointIdxVector.size (); ++i)std::cout << i << "# Index:" << newPointIdxVector[i]<< "  Point:" << (*cloudB)[newPointIdxVector[i]].x << " "<< (*cloudB)[newPointIdxVector[i]].y << " "<< (*cloudB)[newPointIdxVector[i]].z << std::endl;}

这篇关于【点云处理技术之PCL】Octree的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/281568

相关文章

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

SpringBoot操作spark处理hdfs文件的操作方法

《SpringBoot操作spark处理hdfs文件的操作方法》本文介绍了如何使用SpringBoot操作Spark处理HDFS文件,包括导入依赖、配置Spark信息、编写Controller和Ser... 目录SpringBoot操作spark处理hdfs文件1、导入依赖2、配置spark信息3、cont

MyBatis延迟加载的处理方案

《MyBatis延迟加载的处理方案》MyBatis支持延迟加载(LazyLoading),允许在需要数据时才从数据库加载,而不是在查询结果第一次返回时就立即加载所有数据,延迟加载的核心思想是,将关联对... 目录MyBATis如何处理延迟加载?延迟加载的原理1. 开启延迟加载2. 延迟加载的配置2.1 使用

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

Python中处理NaN值的技巧分享

《Python中处理NaN值的技巧分享》在数据科学和数据分析领域,NaN(NotaNumber)是一个常见的概念,它表示一个缺失或未定义的数值,在Python中,尤其是在使用pandas库处理数据时,... 目录NaN 值的来源和影响使用 pandas 的 isna()和 isnull()函数直接比较 Na

详解Python中通用工具类与异常处理

《详解Python中通用工具类与异常处理》在Python开发中,编写可重用的工具类和通用的异常处理机制是提高代码质量和开发效率的关键,本文将介绍如何将特定的异常类改写为更通用的ValidationEx... 目录1. 通用异常类:ValidationException2. 通用工具类:Utils3. 示例文

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

金融业开源技术 术语

金融业开源技术  术语 1  范围 本文件界定了金融业开源技术的常用术语。 本文件适用于金融业中涉及开源技术的相关标准及规范性文件制定和信息沟通等活动。