PCL学习八叉树

建立空间索引在点云数据处理中有着广泛的应用,常见的空间索引一般 是自顶而下逐级划分空间的各种空间索引结构,比较有代表性的包括BSP树,KD树,KDB树,R树,四叉树,八叉树等索引结构,而这些结构中,KD树和八叉树使用比较广泛

八叉树(Octree)是一种用于描述三维空间的数据结构八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,这八个子节点所表示的体积元素加在一起就等于父节点的体积。一般中心点作为节点的分叉中心。

 

百度百科释义八叉树(Octree)的定义是:若不为空树的话,树中任一节点的子节点恰好只会有八个,或零个,也就是子节点不会有0与8以外的数目。那么,这要用来做什么?想象一个立方体, 我们最少可以切成多少个相同等分的小立方体?答案就是8个。再想象我们有一个房间,房间里某个角落藏着一枚金币,我们想很快的把金币找出来,聪明的你会怎 么做?我们可以把房间当成一个立方体,先切成八个小立方体,然后排除掉没有放任何东西的小立方体,再把有可能藏金币的小立方体继续切八等份….如此下去, 平均在Log8(房间内的所有物品数)的时间内就可找到金币。因此,八叉树就是用在3D空间中的场景管理,可以很快地知道物体在3D场景中的位置,或侦测 与其它物体是否有碰撞以及是否在可视范围内。

实现八叉树的原理 

  (1). 设定最大递归深度。

  (2). 找出场景的最大尺寸,并以此尺寸建立第一个立方体。

  (3). 依序将单位元元素丢入能被包含且没有子节点的立方体。

  (4). 若没达到最大递归深度,就进行细分八等份,再将该立方体所装的单位元元素全部分担给八个子立方体。

  (5). 若发现子立方体所分配到的单位元元素数量不为零且跟父立方体是一样的,则该子立方体停止细分,因为跟据空间分割理论,细分的空间所得到的分配必定较少,若是一样数目,则再怎么切数目还是一样,会造成无穷切割的情形。

  (6). 重复3,直到达到最大递归深度。

八叉树的逻辑结构如下:

假设要表示的形体V可以放在一个充分大的正方体C内,C的边长为2n,形体V=C,它的八叉树可以用以下的递归方法来定义:八 叉树的每个节点与C的一个子立方体对应,

树根与C本身相对应,如果V=C,那么V的八叉树仅有树根,如果V≠C,则将C等分为八个子立方体,每个子立方体 与树根的一个子节点相对应。只要某个子立方体不是完

全空白或完全为V所占据,就要被八等分,从而对应的节点也就有了八个子节点。这样的递 归判断、分割一直要进行到节点所对应的立方体或是完全空白,或是完全为V占

据,或是其大小已是预先定义的体素大小,并且对它与V之交作一定的“舍入”,使 体素或认为是空白的,或认为是V占据的。

                              
                                                                                               

PCL中Octree模块及类介绍

pcl::octree::Octree2BufBase< LeafContainerT, BranchContainerT >    实现了同时存储管理两个八叉树与内存中,可以十分高效的实现八叉树的建立管理等操作,并且节点实现对临近树节点的结构的探测,对应到空间点云,其就可以对空间曲面的动态变化进行探测,在进行空间动态变化探测中非常有用

Public Types

typedef Octree2BufBase< LeafContainerT, BranchContainerT > OctreeT
typedef BufferedBranchNode< BranchContainerT > BranchNode
typedef OctreeLeafNode< LeafContainerT > LeafNode
typedef BranchContainerT BranchContainer
typedef LeafContainerT LeafContainer
typedef OctreeDepthFirstIterator< OctreeTIterator
typedef const OctreeDepthFirstIterator< OctreeTConstIterator
typedef OctreeLeafNodeIterator< OctreeTLeafNodeIterator
typedef const OctreeLeafNodeIterator< OctreeTConstLeafNodeIterator
typedef OctreeDepthFirstIterator< OctreeTDepthFirstIterator
typedef const OctreeDepthFirstIterator< OctreeTConstDepthFirstIterator
typedef OctreeBreadthFirstIterator< OctreeTBreadthFirstIterator
typedef const OctreeBreadthFirstIterator< OctreeTConstBreadthFirstIterator

 

Public Member Functions

void setMaxVoxelIndex (unsigned int max_voxel_index_arg)
 Set the maximum amount of voxels per dimension. 设置在各个维度的最大的体素个数
void setTreeDepth (unsigned int depth_arg)
 Set the maximum depth of the octree. 设置八叉树的深度,需要在初始化八叉树时设置
unsigned int getTreeDepth () const
 Get the maximum depth of the octree  获得八叉树的深度
LeafContainerT * createLeaf (unsigned int idx_x_arg, unsigned int idx_y_arg, unsigned int idx_z_arg)
 Create new leaf node at (idx_x_arg, idx_y_arg, idx_z_arg). 创建叶节点
LeafContainerT * findLeaf (unsigned int idx_x_arg, unsigned int idx_y_arg, unsigned int idx_z_arg)
 Find leaf node at (idx_x_arg, idx_y_arg, idx_z_arg). 找出页节点
bool existLeaf (unsigned int idx_x_arg, unsigned int idx_y_arg, unsigned int idx_z_arg) const
 Check for the existence of leaf node at (idx_x_arg, idx_y_arg, idx_z_arg). 判断在(idx_x_arg, idx_y_arg, idx_z_arg)对应的叶子节点是否存在
void removeLeaf (unsigned int idx_x_arg, unsigned int idx_y_arg, unsigned int idx_z_arg)
 Remove leaf node at (idx_x_arg, idx_y_arg, idx_z_arg). 移除在(。。。)的节点
std::size_t getLeafCount () const
 Return the amount of existing leafs in the octree.返回八叉树叶子的个数
std::size_t getBranchCount () const 
 Return the amount of existing branches in the octree. 返回八叉树分支的个数
void deleteTree ()
 Delete the octree structure and its leaf nodes. 删除八叉树结构包括节点
void deletePreviousBuffer ()
 Delete octree structure of previous buffer. 删除另一个缓存区对应的八叉树的结构及其字节点
void deleteCurrentBuffer ()
 Delete the octree structure in the current buffer删除当前缓存区对应的八叉树的结构及其字节点
void switchBuffers ()
 Switch buffers and reset current octree structure. 交换缓存区中对应的八叉树的结构和其叶子节点
void serializeTree (std::vector< char > &binary_tree_out_arg, bool do_XOR_encoding_arg=false)
 Serialize octree into a binary output vector describing its branch node structure.
void serializeTree (std::vector< char > &binary_tree_out_arg, std::vector< LeafContainerT * > &leaf_container_vector_arg, bool do_XOR_encoding_arg=false)
 Serialize octree into a binary output vector describing its branch node structure and and push all DataT elements stored in the octree to a vector.串行化输出八叉树结构
void serializeLeafs (std::vector< LeafContainerT * > &leaf_container_vector_arg)
 Outputs a vector of all DataT elements that are stored within the octree leaf nodes.
void serializeNewLeafs (std::vector< LeafContainerT * > &leaf_container_vector_arg)
 Outputs a vector of all DataT elements from leaf nodes, that do not exist in the previous octree buffer
void deserializeTree (std::vector< char > &binary_tree_in_arg, bool do_XOR_decoding_arg=false)
 Deserialize a binary octree description vector and create a corresponding octree structure.
void deserializeTree (std::vector< char > &binary_tree_in_arg, std::vector< LeafContainerT * > &leaf_container_vector_arg, bool do_XOR_decoding_arg=false)
 Deserialize a binary octree description and create a corresponding octree structure.

 更多详细查看  docs.pointclouds.org/trunk/classpcl_1_1octree_1_1_octree2_buf_base.html#aeea7ecfd6ebe82e93d3c7bb869355502

应用实例

点云由海量的数据集组成,这些数据集通过距离 颜色  法线  等附加信息来描述空间的三维点,此外,点云还能易非常高的速度被创建出来,因此需要占用相当大的存储资源,一旦点云需要存储或者通过速率受限制的通信信道进行传输,提供针对这种数据的压缩方法就变得十分有用,PCL 提供了点云的压缩功能,它允许编码压缩所有类型的点云,

点云压缩示意图:

                                                             octreeCompression

新建工程ch3_2,新建文件 point_cloud_compression.cpp

#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 ()){// 存储压缩点云的字节流对象
      std::stringstream compressedData;// 存储输出点云pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloudOut (new pcl::PointCloud<pcl::PointXYZRGBA> ());// 压缩点云PointCloudEncoder->encodePointCloud (cloud, compressedData);// 解压缩点云PointCloudDecoder->decodePointCloud (compressedData, cloudOut);// 可视化解压缩的点云
      viewer.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.hpcl::io::compression_Profiles_e compressionProfile = pcl::io::MED_RES_ONLINE_COMPRESSION_WITH_COLOR;// 初始化压缩和解压缩对象  其中压缩对象需要设定压缩参数选项,解压缩按照数据源自行判断PointCloudEncoder = new pcl::io::OctreePointCloudCompression<pcl::PointXYZRGBA> (compressionProfile, showStatistics);PointCloudDecoder = new pcl::io::OctreePointCloudCompression<pcl::PointXYZRGBA> ();/***********************************************************************************************************下面的代码为OpenNI兼容设备实例化一个新的采样器,并且启动循环回调接口,每从设备获取一帧数据就回调函数一次,,这里的回调函数就是实现数据压缩和可视化解压缩结果。************************************************************************************************************///创建从OpenNI获取点云的抓取对象pcl::Grabber* interface = new pcl::OpenNIGrabber ();// 建立回调函数boost::function<void(const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&)> f = boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);//建立回调函数和回调信息的绑定boost::signals2::connection c = interface->registerCallback (f);// 开始接受点云的数据流interface->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);
}

 编译后运行的结果如下:

图示为带有RGB纹理信息的实时可视化结果,缩放可视化结果看到经过压缩后点云进行了重采样,纹理信息有所丢失,但数据量有所减小,在实际应用中需要折中取舍

同时在压缩和解压缩的过程中  因为设置compressedData为true所以在标准输出上打印处压缩率帧数等信息:

 

压缩配置文件:压缩配置文件为PCL点云编码器定义了参数集,并针对压缩从openNI采集器获取的普通点云进行了优化设置,注意,解码对象不需要用参数表示,因为它在解码是检测并获取对应编码参数配置,例如下面的压缩配置文件

LOW_RES_ONLINE_COMPRESSION_WITHOUT_COLOR,             //分别率为  1   cm^3   无颜色      快速在线编码
      LOW_RES_ONLINE_COMPRESSION_WITH_COLOR,                 //分别率为  1    cm^3   有颜色      快速在线编码

      MED_RES_ONLINE_COMPRESSION_WITHOUT_COLOR,             //分别率为  5    mm^3   无颜色      快速在线编码
      MED_RES_ONLINE_COMPRESSION_WITH_COLOR,                    //分别率为  5    mm^3   有颜色      快速在线编码

      HIGH_RES_ONLINE_COMPRESSION_WITHOUT_COLOR,         //分别率为  1    mm^3   无颜色      快速在线编码
      HIGH_RES_ONLINE_COMPRESSION_WITH_COLOR,                 //分别率为  1    mm^3   有颜色      快速在线编码

      LOW_RES_OFFLINE_COMPRESSION_WITHOUT_COLOR,       //分别率为  1    cm^3   无颜色      高效离线编码
      LOW_RES_OFFLINE_COMPRESSION_WITH_COLOR,              //分别率为  1    cm^3   有颜色      高效离线编码

      MED_RES_OFFLINE_COMPRESSION_WITHOUT_COLOR,      //分别率为  5    mm^3   无颜色      高效离线编码
      MED_RES_OFFLINE_COMPRESSION_WITH_COLOR,             //分别率为  5    mm^3   有颜色      高效离线编码

      HIGH_RES_OFFLINE_COMPRESSION_WITHOUT_COLOR,     //分别率为  1    mm^3   无颜色      高效离线编码
      HIGH_RES_OFFLINE_COMPRESSION_WITH_COLOR,              //分别率为  1    mm^3   有颜色      高效离线编码
      MANUAL_CONFIGURATION                                                   //允许为高级参数化进行手工配置

微信公众号号可扫描二维码一起共同学习交流

未完待续*********************************************8888

转载于:https://www.cnblogs.com/li-yao7758258/p/6436117.html

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android实现自定义带文字和图片的Button

在Android开发中经常会需要用到带文字和图片的button&#xff0c;下面来讲解一下常用的实现办法。 一.用系统自带的Button实现 最简单的一种办法就是利用系统自带的Button来实现&#xff0c;这种方式代码量最小。在Button的属性中有一个是drawableLeft&#xff0c;这个 属性可以…

mysql语句中的注释方法_MySQL语句注释方式简介

MySQL支持三种注释方式&#xff1a;1.从‘#字符从行尾。2.从‘-- 序列到行尾。请注意‘-- (双破折号)注释风格要求第2个破折号后面至少跟一个空格符(例如空格、tab、换行符等等)。3.从/*序列到后面的*/序列。结束序列不一定在同一行中&#xff0c;因此该语法允许注释跨越多行。…

aqlserver实用程序_sqlserver命令提示实用工具的介绍

除上述的图形化管理工具外&#xff0c;SQL Server2008还提供了大量的命令行实用工具&#xff0c;包括bcp、dtexec、dtutil、osql、reconfig、sqlcmd、sqlwb和tablediff等&#xff0c;下面进行简要说明。dtexec实用工具用于配置和执行SQL Server2008 Intgration Services包。用户…

使用Java和Scala将Play Framework 2应用程序部署到Openshift

几个星期&#xff0c; 马克阿特伍德 &#xff08; Mark Atwood&#xff09; &#xff0c; 豪尔赫阿里斯 &#xff08; Jorge Aliss &#xff09;和我塞巴斯蒂安 斯卡塔诺 &#xff08; SebastinScarano&#xff09;参加了红帽网络研讨会LETS PLAY&#xff01; 在云端&#xff1…

LintCode 387: Smallest Difference

LintCode 387: Smallest Difference 题目描述 给定两个整数数组&#xff08;第一个是数组A&#xff0c;第二个是数组B&#xff09;&#xff0c;在数组A中取A[i]&#xff0c;数组B中取B[j]&#xff0c;A[i]和B[j]两者的差越小越好(|A[i] - B[j]|)。返回最小差。 样例 给定数组A …

android框架----下沉文字Titanic的使用

Titanic is a simple illusion obtained by applying an animated translation on the TextView TextPaint Shaders matrix. Titanic的使用 Titanic的使用&#xff0c;项目结构如下&#xff1a; 一、下载Titanic并且部署到项目中 Titanic的项目地址&#xff1a; https://github…

linux 自动安装mysql_Linux安装mysql

一、下载这里我创建了一目录software用于存放我们待会要下载的mysql包&#xff0c;先去到该目录命令&#xff1a;cd /software命令&#xff1a;wget http://mirrors.sohu.com/mysql/MySQL-5.7/mysql-5.7.17-linux-glibc2.5-x86_64.tar下载完成后&#xff0c;你会在software这个…

Quartz Scheduler插件–隐藏的宝藏

尽管在官方文档中进行了简要描述&#xff0c;但我相信Quartz插件了解得还不够多&#xff0c;看看它们有多有用。 本质上&#xff0c;Quartz中的插件是方便的类&#xff0c;用于包装基础侦听器的注册。 您可以自由编写自己的插件&#xff0c;但我们将专注于Quartz随附的现有插件…

mysql查询表名匹配只有字母的_MySQL按某些匹配字母查询表

MySQL查询是MySQL的核心功能&#xff0c;有时候我们需要查找带有某些匹配字母的表。下文对该MySQL查询方式作了详细的介绍&#xff0c;供您参考。在MySQL中我们可以使用LIKE或者NOT LIKE操作符进行比较。在MySQL中模式默认是不区分大小写的。查询示例&#xff0c;student表----…

hdu 1181(Floyed)

变形课 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 20748 Accepted Submission(s): 7494 Problem Description呃......变形课上Harry碰到了一点小麻烦,因为他并不像Hermione那样能够记住所有的咒语而随意的…

读书笔记-你不知道的JS上-混入与原型

继承 mixin混合继承 function mixin(obj1, obj2) {for (var key in obj2) {//重复不复制if (!(key in obj1)) {obj1[key] obj2[key];}}return obj1;} 这种复制是浅复制&#xff0c;对象或者数组函数等都是同一个引用&#xff0c;改变obj1的会同时影响obj2。 寄生继承 ... 隐式…

JUnit和Hamcrest:在assertEquals上进行改进

在我的博客文章中&#xff0c;Java越来越接受静态导入吗&#xff1f; &#xff0c;我讨论了在Java中越来越多地使用静态导入来使代码在某些情况下更流畅。 Java 单元测试特别受静态导入的影响&#xff0c;在此博客文章中&#xff0c;我提供了一个简单的示例&#xff0c;说明如何…

mysql delete temporary denied_这些错误是什么意思?djang中的mysql

我试着运行一个程序&#xff0c;我被给予了一个例子&#xff0c;它就像一个购物网站&#xff0c;使用MySQL数据库而不是Django提供的原始数据库&#xff01;我只是想看看有没有人理解这些错误的含义&#xff1f;任何信息都将不胜感激&#xff01;我本可以提供网页的代码&#x…

C语言 · 芯片测试

基础练习 芯片测试 时间限制&#xff1a;1.0s 内存限制&#xff1a;512.0MB问题描述有n&#xff08;2≤n≤20&#xff09;块芯片&#xff0c;有好有坏&#xff0c;已知好芯片比坏芯片多。每个芯片都能用来测试其他芯片。用好芯片测试其他芯片时&#xff0c;能正确给出被测试…

Animation用法

测试代码及说明&#xff1a; <!DOCTYPE html> <html lang"en-US"> <head><meta charset"UTF-8"><title>Simple CSS3 Animation</title><style type"text/css">#demo {position: absolute;left: 30%;t…

mysql dese_MySQL 5.6-类似于DENSE_RANK的功能,无需订购

小编典典对于 MySQL版本<8.0(OP的版本是5.6)&#xff1a;问题陈述看起来需要DENSE_RANK功能groupVarian; 但是事实并非如此。正如 GordonLinoff解释的那样 &#xff1a;您似乎希望按它们在数据中出现的顺序来枚举它们。假设您的表名是t(请为您的代码相应地更改表名和字段名)…

Spring和JSF集成:动态导航

通常&#xff0c;您的JSF应用程序将需要超越基本的静态导航并开始做出动态导航决策。 例如&#xff0c;您可能想根据用户的年龄重定向他们。 大多数JSF教程建议通过将命令的action属性绑定到支持bean来实现动态导航&#xff1a; <h:commandButton action"#{bean.action…

通过富文本改变UITextFieldPlaceholder颜色

1、通过属性 a、 //文字属性(一般) NSMutableDictionary *attrs [NSMutableDictionary dictionary]; attrs[NSForegroundColorAttributeName] [UIColor blueColor]; NSAttributedString *placeholderStr [[NSAttributedString alloc] initWithString:"手机号" a…

阻塞/非阻塞/同步/异步方法和多线程的关系?没有任何关系,俩不挨着

1.阻塞非阻塞异步同步是针对方法说的&#xff0c;是评判一个方法运行状态的。和多线程完全两个级别。 2.阻塞非阻塞异步同步是针对方法说的&#xff0c;是评判一个方法运行状态的。和多线程完全两个级别。 3.阻塞非阻塞异步同步是针对方法说的&#xff0c;是评判一个方法运行状…

mysql备份 where_MySQL备份与还原

1.mysqldumpmysqlbinlog介绍mysqldump备份结合binlog日志恢复。MySQL备份一般采取全库备份加日志备份的方式&#xff0c;例如每天执行一次全备份&#xff0c;每小时执行一次二进制日志备份&#xff0c;这样在MySQL故障后可以使用全备份和日志备份将数据恢复到最后一个二进制日志…