跳到正文
世傲命的技术观测站 PERSONAL TECHNOLOGY OBSERVATORY
文章 项目复盘 2026-08

在 RTX GPU 上把一段视频跑成可浏览点云:LingBot-Map 从部署到 Workbench 的工程复盘

从 Windows/WSL2 部署 LingBot-Map、HEVC 视频推理和原始 Viewer,到加权体素融合与 Potree Workbench 的完整工程复盘,附真实点云 GIF、平台自检图和验收边界。

这篇文章记录的是一条完整的工程路径:先把 LingBot-Map 原项目在 Windows + WSL2 + RTX GPU 上跑起来,用一段真实竖屏视频得到原始空间点云;再把一次性 Viewer 演进为可上传、可排队、可融合、可下载、可在网页自由查看的本机 Workbench。

首屏这段 GIF 来自保留的真实融合 LAZ:从 1,464,610 个最终点中确定性采样后做相机环绕。它证明浏览器可以围绕同一份实际点云浏览;它不是算法随时间增长的动画,也不证明厘米级精度或完整的语义建模。

真实融合 LAZ 点云的环绕 GIF,展示竖屏样例的空间扫描结果

8.4 秒竖屏 HEVC 样例,经 LingBot 推理和融合后得到的真实点云环绕预览。GIF 只改变相机视角,不改变点的位置或颜色。

先说边界:这台机器解决什么,不解决什么

目标是让一个本机用户把视频变成可检查、可下载的相对尺度点云。浏览器运行在 Windows,Python、GPU 模型和中间数据运行在 Ubuntu 22.04 WSL;浏览器只访问 localhost。首版没有账户、多租户、云存储、移动端、自动房间分割或厘米级测量。

场景坐标以 right-handed-y-up 发布,scaleStatusrelative。页面可显示相对高度,但不把单目视频重建包装成测量仪器。反光面、无纹理墙面和细薄结构仍然是需要更多样例验证的边界。

平台:把重计算留在 WSL ext4

最初的部署建议来自模型项目的 Python 3.10 / PyTorch 2.8 组合。后来环境中的 CUDA wheel 从 cu128 升到 cu129,因此文章不把某个 wheel 标签写成永恒配置。下面的图是本文复跑时刚执行的运行时自检:它记录当时真正可用的 WSL、GPU、驱动、Torch、CUDA、FlashInfer 与存储文件系统。

WSL 运行时自检终端图,展示 Ubuntu、RTX 5070 Ti、PyTorch、CUDA、FlashInfer 与 ext4 数据根

这是一张由实际命令输出制成的终端图。发布版本省略了私有绝对路径,但保留了版本和文件系统证据。

组件本次复跑自检
WSLUbuntu 22.04.2 LTS,WSL2 内核 6.18.33.2
GPUNVIDIA GeForce RTX 5070 Ti,驱动 595.79,16,303 MiB
Python3.10.12
PyTorch / torchvision2.8.0+cu129 / 0.23.0+cu129
CUDA 可用性True,CUDA 12.9
FlashInfer0.6.15.post1
数据根WSL ext4,而不是 /mnt/d

模型权重、抽出的帧、逐帧 evidence 和 Potree 文件都放在 WSL ext4。视频抽帧与 LOD 打包会创建大量小文件;把它们放到 Windows 挂载盘会让跨文件系统 I/O 成为明显瓶颈。Windows 保留浏览器和前端开发体验即可。

原项目的最短环境检查可以写成下面这样。实际安装前仍应以仓库 README 和当前 GPU 驱动为准。

Terminal window
# 在 WSL 中,而不是 Windows Python 中
python --version
nvidia-smi
python -c "import torch; print(torch.__version__, torch.cuda.is_available(), torch.version.cuda)"

成功信号不是“命令没有报错”,而是 Python 能看到 CUDA,nvidia-smi 能看到这张卡,并且模型虚拟环境位于 Linux 文件系统。Windows 侧曾经使用过 SDPA 路径,因为那里没有可用的 FlashInfer;WSL 侧则可以使用 FlashInfer。为了让本次原项目重放尽量少依赖额外后端,我显式使用了 --use_sdpa

从原项目开始:视频先变成一组方向正确的帧

LingBot-Map 的 demo.py 能把图像序列或视频推理成深度、相机与世界坐标点,并在 Viser 中打开交互 Viewer。它很适合判断“模型能不能在这台机器上跑”,但它不是作业系统:没有上传协议、持久状态、重试、融合产物或浏览器 LOD。

这次使用的是此前上传过的 8.4 秒、720×1280、HEVC、30 fps 竖屏样例。OpenCV 曾在同一 HEVC 文件上间歇性读出零帧,因此不把它作为唯一输入链路。先用 FFmpeg 在 WSL ext4 中固定抽帧,再旋转 90°,让相机与画面方向一致:

Terminal window
ffmpeg -i input.mp4 -vf "fps=10" -q:v 2 frames/%06d.jpg
python demo.py \
--model_path models/lingbot-map-long.pt \
--image_folder frames \
--rotate_clockwise_90 \
--camera_num_iterations 4 \
--use_sdpa \
--port 8085

本次复跑实际得到 84 帧,并在 http://localhost:8085 启动原项目 Viewer。下面是 84 帧、4 次相机优化的原始 Viser 视图截图。它是模型直接输出的点云观察面,因此会比融合结果更松散;这正是后续需要融合层的原因。

复跑日志中还出现了一条被内部捕获的 DINO 预训练路径警告;这不是把它忽略掉的理由。此处把 8085 监听成功和浏览器中实际渲染出的 Viser 点云作为通过依据,同时把该警告留作原项目环境待清理项,而不是把它包装成“零警告部署”。

原始 LingBot-Map Viser Viewer 复跑截图,显示未融合的真实空间点云

原始 Viewer 验证的是模型输出可被交互查看。右侧视频帧控制与左侧点云来自同一次本机复跑。

两段真实输入的原始推理记录

早期直接推理已经跑过两段 HEVC 视频;本文又重放了竖屏样例的完整 Viewer 链路。下表把模型纯推理记录和 Workbench 端到端融合结果分开,避免把两个不同的计时口径混在一起。

样例输入与抽帧直接模型记录峰值显存Workbench 融合结果
竖屏8.4 秒,720×1280,HEVC;FFmpeg 84 帧,顺时针旋转 90°约 12.1 秒约 13.37 GB12,792,528 observations → 1,464,610 点
横屏24.3 秒,1280×720,HEVC;10 fps 为 243 帧,无旋转4 次优化约 33.9 秒约 13.66 GB37,006,956 observations → 1,009,550 点

这些数字来自真实 GPU 运行记录。它们不等于“上传到网页直到可交互”的端到端时间;首个可交互小于 3 秒、默认视图 30 FPS、浏览器内存小于 512 MB 仍是待测验收目标。

为什么原始 Viewer 还不够:从一次推理到可用工作台

原始 Viser Viewer 解决了模型可视化,但用户还需要处理视频上传、输入异常、GPU 排队、长任务进度、断线恢复、场景下载和重复浏览。于是 Workbench 将一次命令拆成有状态的本地 job:FastAPI 提供接口,SQLite 保存状态,SSE 推送阶段与日志,单个常驻 GPU worker 按 FIFO 消费任务。

flowchart LR A["Windows 浏览器\n上传与浏览"] --> B["FastAPI\nSQLite + SSE"] B --> C["单 GPU FIFO Worker\nUbuntu WSL"] C --> D["FFmpeg 预检\n转码、旋转、抽帧"] D --> E["LingBot 推理\n深度、相机、RGB、置信度"] E --> F["分块加权体素融合"] F --> G["LAZ + Potree LOD\n可选 TSDF GLB"] G --> B B --> A

状态为 uploadingqueuedpreflightextractingreconstructingfusingpackagingreadyfailedcancelled。取消不会被伪装成失败,只有失败和取消的 job 可以重试。错误返回固定的 codestageretryableuserMessagediagnosticId;CUDA 栈和本地路径只留在诊断日志。

启动入口固定使用 WSL 项目虚拟环境,避免 Windows 临时 uv 解释器带来的 0x800700e8

Terminal window
.\scripts\workbench.ps1 start
.\scripts\workbench.ps1 status
.\scripts\workbench.ps1 stop

stop 只停止 Workbench,不执行 wsl --shutdown。此前出错命令的 Python 位于 uv 的临时构建缓存,临时目录清理后 Windows 无法再创建该进程;这个问题与 CUDA 或模型权重无关。

逐帧点为什么要融合:把重复观测收敛成权威点云

每一帧推理都会产生世界坐标点、RGB、置信度和相机信息。简单拼接会保留重复观测和深度噪声。Workbench 先按 Morton 顺序分块,再按最细体素累计 sumWeightweightedXYZweightedRGBobservationCountpositionVariancefirstFramelastFrame

xyz = Σ(weight_i × xyz_i) / Σ(weight_i)
rgb = Σ(weight_i × rgb_i) / Σ(weight_i)

最细融合层是唯一的权威结果;父级 LOD 从它派生。这样 LAZ 下载、Potree 浏览和统计数字不会各自做一次融合。竖屏样例的 observation 数下降 88.55%,横屏样例下降 97.27%,但这不是随机删点,而是将同一个细小体素中的多次观测收敛为一个带权重的代表点。

WorkBench 中的 raw preview,适合检查视频输入和逐帧推理是否跑偏

WorkBench 中的 fused points,RGB 和点数统计来自实际融合产物

原始预览最多约 200 万个确定性采样点,用于快速判断输入;权威融合点导出为压缩 LAZ,并由 PotreeConverter 2 打成网页 LOD。可选的 Open3D TSDF 表面单独导出为 GLB,失败只给警告,不阻塞已经成功的融合点云。

可选 clean surface 是独立 GLB,用于观察连续表面而不是替代大点云浏览

两个真实显示问题:白色点云与空间方向

白色不是没有颜色

横屏融合结果第一次在网页里几乎全白,但几何正确。检查 LAZ 后确认 RGB 字段还在,问题落在 Potree 材质的输入与输出颜色编码没有对齐。ViewerAdapter 在加载点云时令 outputColorEncodinginputColorEncoding 一致,恢复了真实 RGB。

颜色编码修复前,横屏点云有几何形状但 RGB 几乎发白

这个例子提醒我:截图中的“颜色丢失”不能直接归因于模型。应该先分层检查模型 RGB、导出字段、浏览器材质和显示器色彩链路。

方向不对时,不改写原始坐标

点云有时会像侧放在场景网格上。只旋转一个点云对象会让轨迹、GLB、边界和 fit view 不同步,因此修复放在显示层:以内容边界中心为 pivot,应用 T(center) × R(x,y,z) × T(-center)。点云、轨迹和可选 GLB 共用内容根节点,世界网格保持不动。

方向校正前,内容与场景网格的关系难以阅读

方向校正后,融合点云、轨迹与网格同步旋转

右侧面板提供 X/Y/Z 的 -180° 到 180° 滑杆、每轴 +90° 和重置。这是显示偏好,当前只保留在页面会话,不会改写原始场景或假装已经持久化为标定结果。

最终产物与当前验证边界

发布 manifest 为 point-scene/v1,其中声明坐标系、相对尺度、轨迹和三个 variant:

Variant用途主格式
raw-preview输入与逐帧推理核对确定性采样点云
fused-points浏览与下载的权威点云Potree LOD + 压缩 LAZ
clean-surface可选连续表面观察独立 GLB

已验证的事实包括:两段真实 HEVC 视频在 RTX GPU 上的模型运行、84 帧竖屏样例的原始 Viser Viewer 复跑、真实 LAZ/Potree/GLB 资产、网页三种 variant 切换、颜色修复、方向控制,以及前端的上传、SSE 恢复、取消重试、viewer dispose、键盘和 reduced-motion 自动化覆盖。

尚未形成正式基准的项目也明确保留:ready 后首个可交互时间、默认 30 FPS、浏览器内存和不同墙角/薄结构的 P95 几何误差。下一轮会用固定输入、同一浏览器和相同点预算记录这些数据,而不是以“能打开页面”代替性能结论。

这条链路现在有两层证据:原项目 Viewer 说明模型能从同一段视频生成可浏览点云;Workbench 的 LAZ、Potree、任务状态和融合统计说明这份结果能够被稳定地保存、重开、切换与下载。前者验证模型,后者把模型变成了可以实际使用的本机工具。

继续探索

展开系列路线

同类延伸

项目复盘

01 / 2
查看完整路线
  1. 01在 RTX GPU 上把一段视频跑成可浏览点云:LingBot-Map 从部署到 Workbench 的工程复盘当前
  2. 02Windows 通过 WSL2 部署 vLLM 的关键步骤
  • #LingBot-Map
  • #三维重建
  • #点云
  • #WSL2
  • #GPU 推理
  • #Potree
  • #React

COMMUNITY DISCUSSION

评论

使用 GitHub 账号登录后参与讨论,评论会同步到 GitHub Discussions。