采集 · SfM
这是用全景相机做三维重建的人几乎都会撞的一堵墙: 素材没问题、软件不报错,但重建就是不出来。 原因不在素材,在投影方式和相机内参。这一篇把两件事都讲清。
如果你正拿 360° 全景视频(或双鱼眼原片)直接喂给 COLMAP 做三维重建, 大概率会看到稀疏点云几乎为空,或者重建出来的位姿完全错乱。
两个原因,都很具体:
修好这两点之后,同一段素材的注册率从完全失败变成了 100%(30/30 帧)。素材一个字没改。
SfM(运动恢复结构)要成立,得先知道「这张图里的这个像素,对应空间中哪条光线」。 这个关系由相机模型定义。
COLMAP 支持的相机模型里,最常用的是针孔模型(PINHOLE)—— 它的假设是「直线投影」:空间中的直线在图像上仍然是直线。
而鱼眼镜头是非线性投影:为了把 200° 甚至更广的视野压进一个画面, 它把边缘强烈压缩。画面上的直线是弯的。
特征匹配阶段往往还能凑合(局部的纹理块仍然对得上), 但到了初始对三角化这一步就会失败 —— 因为算出来的两条光线根本不相交,或者交在荒谬的位置。
这就是「素材看着没问题、重建却出不来」的原因。 不是素材坏了,是模型选错了。
做法是把鱼眼画面重投影成透视投影(也叫平面投影、rectilinear)。 相当于「从这张 200° 的画面里,抠出一块符合直线投影的区域」。
我们用的视场角是 122° —— 这不是随便取的, 而是与常用航空摄影测量软件的配置保持一致。
用 ffmpeg 的 v360 滤镜可以做这件事:
# 双鱼眼 → 等距柱状(equirectangular)
ffmpeg -i input.mp4 -vf "v360=input=dfisheye:output=e:ih_fov=200:iv_fov=200" eq.mp4
# 等距柱状 → 122° 透视
ffmpeg -i eq.mp4 -vf "v360=input=e:output=flat:h_fov=122:v_fov=68" flat.mp4
如果相机原片本身已经是等距柱状(很多全景相机的标准输出格式), 可以直接做第二步。
注意:重投影会损失边缘分辨率。 122° 是从 200° 里"抠"出来的一块,所以最终成图的有效像素比原片少。 如果你的原片分辨率不够高,重投影后的清晰度可能不足以支撑重建 —— 这一点要在采集阶段就考虑到。
这是更隐蔽的一个坑,因为你不会收到任何错误提示。
COLMAP 在没有提供内参时,会用一个经验公式猜焦距。 这个猜法在「普通相机拍的照片」上大致可用, 但对重投影出来的透视画面,它的假设不成立。
焦距与视场角的关系是:
f = (W / 2) / tan(FOV / 2)
W = 图像宽度(像素)
FOV = 水平视场角
以我们处理的画面为例,宽度约 2048 像素、水平视场 122°:
f = (2048 / 2) / tan(122° / 2)
= 1024 / tan(61°)
≈ 1024 / 1.804
≈ 568 像素
而 COLMAP 的默认估计大致相当于 1.2 × 图像宽度,
也就是 2400 像素上下 —— 与实际值 差了约 4 倍。
焦距错 4 倍,等于告诉解算器"这个视角比实际窄得多", 位姿解算出来的结果自然完全对不上。
不要依赖自动估计。把焦距和主点显式算出来传进去:
colmap feature_extractor \
--database_path database.db \
--image_path images/ \
--ImageReader.camera_model PINHOLE \
--ImageReader.single_camera 1 \
--ImageReader.camera_params "568.0,568.0,1024.0,576.0"
camera_params 的四个值依次是
fx, fy, cx, cy(焦距 x、焦距 y、主点 x、主点 y)。
其中:
如果重投影时做了裁剪或偏移,主点位置要相应调整 —— 这一点容易被忽略,但会直接导致重建偏移。
同一段素材(65 秒全景视频),只改上面两点:
| 修复前 | 修复后 | |
|---|---|---|
| 投影方式 | 200° 双鱼眼直喂 | 122° 透视图 |
| 相机内参 | COLMAP 自动估计 | 显式计算并提供 |
| 相机模型 | — | PINHOLE |
| 注册率 | 失败(初始三角化不成立) | 100%(30/30 帧) |
上表结果来自同一段素材的两次处理,仅修改了投影方式与相机内参两项,其余参数完全一致。
用运动延时(hyperlapse)拍的素材,相邻帧之间已经走了很远, 重叠度不足,匹配会失败。我们按「每 N 帧取 1 帧」抽帧来控制间隔。
移动太快导致运动模糊、或者高光溢出,都会污染匹配。 我们在抽帧阶段就做质检(拉普拉斯方差判模糊、过曝像素占比), 不合格的帧直接剔掉并记录原因。
手持或慢速拍摄时会有大量几乎相同的帧,白白增加计算量。 用帧差阈值去重。
手持全景相机时,画面底部中央往往是手或杆子。 这些区域在相邻帧之间一直在动,会被匹配算法当成移动物体, 影响位姿解算。我们在底部区域加了遮罩。
用全景素材做三维重建,不要在相机模型上想当然。 先问自己两个问题:
① 画面的投影方式,和你告诉解算器的相机模型一致吗?
② 内参是你算出来的,还是软件猜的?
这两个问题的答案,往往就是"重建不出来"和"重建得很顺"的分界线。
我们做完整的实景重建管线 —— 从采集方案、位姿解算到浏览器渲染。 如果你手上有素材重建不出来,可以说说情况,我们看看是哪一环的问题。