八叉树 octree

来源:互联网 发布:高速铣编程用什么软件 编辑:程序博客网 时间:2024/06/09 16:36

八叉树

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

简介

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

实现原理

编辑
(1). 设定最大递归深度
(2). 找出场景的最大尺寸,并以此尺寸建立第一个立方体
(3). 依序将单位元元素丢入能被包含且没有子节点的立方体
(4). 若没有达到最大递归深度,就进行细分八等份,再将该立方体所装的单位元元素全部分担给八个子立方体
(5). 若发现子立方体所分配到的单位元元素数量不为零且跟父立方体是一样的,则该子立方体停止细分,因为跟据空间分割理论,细分的空间所得到的分配必定较少,若是一样数目,则再怎么切数目还是一样,会造成无穷切割的情形。
(6). 重复3,直到达到最大递归深度。

存贮结构

编辑
本例中八叉树的存贮结构用一个有(若干+八)个字段的记录来表示树中的每个结点。其中若干字段用来描述该结点的特性(本例中的特性为:节点的值和节点坐标),其余的八个字段用来作为存放指向其八个子结点的指针。此外,还有线性存储和1托8式存储。

叉树对比

编辑
a) BSP树将场景分割为1个面,而八叉树分割为3个面。
b) BSP树每个节点最多有2个子结点,而八叉树最多有8个子结点
因此BSP树可以用在任意维度的场景中,而八叉树则常用于三维空间场。
点云压缩:
#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")  {  }voidcloud_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);    }  }voidrun ()  {bool showStatistics=true;//设置在标准设备上面打印出压缩结果信息 // 压缩选项详见 /io/include/pcl/compression/compression_profiles.hpcl::octree::compression_Profiles_e compressionProfile=pcl::octree::MED_RES_ONLINE_COMPRESSION_WITH_COLOR;// 初始化压缩与解压缩对象PointCloudEncoder=new pcl::octree::PointCloudCompression<pcl::PointXYZRGBA> (compressionProfile, showStatistics);PointCloudDecoder=new pcl::octree::PointCloudCompression<pcl::PointXYZRGBA> ();//创建从 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::octree::PointCloudCompression<pcl::PointXYZRGBA>*PointCloudEncoder;pcl::octree::PointCloudCompression<pcl::PointXYZRGBA>*PointCloudDecoder;};intmain (int argc, char**argv){SimpleOpenNIViewer v;v.run ();return (0);}
octree空间划分以及搜索:
#include <pcl/point_cloud.h>#include <pcl/octree/octree.h>#include <iostream>#include <vector>#include <ctime>intmain (int argc, char**argv){srand ((unsigned int) time (NULL));pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);// 创建点云数据cloud->width =1000;cloud->height =1;cloud->points.resize (cloud->width * cloud->height);for (size_t i=0; i< cloud->points.size (); ++i)  {cloud->points[i].x =1024.0f* rand () / (RAND_MAX +1.0f);//随机产生点坐标值 cloud->points[i].y =1024.0f* rand () / (RAND_MAX +1.0f);cloud->points[i].z =1024.0f* rand () / (RAND_MAX +1.0f);  }float resolution =128.0f;//设置分辨率进行初始化,用叶节点存放索引向量 pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree(resolution);octree.setInputCloud (cloud);//设置输入点云 octree.addPointsFromInputCloud ();//创建一个octree实例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);// 体素内近邻搜索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 (size_t i=0; i<pointIdxVec.size (); ++i)std::cout<<"    "<< cloud->points[pointIdxVec[i]].x <<" "<< cloud->points[pointIdxVec[i]].y <<" "<< cloud->points[pointIdxVec[i]].z <<std::endl;  }//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 (size_t i=0; i<pointIdxNKNSearch.size (); ++i)std::cout<<"    "<<   cloud->points[ pointIdxNKNSearch[i] ].x <<" "<< cloud->points[pointIdxNKNSearch[i] ].y <<" "<< cloud->points[pointIdxNKNSearch[i] ].z <<" (squared distance: "<<pointNKNSquaredDistance[i] <<")"<<std::endl;  }//半径内近邻搜索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 (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;  }}

点云数据空间变化检测:
#include <pcl/point_cloud.h>#include <pcl/octree/octree.h>#include <iostream>#include <vector>#include <ctime>int main (intargc, char**argv){srand ((unsignedint) time (NULL));// 八叉树分辨率 即体素的大小float resolution =32.0f;// 初始化空间变化检测对象pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZ>octree (resolution);pcl::PointCloud<pcl::PointXYZ>::PtrcloudA (newpcl::PointCloud<pcl::PointXYZ> );//为cloudA创建点云cloudA->width =128;cloudA->height =1;cloudA->points.resize (cloudA->width *cloudA->height);for (size_ti=0; i<cloudA->points.size (); ++i)  {cloudA->points[i].x =64.0f* rand () / (RAND_MAX +1.0f);cloudA->points[i].y =64.0f* rand () / (RAND_MAX +1.0f);cloudA->points[i].z =64.0f* rand () / (RAND_MAX +1.0f);  }//添加点云到八叉树,建立八叉树octree.setInputCloud (cloudA);octree.addPointsFromInputCloud ();// 交换八叉树缓存,但是cloudA对应的八叉树仍在内存中octree.switchBuffers ();pcl::PointCloud<pcl::PointXYZ>::PtrcloudB (new pcl::PointCloud<pcl::PointXYZ> );// 为cloudB创建点云cloudB->width =128;cloudB->height =1;cloudB->points.resize (cloudB->width *cloudB->height);for (size_ti=0; i<cloudB->points.size (); ++i)  {cloudB->points[i].x =64.0f* rand () / (RAND_MAX +1.0f);cloudB->points[i].y =64.0f* rand () / (RAND_MAX +1.0f);cloudB->points[i].z =64.0f* rand () / (RAND_MAX +1.0f);  }//添加 cloudB到八叉树octree.setInputCloud (cloudB);octree.addPointsFromInputCloud ();std::vector<int>newPointIdxVector;//获取前一cloudA对应的八叉树在cloudB对应八叉树中没有的体素octree.getPointIndicesFromNewVoxels (newPointIdxVector);//打印输出点std::cout<<"Output from getPointIndicesFromNewVoxels:"<<std::endl;for (size_ti=0; i<newPointIdxVector.size (); ++i)std::cout<<i<<"# Index:"<<newPointIdxVector[i]<<"  Point:"<<cloudB->points[newPointIdxVector[i]].x <<" "<<cloudB->points[newPointIdxVector[i]].y <<" "<<cloudB->points[newPointIdxVector[i]].z <<std::endl;}



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

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

原创粉丝点击