超大点云处理策略

4 阅读5分钟

超大点云处理策略:基于空间分片与4D融合点云的高效加载与渲染

在处理超大规模点云时,如何高效地管理内存、减少网络请求并提升用户体验,是一个非常关键的问题。今天我们介绍一种常见的解决方案:空间分片与4D融合点云,结合前端按需加载和切帧控制,实现高效的可视化与交互。

一、什么是超大点云?

超大点云指的是包含数百万甚至数十亿个点的数据集,常见于自动驾驶、地理信息系统、三维重建等领域。在这种场景下,如何高效处理这些点云数据,尤其是在浏览器或前端渲染时,成为了一个巨大的挑战。

二、方案概述

本方案通过将点云按空间区域分片,以及在每个分片内融合多个时间帧,解决了超大点云的数据传输、内存占用、渲染效率等问题。具体策略如下:

1. 空间分片(Sharding)

当点云数据集非常庞大时,我们通常会将点云按空间区域切分成多个分片。每个分片对应一个空间区域,包含该区域内所有的点云数据。

例:rangeJSON 数据结构
{
  "0": {
    "range": [x1, y1, x2, y2],
    "final_pcds_num": 10000,
    "final_extra_pcds_num": 5000,
    "num_not_in_overlap": 2000
  },
  "1": {
    "range": [x3, y3, x4, y4],
    "final_pcds_num": 15000,
    "final_extra_pcds_num": 7000,
    "num_not_in_overlap": 3000
  },
  "frames": 50,
  "pcds_ds_mode": "split",
  "sam_version": "v1.0",
  "psam_version": "v2.0",
  "instance_skip_threshold": 10
}

在这个结构中,每个分片(如 0、1)都有一个空间范围(range) ,指定了点云数据的空间坐标范围。每个分片也包含了最终的点云数量、额外预标注点数量以及非重叠区域的点数量等信息。

2. 按需加载分片

根据用户当前视野,前端将按需加载分片。当用户查看某个区域时,后端会加载该区域的融合点云数据(如 0.pcd)。与此同时,后台会通过 Web Worker 预加载其他分片(如 1.pcd、2.pcd等),以便用户切换到其他区域时,能够快速加载数据。

加载流程
  1. 用户打开任务,前端获取当前区域的分片:infoShardingId = 0
  2. 只请求对应区域的点云文件(如 0.pcd
  3. 后台预加载其他区域的点云数据(如 1.pcd, 2.pcd 等)到 Worker
  4. 用户切换区域时,从缓存中加载对应的分片,若缓存没有,则重新请求

3. 4D 点云 = 融合点云

每个分片的点云文件(如 0.pcd)包含该区域所有帧的数据,多个帧的数据已经融合。每个点都携带了 frameIndex 属性,表示它属于哪个时间帧。

切帧操作并不需要重新请求新的文件,而是通过改变每个点的可见性来控制渲染哪些帧的数据。

function filterPcd(frameStart, frameEnd) {
  for (let i = 0; i < totalPoints; i++) {
    const pointFrameIndex = pointArray[i].frameIndex;
    if (pointFrameIndex >= frameStart && pointFrameIndex <= frameEnd) {
      pointArray[i].visible = 1; // 显示
    } else {
      pointArray[i].visible = 0; // 隐藏
    }
  }
}

4. 总结

通过空间分片和4D融合点云的处理策略,我们可以有效解决以下问题:

  • 空间分片:通过将点云按区域划分成多个 .pcd 文件,每个文件存储该区域内的所有帧数据。这样能减轻每次加载时的内存压力。
  • 按需加载:前端根据用户当前查看的区域,动态加载对应的分片数据,避免一次性加载所有点云,减少带宽消耗。
  • 后台预缓存:后台使用 Web Worker 预加载其他分片数据,提高区域切换时的响应速度。
  • 时间维度:每个分片内包含所有时间帧的数据,通过 frameIndexvisible 属性来控制切帧的显示与隐藏,不需要每次切帧时重新请求点云数据。
  • 内存优化:同一时间只渲染一个区域的点云,避免显存爆炸。

因此,你在浏览器中看到的只是一开始加载的 0.pcd,但它已经包含了所有的帧数据。切换帧只是修改每个点的可见性,而切换区域才会触发新的 .pcd 文件请求。


三、rangeJSON 的定义和获取

为了实现上述的按需加载和切帧操作,rangeJSON 作为配置信息被用来存储分片的具体信息,并且能够在前端通过 range.json 动态获取。

1. 获取 range.json

const baseURL = 'oss://path/to/pcds_for_label/';
const rangeUrl = baseURL + 'range.json';
const rangeJSON = await fetch(rangeUrl).json();

2. rangeJSON 数据结构

rangeJSON 包含了每个分片的空间范围、点云数量以及帧数等信息:

{
  "0": {
    "range": [x1, y1, x2, y2],
    "final_pcds_num": 10000,
    "final_extra_pcds_num": 5000,
    "num_not_in_overlap": 2000
  },
  "1": { ... },
  "frames": 50,
  "pcds_ds_mode": "split",
  "sam_version": "v1.0",
  "psam_version": "v2.0",
  "instance_skip_threshold": 10
}

3. 判断是否有多个分片

通过解析 rangeJSON 中的分片索引,判断是否有多个区域分片。

const shardIndices = Object.keys(rangeJSON)
  .map(key => +key)
  .filter(key => !Number.isNaN(key)); // [0, 1, 2, ...]

// 如果只有 0,说明只有一个区域
// 如果有 [0, 1, 2],说明有多个区域分片

4. 你的情况

如果你只看到 0.pcd 的请求,说明整个点云任务只有一个区域:

rangeJSON = {
  "0": {
    "range": [...],
    "final_pcds_num": 10000,
    "final_extra_pcds_num": 5000,
    "num_not_in_overlap": 2000
  },
  "frames": 50,
  "pcds_ds_mode": "split"
}

这意味着:

  • 只有一个分片,没有其他区域分片(如 1.pcd, 2.pcd 等)
  • 所有点云数据都在 0.pcd 中,包含了所有50帧的数据
  • 切帧操作只是通过修改点的 visible 属性来控制显示哪些帧的数据
  • 不需要切换区域,因此也不会有额外的请求

四、总结

通过空间分片和4D融合点云的策略,我们成功地将超大点云数据切分成多个区域,按需加载分片并进行时间轴控制。通过这种方式,我们既能有效地管理大规模的点云数据,又能提供流畅的用户体验,同时确保内存和网络带宽的高效利用。

在你看到的任务中,只有一个区域(0.pcd),所有数据都在其中,切换帧时无需重新请求点云文件。