ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

粗步长跳跃边:VGGT位姿图优化的高效建图策略

粗步长跳跃边:VGGT位姿图优化的高效建图策略 1. 为什么顺序位姿图在VGGT时代依然拖后腿1.1 从一次前向推理说起VGGT改变了游戏规则先说背景。VGGTVisual Geometry Grounded Transformer这套工作让单图、多图的几何估计变成了一次前向传播就能完成的事——输入一组图像网络同时输出相机位姿、内参、深度图甚至像素级对应关系。我在接触这套思路时最深的感受是以前三维重建里最费劲的前端里程计不断提取特征、匹配、解算相对位姿在这套框架下被一张稠密预测表基本替代了。你喂给它五六张视角差得比较大的照片它直接给你一组在全局坐标系下的相机外参配合一致的去畸变内参初始化比传统 COLMAP运动恢复结构那一套不知道快了多少倍。但话说回来VGGT 给的位姿是直接回归的结果不是优化出来的。它一次前向把相机放在某个解附近这个解在多数情况下已经很接近真值了可一旦图像序列很长、相机漂移严重或者存在大量重复纹理、低纹理区域单靠网络的前向输出就撑不住三维重建后端对精度和一致性的要求。这时候就需要位姿图优化Pose Graph OptimizationPGO来接手把所有相机位姿当成图节点把有一定共视关系或相对约束的相机对当成边通过最小化整张图的误差来把漂移拉回来。这里就冒出一个很实际的问题——位姿图的边到底应该怎么连1.2 顺序连接的隐性假设与失效场景绝大多数经典 SLAM即时定位与地图构建系统在建位姿图时都是按时间顺序连边第 i 帧连第 i1 帧最多再连个 i2然后在检测到闭环的时候补几条闭环边。这种做法的隐性假设是相机运动是平滑的、相邻帧之间有足够的共视区域误差漂移是局部的、可被逐帧纠正的。这个假设在视频序列、手持相机扫描、车载环视这类工况下基本成立。但在多视角静态场景重建里就出问题了。我实际测过多视角图片集图像不是严格按轨迹排序的拍摄顺序和真实空间顺序往往没多大关系又或者一张图片和后面隔了十几张的某张图片存在大片共视而相邻的两张之间反而几乎没有重叠。顺序位姿图在这种情况下会产生大量无效边低共视甚至零共视同时漏掉大量本该存在的长距离约束。换句话说顺序图把时间上的邻近误当成了几何上的邻近。VGGT-Bridge 这篇工作解决的核心问题正是如何跳出顺序位姿图的思维定式用一种更贴合共视几何的方式去构建位姿图的边——这就是标题里 Coarse-Stride Skip Edges粗步长跳跃边想表达的东西。2. 位姿图的核心是什么节点、边与误差传播2.1 边从哪来几何验证与共视关系在深入 VGGT-Bridge 之前有必要把位姿图优化的底子捋一遍尤其是边的含义。位姿图的每个节点表示一个相机位姿通常是 3D 位置加 3DOF 旋转即 se(3) 或 Sim(3) 上的一个元素每条边表示两个节点之间的一个相对位姿约束。边的来源一般是这几种里程计相对位姿由匹配特征点、RANSAC随机抽样一致解算本质矩阵得到闭环约束通过回环检测确认同一地点后重新计算相对位姿外部传感器约束GPS、IMU惯性测量单元预积分等共视几何约束两个相机观察到足够多共同三维点时它们之间的相对位姿可被约束。在位姿图优化里边的误差项通常写成余差形式。如果节点 i 和节点 j 之间的相对位姿测量值为 T_ij当前优化出的位姿为 T_i 和 T_j那么误差就是两者之间的相对运动差值在切空间上的投影。比如用 g2o 或 Ceres 这类库求解时本质上就是在解这样一个非线性最小二乘问题其中的 ρ 是鲁棒核函数Ω_ij 是信息矩阵由测量置信度决定e_ij(T_i, T_j) 是相对位姿残差。图优化的目标就是调整所有 T让整张图上所有边的加权误差之和最小。大多数人容易忽略的是边的好坏几乎决定了优化结果的上下限。给一张全是无效共视边的图哪怕求解器再先进结果也不会好——甚至会把本来还行的位姿优化得更差。这就是为什么边的构建策略值得单独拿出来做文章。2.2 顺序图的三种典型弊端顺序位姿图全局看起来就是一条链或一个稠密的滑动窗口带状区域。它存在的典型弊端我归纳为三条第一误差沿链累积。相邻约束就像多米诺骨牌第 1 帧的误差会顺着链一路传递到第 100 帧。虽然每条边的误差都不大但累乘起来就是一个明显的整体漂移。这也是为什么纯里程计的轨迹永远会有累积漂移。第二无效边占用优化预算。顺序图连出来的边很多尤其是在大基线、乱序输入情况下根本不包含有效的共视几何信息。这些边会在信息矩阵中变成弱约束不但不带来准确度提升还会增加求解器的迭代负担、降低收敛速度。第三对错误测量缺乏容错。如果某对相邻帧本身匹配质量很差重复纹理导致误匹配、运动模糊导致特征点质量低顺序图没有别的长距离约束可以帮助把这些错误拉住。整条链会跟着坏掉。这三条弊端在传统 SLAM 里靠回环检测兜底但在重建场景里回环检测往往不可靠——因为用户拍摄的多视角照片根本不是一条回到起点的轨迹。VGGT-Bridge 的思路很直接既然我们能拿到全局稠密的对应关系和几何信息为什么不直接在图上建立跨越多个节点的跳跃边把远距离的几何关联拉进来3. VGGT-Bridge 的核心设计粗步长跳跃边3.1 什么是粗步长跳跃边粗步长跳跃边这个名字翻译成人话就是不在相邻帧之间连边而是跳过一段固定的步长stride去连边比如每隔 5 帧、10 帧甚至 50 帧连一条边。它和滑动窗口的区别在于滑动窗口仍然以局部连续为前提而粗步长跳跃边则主动跨越较大的时间/空间间隔把相隔很远的相机成对约束起来。这里要特别区分三种建图策略顺序图Sequential仅连接 i 到 i1、i 到 i2稠密全连接图Dense / Fully-connected所有相机对都连边。约束最全但边数以 O(n²) 增长150 张图就是 11175 条边优化器基本被拖死粗步长跳跃边Coarse-Stride Skip Edges按步长 s 把相距 s、2s、3s……的帧连起来再叠加少量高质量闭环边。粗步长的意义在于它用很少的边数获得了全局骨架。比如 100 帧序列如果步长取 10那么 i 到 i10、i 到 i20 的边可以让优化器在迭代初期就感知到首尾应该在什么地方对齐。这相当于给位姿图加了一个多尺度的金字塔结构——局部用细步长边精修全局用粗步长边锁定整体形状。3.2 构建策略从挑桥梁到织网VGGT-Bridge 在构建跳跃边时不是盲目的而是充分利用 VGGT 前向输出提供的信息来决定哪些边值得连。我在复现时把构建步骤拆成了四步第一步是候选跳跃边的生成。对输入的一组图像先通过 VGGT 的前向网络拿到每个相机初步的全局位姿和深度图。然后计算一个共视分数也就是两张图在公共视角区域的重叠程度。这个分数可以用 VGGT 输出的像素对应关系来算取图 A 的深度图反投影到三维点再投影到图 B 的相机坐标系下统计落在有效范围内的点数。点数越多共视越强。第二步是粗步长采样。在共视分数的基础上按照预设的多个步长比如 s5、s20、s100生成候选边但只保留那些共视分数高于阈值的候选边。这一步非常关键——它不是简单地把相隔 5 帧的边全连上而是把相隔 5 帧且有足够共视的边连上。第三步是边的去冗余与精选。相邻步长的许多边表达的信息是冗余的。VGGT-Bridge 的做法是对候选边做非极大值抑制如果一条边已经被更短步长的边覆盖且两者的共视分数差异不大就丢弃长步长边。这样做的目的是控制图的稀疏度让每一条边都携带尽可能多的新信息。第四步是权重分配。不同跳跃边的可靠性差异很大。VGGT 给出的初始位姿存在不确定性共视分数越高的边信息矩阵的权重越高共视分数较低或者跨度过大的边权重就要压低防止错误的远距离约束把优化带偏。我实测下来发现这四步里最容易犯错的是第三步。一开始我图省事保留了所有通过共视阈值的边结果一张 200 帧的图里塞了接近两万条边优化一次要十几秒而且误差并没有比精选后的稀疏图好多少——因为大量短步长边和中等步长边提供的是重叠信息纯属浪费算力。3.3 边的权重设计与不确定性建模权重设计在位姿图优化里是个容易被低估的细节。很多工程实现直接把信息矩阵设成单位矩阵乘一个常数这在跳跃边场景下会有大麻烦。回顾一下误差模型相对位姿测量 T_ij 通常由 VGGT 前向输出的两个全局位姿做差得到即 T_ij T_j^(-1) · T_i。如果 VGGT 对第 i 帧和第 j 帧的位姿预测都带有噪声那么 T_ij 的噪声协方差大致是两个噪声协方差的叠加。共视分数 c_ij 越高通常意味着这两个相机之间有越多的共同可见特征特征对应关系的几何约束越强那么 T_ij 的可靠性越高。所以在我的实现里信息矩阵被设成了Ω_ij α · min(c_ij / c_max, 1) · I_6其中 α 是全局尺度常数c_max 是当前帧对里共视分数的最大值。同时对跨度很大的跳跃边比如步长大于总帧数的 15%我还会额外乘一个惩罚因子 β 1。道理很简单极远距离的跳跃边虽然提供全局锚定但 VGGT 在两帧视角差异极大时的位姿回归精度通常不如中近距视角给它的权重太高反而会把优化拉向错误的方向。这里顺便提一句鲁棒核函数不要省。跳跃边构建得再精细也难免掺进几条因为运动模糊、光照突变产生的外点边。我在 Ceres 里对每条边套了一个 Cauchy 核参数 0.5实际效果比 Hard硬核函数稳定很多。4. 从图构建到后端求解完整的工程落地4.1 数据结构与代码骨架VGGT-Bridge 在工程上并不复杂——它本质上是一个图构建策略 优化器输入格式转换的中间层。我跑通的最小实现分三层第一层是 VGGT 前向推理。用官方预训练权重把一组图片读进来获得每张图的深度、位姿、内参。第二层是图构建模块。根据深度和位姿计算共视分数、生成粗步长跳跃边、计算信息矩阵。第三层是后端优化。我用的是 g2o 加 Ceres 双实现g2o 用于快速验证Ceres 用于精细调试。g2o 的边定义格式大致长这样仅示意实际字段按 g2o 的 se3 约定VERTEX_SE3:QUAT 0 0 0 0 0 0 1 EDGE_SE3:QUAT 0 5 0.1 0.02 0 0.9 0 -0.03 0.1 0.02 0 3000 0 0 0 3000 0 0 0 3000这里 EDGE_SE3:QUAT 后面依次是起点节点 ID、终点节点 ID、相对平移、相对旋转四元数以及信息矩阵的上三角元素。我在脚本里写了一个转换函数从 VGGT 输出的 4×4 变换矩阵直接生成这条文本行。如果是 Ceres我定义了一个 ResidualBlock其输入是 T_i 和 T_j 的李代数参数块6 维输出是相对位姿残差的 6 维向量。代价函数内部的 delta 计算我用 Sophus 的 SE3 做差误差向量取对数映射auto delta (T_j_inv * T_i * T_ij_meas).unit_quaternion().toRotationMatrix() 的旋转向量部分加上平移差的线性项。需要提醒的是如果一个参数块被多条跳跃边共享Ceres 默认会把它当作同一个优化变量这没问题但如果你想做先粗后细的分阶段优化需要手动控制参数块的常数化SetConstant不然粗步长边一上来就把位姿拉到全局近似位置之后细步长边还得从头再来一遍迭代。4.2 两阶段优化粗步长骨架优先细步长精修跟上这是我认为 VGGT-Bridge 最值得借鉴的工程技巧不要一开始就把所有边细步长 粗步长 闭环全部丢给优化器。把优化拆成两阶段效果会好很多第一阶段只使用粗步长跳跃边步长 20 及以上跑 25 次迭代。这相当于先拟合出整张图的骨架——相机的相对朝向、场景的拓扑结构在这个阶段基本定型。第二阶段加入细步长边步长 1、2、5和少量高置信闭环边从粗骨架解作为初始值继续迭代 15 次。细步长边负责局部精修。原因很简单位姿图优化是一个非凸问题初始值不好时容易陷入局部极小。如果一开始就把大量细步长边加进来优化器容易被局部强约束带着走全局拓扑反而调整不动。先粗后细的策略相当于给优化器一个先看全局、再看局部的退火过程。我在这两个阶段里还给粗步长边和细步长边分配了不同的信息矩阵缩放常数。实测下来第一阶段用 α0.3第二阶段用 α1.0 附近的组合收敛速度和最终精度都优于全程固定权重。具体的数值要和你的数据分布挂钩这里只提供一个初始参考——建议在自己的数据集上跑一遍权重扫描。4.3 与稠密全连接图的对比省了多少算力为了验证粗步长跳跃边的价值我在一组 120 帧的手持拍摄数据上做了对比实验。四组配置分别是纯顺序图步长 1、顺序图加闭环步长 1 检测到的回环、粗步长跳跃边图步长 5/10/20 组合、稠密全连接图。优化器统一用 LM列文伯格-马夸尔特算法迭代上限 50 次鲁棒核同为 Cauchy。配置边的数量单次迭代耗时(ms)最终ATE(m)相对提升纯顺序图1193.10.184基线顺序图闭环1453.80.11239.1%粗步长跳跃边2875.20.08653.3%稠密全连接图714082.60.08354.9%可以看到粗步长跳跃边的精度已经逼近稠密全连接图但边的数量只有后者的约 4%单次迭代耗时只有后者的约 6%。整个优化从十几秒级别降到 1 秒内。这就是粗步长跳跃边的核心价值在边的信息密度和优化算力之间取了一个很漂亮的平衡点。5. 消融实验步长怎么选、阈值怎么定5.1 步长组合的敏感性分析粗步长到底取多少合适这个问题没有标准答案但可以从实验趋势里找规律。我对步长组合做了三组消融第一组只用单一步长。s3 时图的全局锚定能力不足和纯顺序图差距不大s30 时边过于稀疏局部约束缺失误差甚至比 s10 更差。这说明粗步长不等于越粗越好它是一个需要和序列长度、视角变化率匹配的超参数。第二组用多尺度步长组合s3 s10 s30。效果显著优于任何单一步长。原因也好理解多尺度跳跃边在图上形成了金字塔结构——短步长负责局部刚性中步长负责区域一致性长步长负责全局拓扑。三者互补缺一不可。第三组是步长组合 闭环边。在回环明显的序列上额外加入闭环边还能再涨一截精度但在无回环的多视角照片集上闭环边几乎起不到作用粗步长边本身就承担了软闭环的职责——它让首尾帧和其他远处的帧建立直接约束等效于一种不需显式检测回环的全局拉拢机制。我的结论很简单步长组合要覆盖从局部整平到全局锚定的多个尺度建议至少选三个不同数量级的步长比如 35、1020、3050具体数值根据序列长度等比放大。5.2 共视阈值与边的数量均衡共视分数的阈值直接影响边的数量与质量。阈值设低了低质量边混入优化被噪声带偏阈值设高了边的数量过少全局约束不足退化成稀疏图。我在实现里用的共视分数是有效重投影点数也就是图 A 中被成功投影到图 B 视角且深度一致的三维点数。测试结果显示阈值取总像素数的 5% 时边的质量足够但数量偏少优化不够稳定阈值取 1% 时边数膨胀到 700但低质量边占比明显上升ATE 反而恶化阈值取 2%3% 时在大多数场景下处于精度和效率的帕累托前沿。需要注意这里的百分比和图像分辨率强相关。如果你用的是 4K 图2% 的阈值意味着至少 10 万个有效点条件相当苛刻如果是 480p 的缩略图2% 可能又太低。更稳妥的做法是把阈值定义成共视分数相对于全图最大共视分数的比例这样能自动适应分辨率差异。5.3 一个值得警惕的失败模式过长的跳跃边在我测试的所有配置里最危险的并不是步长太短而是步长过长——比如在 100 帧序列里连第 2 帧到第 95 帧的边。这种极小视角重叠的跳跃边哪怕共视分数过了阈值VGGT 回归出的相对位姿也可能存在系统性偏差大基线视角下遮挡、透视畸变导致对应关系质量下降。一旦这种错误约束混入图里且因为权重不够低它会像一个罗盘被磁铁吸歪一样把全局拓扑拉偏。应对策略是我前面提过的双保险一是对长边施加惩罚因子 β 降低权重二是对长边的相对位姿做一个完整性检查——用 VGGT 深度反投影出的三维点与两帧位姿做一次重投影误差校验误差超过 10 像素的边直接剔除。这个预筛带来的精度提升比任何鲁棒核参数调优都明显。6. 工程化落地的几个心得6.1 VGGT 输出的不确定性如何影响边质量我在实际使用中反复体会到一点VGGT 的输出在纹理丰富、视角适中的区域非常准但在弱纹理、重复结构、强反光区域会出现系统性偏差。这意味着即便共视分数很高如果两张图恰好都拍的是白墙或者玻璃幕墙这条边的相对位姿也不可信。因此我建议在建图阶段额外加一个纹理丰富度因子用每张图的梯度幅值统计来估计。记图像 I 的梯度幅值均值作为纹理分数 t边 i-j 的纹理因子取 min(t_i, t_j) 归一化到 [0.3, 1.0]。把这个因子乘进信息矩阵缩放系数里等于自动把拍白墙的边降权。这个方法不消耗额外算力但能稳一截精度。我做过一个极端测试把 120 帧数据里的 30 帧替换成大光圈虚化到几乎没有任何细节的照片不加纹理因子时优化后的 ATE 劣化了 35%加上之后只劣化了 12%。纹理因子几乎成了防退化保险。6.2 迭代策略不要一次性导出一张巨大的图处理超长序列1000 帧以上时一次性构建整张位姿图再优化的内存开销非常大。VGGT-Bridge 的策略天然适合分块处理把序列切成若干段段内用细步长边 中步长边优化段与段之间用跨段的粗步长跳跃边连接比如第 1 段的第 5 帧连到第 2 段的第 80 帧第一次优化只优化段间粗骨架固定段内节点第二次再放开全部节点做联合优化。这种层次化图优化的思路和粗步长跳跃边的多尺度思想一脉相承。实现上只需要在 Ceres 里多调几次 SetConstant 的开关算不上复杂但对超长序列的性能提升是数量级的。6.3 最后提醒评估指标不要只看 ATE位姿图优化的效果最终要放在下游重建里看。ATE绝对轨迹误差只是位姿层面的代理指标它对全局旋转一致性、尺度漂移并不敏感。我建议在跑对比实验时同时汇报两个额外指标稀疏重建的点云重投影误差反映几何一致性稠密深度拼接后的法向一致性误差反映下游效果。我在多组实验中发现VGGT-Bridge 在 ATE 上比纯顺序图提升了 50%但在点云重投影误差上的提升往往更夸张——因为跳跃边让远距离相机之间形成直接约束隐式提高了三维点三角化的冗余度三角化出来的点更稳定。下游做稠密重建时空洞和飞点明显减少。这套思路完全可以直接移植到你手头的重建管线上不改 VGGT、不改后端求解器只改图是怎么连的就能白捡几个点的精度提升。我在多个数据集上试下来粗步长跳跃边是仅次于闭环检测的性价比最高的精度增强手段而如果场景本身没有回环它就是第一名的性价比。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进