学习PCL库:基于LOD的大规模点云可视化

公众号致力于点云处理,SLAM,三维视觉,高精地图等领域相关内容的干货分享,欢迎各位加入,有兴趣的可联系dianyunpcl@163.com。未经作者允许请勿转载,欢迎各位同学积极分享和交流。

什么是LOD(Level of Detail)?

LOD(Level of Detail)是一种在计算机图形学中用于优化渲染性能的技术,主要应用于三维模型、地形等复杂几何数据的渲染中。LOD通过在不同的距离和尺寸下使用不同的模型细节级别,使得在近处显示高细节的模型,而在远处则只显示简化的模型。这样可以减少需要渲染的数据量,提高渲染性能。LOD将一个复杂的模型分成多个不同的细节层次,每个层次都有一个相应的模型表示。随着视点的移动,系统会根据视点与模型的距离和大小,自动切换显示不同的细节层次,从而在不影响视觉效果的前提下,提高渲染性能。

在点云可视化中,LOD技术也可以应用于优化点云的渲染性能。例如,在近处可以显示点云的所有细节,而在远处只需要显示部分点云或者采用一些简化的点云表示方式,从而提高点云可视化的效率。

之前的一篇文章:PCL中outofcore模块---基于核外八叉树的大规模点云的显示

LOD算法的基本思想

对于每一个点云数据,将其表示为不同层次的细节级别,即将每个点云数据分解成若干层,每一层代表一种不同的细节级别,每一层的点云数量比前一层减少,同时每层点云之间存在一定的关联关系。一般来说,每一层的点云数据都可以通过前一层数据进行重建或者近似重建。这样,在可视化时,根据需要,选择合适的细节级别进行显示,能够在保证精度的前提下,减少计算和存储的开销。

LOD(Level of Detail)算法的基本思想是根据视点距离和显示需求等因素,对模型进行适当的简化和优化,以提高显示效率和减少计算开销。LOD算法也常用于对点云数据进行适当的简化和优化,以提高点云渲染的效率。LOD算法的基本思想可以分为两个方面:

  • 减少数据量:LOD算法根据视点距离,将大范围的点云数据进行适当的简化和压缩,减少数据量,提高点云数据的渲染效率。

  • 保持数据的精度:LOD算法在简化数据的同时,尽可能地保留数据的精度。例如,在点云数据简化时,可以保留重要的点和局部细节信息,从而避免丢失重要的特征信息,保持数据的精度和可视化效果。

LOD算法通常会将点云数据分为不同的层级,每个层级对应不同的点云分辨率。在视点距离较远时,可以使用较低分辨率的点云数据来显示,以提高渲染效率;在视点距离较近时,则可以使用更高分辨率的点云数据来显示,以保证显示精度和细节。

LOD算法常见的实现方式

LOD(Level of Detail)算法的实现方式有多种,其中常见的有两种:基于采样的LOD(金字塔层次结构、变形网格)和基于分割的LOD(空间分割)。

  • 基于采样的LOD是指通过对点云数据进行采样,从而得到不同密度的点云表示不同的细节层次。这种方法的优点是简单易实现,可以方便地对不同层次的点云进行展示和处理。常见的实现方式包括:体素化采样和随机采样。其中,体素化采样是指将点云数据按照一定的体素大小进行采样,从而得到不同精度的点云。CloudCompare中就使用了体素化采样的方法来实现LOD算法,用户可以通过设置不同的体素大小来控制不同细节层次的显示。

  • 基于分割的LOD是指将点云数据按照不同的特征进行分割,从而得到不同密度的点云表示不同的细节层次。这种方法的优点是可以更加准确地表达点云数据的特征信息。常见的实现方式包括:基于颜色和法向量的分割、基于曲率的分割等。但是,这种方法相对于基于采样的LOD来说更加复杂,实现起来也更加困难。

CloudCompare和PCL库中LOD的实现

LOD算法可以帮助我们更好地展示和处理大规模的点云数据,常见的实现方式包括基于采样的LOD和基于分割的LOD。在CloudCompare中,主要采用了基于体素化采样的方法实现LOD算法。

这是CloudCompare中实现LOD算法的函数,函数原型为

void CCViewer::computeLOD(std::vector& comps, const unsigned int maxPoints, const unsigned int maxVoxels)。

该函数会接收一个点云组件列表和最大点数和最大体素数,然后计算总点数,并根据总点数和最大点数计算采样因子。然后,根据采样因子和最大体素数计算体素大小,并将其应用于点云组件。这种方法使用体素化采样,可以快速地减少点云数据的密度,从而实现LOD效果。下面对其进行详细的注释:

void CCViewer::computeLOD(std::vector& comps, const unsigned int maxPoints, const unsigned int maxVoxels)
{
    // compute the total number of points
    unsigned long long totalPoints = 0;
    for (size_t i = 0; i < comps.size(); i++)
    {
        totalPoints += comps[i]->getPointCloud().size();
    }

首先,该函数接收一个CloudGLComponent指针的向量comps,表示所有待处理的点云组件,以及两个参数maxPoints和maxVoxels,分别表示采样后最大的点数和最大的体素数。函数的第一步是计算所有点云的点数总和,这个总和保存在变量totalPoints中。

// compute the sampling factor
    float factor = (float)totalPoints / (float)maxPoints;
    float voxelFactor = factor * 0.3f; // arbitrary factor to take into account the voxelization process

接下来,函数计算采样系数。采样系数是一个与总点数和采样后最大点数有关的浮点数,用于指导采样时的点数选择。LOD算法的基本思想是,在显示远处的点云时,选择相对较少的点来表示,从而减小渲染的负担。因此,采样系数越大,表示点云被采样得越稠密。voxelFactor是一个用于考虑体素化过程的任意系数。

// compute the voxel size
    double voxels = totalPoints / voxelFactor;
    voxels /= maxVoxels;
    voxels = pow(voxels, 1.0 / 3.0);
    voxels = std::max(voxels, 0.005);

接下来,函数根据采样系数和最大体素数计算体素大小。计算方法是:先计算所有点云的点数与voxelFactor的比值,再除以maxVoxels,最后开三次方根。这样计算出来的结果就是每个体素的边长。另外,函数还对计算结果进行了一个限制,保证每个体素的大小不小于0.005。

// update the voxel size
    for (size_t i = 0; i < comps.size(); i++)
    {
        comps[i]->updateVoxelSize(voxels);
    }
}

最后,函数更新每个点云组件的体素大小,将之前计算出来的边长voxels作为参数传递给updateVoxelSize函数。这个函数的作用是更新点云组件的体素,并在必要时重新计算点云的LOD信息。

PCL中outofcore模块实现了大规模点云的可视化,其中采用了基于体素的LOD算法,该算法的具体实现过程如下所示:

  • 初始化体素树:首先,需要在内存中初始化一个体素树,即根据点云数据生成一个体素层级结构,最底层为点云的原始数据,然后不断上采样生成更高分辨率的体素层。

  • 选择当前LOD:根据视点位置,计算出当前视点在体素树中的层数,进而确定当前需要显示的LOD层数。

  • 加载数据:根据当前需要显示的LOD,从磁盘中加载相应的数据,即体素、八叉树节点、点云块等。

  • 体素渲染:将加载的体素通过OpenGL渲染到屏幕上,根据当前LOD选择体素的大小,以保证视觉效果。

  • 八叉树渲染:对于体素层次结构中的内部节点,需要采用递归的方式对其子节点进行渲染。

  • 点云块渲染:对于叶子节点(即点云块),则需要根据当前LOD选择加载部分点云块的数据,并通过OpenGL渲染到屏幕上。

  • 点云渲染:在点云块渲染的过程中,还需要对其中的点云进行LOD处理,即根据当前LOD选择保留一定比例的点云数据进行渲染,而剩余的点云则被抽样或者丢弃。

  • 总的来说,outofcore模块的LOD算法主要利用了体素结构的层次性质,根据视点位置动态选择LOD并采用不同程度的采样对点云数据进行处理,以实现大规模点云的可视化。

#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/outofcore/visualization/outofcore_visualizer.h>
int main(int argc, char **argv)
{
  // 创建一个可视化窗口
  boost::shared_ptrviewer(new pcl::visualization::PCLVisualizer("PCL Outofcore Viewer"));
  // 创建一个outofcore可视化器
  pcl::outofcore::visualization::OutofcoreVisualizervis(viewer);
  // 加载点云数据
  vis.load(argv[1]);
  // 初始化体素树
  vis.initOctree();
  // 设置视点位置
  Eigen::Vector3d eye(0.0, 0.0, 200.0);
  // 设置目标位置
  Eigen::Vector3d target(0.0, 0.0, 0.0);
  // 设置向上方向
  Eigen::Vector3d up(0.0, 1.0, 0.0);
  // 设置视口大小
  int width = 640;
  int height = 480;
  // 设置近点距和远点距
  double near = 0.1;
  double far = 1000.0;
  // 根据视点位置计算当前LOD
  int lod = vis.computeLOD(eye);
  // 设置背景颜色
  viewer->setBackgroundColor(0.0, 0.0, 0.0);
  // 开始渲染
  while (!viewer->wasStopped())
  {
    // 加载当前需要显示的LOD层数的数据
    vis.loadLOD(lod);
    // 渲染体素
    vis.renderVoxels(lod);
    // 渲染八叉树节点
    vis.renderOctree(lod);
    // 渲染点云块
    vis.renderBlocks(lod);
    // 渲染点云
    vis.renderPoints(lod);
    // 更新窗口
    viewer->spinOnce(100);
    // 更新视点位置
    eye = viewer->getCameras()[0].pos;
    lod = vis.computeLOD(eye);
  }
  return 0;
}

当点云数据非常大时,对于每次的渲染操作,需要从磁盘中加载相应的数据,会导致大量的IO操作,从而导致渲染效率非常低下。为了提高渲染效率,PCL中的outofcore模块还提供了一些性能优化手段,例如预加载数据、异步加载数据等。

  • 预加载数据:在初始化体素树时,可以预加载一些体素、八叉树节点、点云块等数据到内存中,这样可以在后续渲染操作时避免磁盘IO操作,从而提高渲染效率。

  • 异步加载数据:在渲染操作中,可以采用异步加载数据的方式,即将数据加载的过程放在后台线程中进行,这样可以避免阻塞主线程,从而提高渲染效率。

PCL中的outofcore模块可以有效地实现对大规模点云数据的可视化,不仅可以提供高效的渲染效果,还支持LOD、性能优化等一系列功能。

LOD算法的优缺点

优点:

  • 高效性:通过降低点云数据的分辨率,减少需要处理的数据量,提高算法的处理效率,可以根据需要选择不同的细节级别进行渲染,减少点云数量,从而提高渲染效率。

  • 可视化效果好:通过降低点云数据的分辨率,可以实现在不损失重要信息的情况下,显示更大规模的点云数据。即使在较低的细节级别下,也能够提供足够的可视化信息。

  • 可以减少内存占用:可以将点云数据集分解成多层,每一层点云数据数量逐层减少,从而节省存储空间,通过降低点云数据的分辨率,可以减少存储数据所需的内存。

缺点:

  • 精度受限:LOD算法降低了点云数据的分辨率,因此对于需要高精度的应用,可能会出现信息丢失的情况。

  • 不能完全代替原始数据:虽然通过LOD算法可以降低点云数据的分辨率,但是不能完全代替原始数据,因为降低分辨率会损失一些重要信息。

  •  LOD算法本身需要设计:需要在算法实现时进行一些设计,例如选择何种算法、决定采样率等,这可能需要一些经验和实验验证。

    因此,LOD算法适用于大规模点云数据的可视化和处理,但对于需要高精度和完整性的应用,需要谨慎使用。

DEMO展示

1b30f86afbf7ca3160d2678712be9d02.jpeg

0bc12f49c108354a5a51b1656a37daba.jpeg

更多详细内容请加入智驾全栈与3D视觉学习星球

智驾全栈与3D视觉学习星球:主要针对智能驾驶全栈相关技术,3D/2D视觉技术学习分享的知识星球,将持续进行干货技术分享,知识点总结,代码解惑,最新paper分享,解疑答惑等等。星球邀请各个领域有持续分享能力的大佬加入我们,对入门者进行技术指导,对提问者知无不答。同时,星球将联合各知名企业发布自动驾驶,机器视觉等相关招聘信息和内推机会,创造一个在学习和就业上能够相互分享,互帮互助的技术人才聚集群。

资源

自动驾驶及定位相关分享

【点云论文速读】基于激光雷达的里程计及3D点云地图中的定位方法

自动驾驶中基于光流的运动物体检测

基于语义分割的相机外参标定

综述:用于自动驾驶的全景鱼眼相机的理论模型和感知介绍

高速场景下自动驾驶车辆定位方法综述

Patchwork++:基于点云的快速、稳健的地面分割方法

PaGO-LOAM:基于地面优化的激光雷达里程计

多模态路沿检测与滤波方法

多个激光雷达同时校准、定位和建图的框架

动态的城市环境中杆状物的提取建图与长期定位

非重复型扫描激光雷达的运动畸变矫正

快速紧耦合的稀疏直接雷达-惯性-视觉里程计

基于相机和低分辨率激光雷达的三维车辆检测

用于三维点云语义分割的标注工具和城市数据集

ROS2入门之基本介绍

固态激光雷达和相机系统的自动标定

激光雷达+GPS+IMU+轮速计的传感器融合定位方案

基于稀疏语义视觉特征的道路场景的建图与定位

自动驾驶中基于激光雷达的车辆道路和人行道实时检测(代码开源)

用于三维点云语义分割的标注工具和城市数据集

更多文章可查看:点云学习历史文章大汇总

SLAM及AR相关分享

TOF相机原理介绍

TOF飞行时间深度相机介绍

结构化PLP-SLAM:单目、RGB-D和双目相机使用点线面的高效稀疏建图与定位方案

开源又优化的F-LOAM方案:基于优化的SC-F-LOAM

【开源方案共享】ORB-SLAM3开源啦!

【论文速读】AVP-SLAM:自动泊车系统中的语义SLAM

【点云论文速读】StructSLAM:结构化线特征SLAM

SLAM和AR综述

常用的3D深度相机

AR设备单目视觉惯导SLAM算法综述与评价

SLAM综述(4)激光与视觉融合SLAM

Kimera实时重建的语义SLAM系统

SLAM综述(3)-视觉与惯导,视觉与深度学习SLAM

易扩展的SLAM框架-OpenVSLAM

高翔:非结构化道路激光SLAM中的挑战

基于鱼眼相机的SLAM方法介绍

以上内容如有错误请留言评论,欢迎指正交流。如有侵权,请联系删除

扫描二维码

                   关注我们

让我们一起分享一起学习吧!期待有想法,乐于分享的小伙伴加入知识星球注入爱分享的新鲜活力。分享的主题包含但不限于三维视觉,点云,高精地图,自动驾驶,以及机器人等相关的领域。

分享及合作方式:微信“920177957”(需要按要求备注) 联系邮箱:dianyunpcl@163.com,欢迎企业来联系公众号展开合作。

点一下“在看”你会更好看耶

53f360021c7fd7897dc46ead7a76b075.gif

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点云PCL公众号博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值