PCL系列3——Octree的使用

PCL库中的Octree使用示例

1. Octree原理介绍

1.1百度百科:

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

1.2实现八叉树的原理:

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

2. 示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <pcl/io/pcd_io.h>  //文件输入输出
#include <pcl/octree/octree_search.h> //octree相关定义
#include <pcl/visualization/cloud_viewer.h> //vtk可视化相关定义
#include <pcl/point_types.h> //点类型相关定义

#include <iostream>
#include <vector>

int main()
{
//1.读取点云
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
if (pcl::io::loadPCDFile<pcl::PointXYZRGB>("rabbit.pcd", *cloud) == -1)
{
PCL_ERROR("Cloudn't read file!");
return -1;
}

//2.原始点云着色
for (size_t i = 0; i < cloud->points.size(); ++i){
cloud->points[i].r = 255;
cloud->points[i].g = 255;
cloud->points[i].b = 255;
}

//3.创建Octree实例对象
float resolution = 0.03f; //设置octree体素分辨率
pcl::octree::OctreePointCloudSearch<pcl::PointXYZRGB> octree(resolution); //建立octree对象
octree.setInputCloud(cloud); //传入需要建立kdtree的点云指针
octree.addPointsFromInputCloud(); //构建Octree

//3.1.体素内近邻搜索
pcl::PointXYZRGB searchPoint1 = cloud->points[1250]; //设置查找点
std::vector<int> pointIdxVec; //保存体素近邻搜索的结果向量
if (octree.voxelSearch(searchPoint1, pointIdxVec))
{
std::cout << "Neighbors within voxel search at (" << searchPoint1.x
<< " " << searchPoint1.y
<< " " << searchPoint1.z << ")"
<< std::endl;

//给查找到的近邻点设置颜色
for (size_t i = 0; i < pointIdxVec.size(); ++i){
cloud->points[pointIdxVec[i]].r = 255;
cloud->points[pointIdxVec[i]].g = 0;
cloud->points[pointIdxVec[i]].b = 0;
}
}

//3.2.K近邻搜索
pcl::PointXYZRGB searchPoint2 = cloud->points[3000]; //设置查找点
int K = 200;
std::vector<int> pointIdxNKNSearch; //保存K近邻点的索引结果
std::vector<float> pointNKNSquaredDistance; //保存每个近邻点与查找点之间的欧式距离平方

std::cout << "K nearest neighbor search at (" << searchPoint2.x
<< " " << searchPoint2.y
<< " " << searchPoint2.z
<< ") with K=" << K << std::endl;

if (octree.nearestKSearch(searchPoint2, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0)
{ //给查找到的近邻点设置颜色
for (size_t i = 0; i < pointIdxNKNSearch.size(); ++i){
cloud->points[pointIdxNKNSearch[i]].r = 0;
cloud->points[pointIdxNKNSearch[i]].g = 255;
cloud->points[pointIdxNKNSearch[i]].b = 0;
}
}
std::cout << "K = 200近邻点个数:" << pointIdxNKNSearch.size() << endl;

//3.3.半径内近邻搜索
pcl::PointXYZRGB searchPoint3 = cloud->points[6500]; //设置查找点
std::vector<int> pointIdxRadiusSearch; //保存每个近邻点的索引
std::vector<float> pointRadiusSquaredDistance; //保存每个近邻点与查找点之间的欧式距离平方
float radius = 0.02; //设置查找半径范围

std::cout << "Neighbors within radius search at (" << searchPoint3.x
<< " " << searchPoint3.y
<< " " << searchPoint3.z
<< ") with radius=" << radius << std::endl;

if (octree.radiusSearch(searchPoint3, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0)
{ //给查找到的近邻点设置颜色
for (size_t i = 0; i < pointIdxRadiusSearch.size(); ++i){
cloud->points[pointIdxRadiusSearch[i]].r = 0;
cloud->points[pointIdxRadiusSearch[i]].g = 0;
cloud->points[pointIdxRadiusSearch[i]].b = 255;
}
}
std::cout << "半径0.02近邻点个数: " << pointIdxRadiusSearch.size() << endl;

//4.显示点云
pcl::visualization::CloudViewer viewer("cloud viewer");
viewer.showCloud(cloud);

system("pause");
return 0;
}

3.运行结果

octree

-------------本文结束感谢您的阅读-------------