【点云处理技术之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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/QLeelq/article/details/117218327
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/281568

相关文章

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

Python实现自动化接收与处理手机验证码

《Python实现自动化接收与处理手机验证码》在移动互联网时代,短信验证码已成为身份验证、账号注册等环节的重要安全手段,本文将介绍如何利用Python实现验证码的自动接收,识别与转发,需要的可以参考下... 目录引言一、准备工作1.1 硬件与软件需求1.2 环境配置二、核心功能实现2.1 短信监听与获取2.

Python使用date模块进行日期处理的终极指南

《Python使用date模块进行日期处理的终极指南》在处理与时间相关的数据时,Python的date模块是开发者最趁手的工具之一,本文将用通俗的语言,结合真实案例,带您掌握date模块的六大核心功能... 目录引言一、date模块的核心功能1.1 日期表示1.2 日期计算1.3 日期比较二、六大常用方法详

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件