点云的降采样:八叉树采样(Octree)

Octree

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

Octree的用途
八叉树是一种用于描述三维空间的树状数据结构。

Octree的结构:
八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,将八个子节点所表示的体积元素加在一起就等于父节点的体积。
完整的八叉树,每个中间节点都有八个子节点,所有叶节点都有相同的树深度D,叶节点数为8的D次幂
图1:
图2
在这里插入图片描述

八叉树构建原理如下:
(1). 设定最大递归深度

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

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

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

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

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

:构建八叉树的时候,要区分插入的各点云,将各点云进行编号,插入时主要通过递归的方式寻找无数据的child,生成的八叉树可以是是增长式的,即哪里有点云则往哪里插入栅格,无点云的地方不插入栅格。也可以是上图中的固定体素构建形式

空间栅格划分完成之后,去重叠的方法:
一种为只保留体素中心点,将体素中的其他点删除,这样的到的采样点云比较均匀,但在特征的保留上效果不是很好

一种为,计算体素中的点距离体素中心点的长度,然后计算距离的均值,大于(或小于)均值的点即删除,这种方法保留了原始点云数据,但重叠区域的点仍然会比较密集,因此,最好要将法向量、曲率等因素考虑在内,增加细节部分的显示,但还要均衡处理速度

一种为,通过K-Dtree搜索各点近邻的方式来判断各部分点云的密度,然后,遍历各体素,保留体素中密度较大的点云来达到去重叠的效果,但处理后会发现,各点云的交接处会有缝隙出现。解决办法:各交接点云去除时保留不带边缘的点云。最后,会有一个问题待解决,计算点云密度耗时较多。主要耗时部分为构建K-Dtree的时候。另外,这种处理方法会频繁计算点云密度,所以可以考虑以各体素中的点数来判断密度的方式替代。

另外,PCL中的octree框架中,每一个体素都产生了对应的编号,所以在查找体素和查找体素中对应点的时候方便且不会出错。 这一方法的主要优点在于可以非常方便地实现有广泛用途的集合运算(例如可以求两个物体的并、交、差等运算),而这些恰是其它表示方法比较难以处理或者需要耗费许多计算资源的地方。不仅如此,由于这种方法的有序性及分层性,因而对显示精度和速度的平衡、隐线和隐面的消除等,带来了很大的方便,特别有用。

最后,
奉上octree的源码:https://codeload.github.com/brandonpelfrey/SimpleOctree/zip/master
(要不要考虑点个赞!!!!!)

代码的主要部分:

void insert(OctreePoint* point)
{
	if(isLeafNode()) 
	{
    	    if(data==NULL) {
     		data = point;
     		return;
   	     }
   	    else {
  	 	OctreePoint *oldPoint = data;
   		data = NULL;
  	 	for(int i=0; i<8; ++i) {
   	 	Vec3 newOrigin = origin;
    		newOrigin.x += halfDimension.x * (i&4 ? .5f : -.5f);
   	 	newOrigin.y += halfDimension.y * (i&2 ? .5f : -.5f);
   	 	newOrigin.z += halfDimension.z * (i&1 ? .5f : -.5f);
   	 	children[i] = new Octree(newOrigin, halfDimension*.5f);
  	     }
  	     children[getOctantContainingPoint(oldPoint->getPosition())]->insert(oldPoint);
   	     children[getOctantContainingPoint(point->getPosition())]->insert(point);
         }
	 else {
   		int octant = getOctantContainingPoint(point->getPosition());
   		children[octant]->insert(point);
  	 }
}
### 使用八叉树点云进行降采样的方法 在处理大规模点云数据时,降采样是一种常见的优化技术。通过减少点的数量来降低计算复杂度并提高效率。PCL(Point Cloud Library)提供了基于八叉树点云降采样功能[^2]。 #### 八叉树的概念 八叉树是一种空间划分结构,用于高效地表示三维空间中的对象分布情况。它通过对立方体区域递归分割成八个子立方体的方式实现层次化存储。这种结构非常适合用来管理密集型点云数据集。 #### PCL 中的 Octree 实现 PCL 提供了一个名为 `pcl::octree` 的模块,支持多种操作,其中包括点云降采样。具体来说,可以利用类 `pcl::OctreePointCloudVoxelGrid` 来完成这一任务。该类继承自 `pcl::octree::OctreeBase` 并实现了基于体素网格的方法来进行降采样。 以下是使用 PCL 进行点云降采样的代码示例: ```cpp #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/filters/voxel_grid.h> int main () { pcl::PCLPointCloud2::Ptr cloud (new pcl::PCLPointCloud2 ()); pcl::PCLPointCloud2::Ptr cloud_filtered (new pcl::PCLPointCloud2 ()); // 加载点云文件 pcl::io::loadPCDFile ("test_pcd.pcd", *cloud); std::cerr << "原始点数: " << cloud->width * cloud->height << std::endl; // 创建滤波器实例 pcl::VoxelGrid<pcl::PCLPointCloud2> sor; sor.setInputCloud (cloud); // 设置体素大小(即分辨率) double leaf_size = 0.01; // 单位为米 sor.setLeafSize (leaf_size, leaf_size, leaf_size); // 执行过滤 sor.filter (*cloud_filtered); std::cerr << "降采样后的点数: " << cloud_filtered->width * cloud_filtered->height << std::endl; // 保存结果到新文件 pcl::io::savePCDFileBinaryCompressed("downsampled_cloud.pcd", *cloud_filtered); return (0); } ``` 上述程序展示了如何加载一个 `.pcd` 文件,并应用体素栅格法对其进行降采样。这里设置的参数 `setLeafSize()` 定义了每个体素单元的空间尺寸,从而决定了最终保留下来的点密度。 需要注意的是,在实际项目中可能还需要考虑其他因素比如边界条件或者特殊几何形状的影响等。因此建议深入研究官方文档获取更多细节信息以便更好地调整算法满足特定需求。 #### 性能考量 当面对非常庞大的点云集合时,采用高效的日志记录工具如 spdlog 可以帮助监控性能瓶颈以及调试过程中产生的各种状态变化[^1]。这有助于开发者快速定位问题所在位置进而采取相应措施改善整体表现。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值