TT Lab
博客

한국어 English 日本語 中文

开始
博客

博客

光流与 RAFT:用像素解读运动 —— 比较所有像素对,重复相同的更新

状态:草稿(2026-10-13),部分实测。 论文中的数值已对照原文及条件进行了确认。亲自尝试的内容为笔记本电脑 CPU 上的 numpy 示例(code/05_flow_toy.py,不到 1 秒)。乒乓球视频的光流实测(Farneback)是代码库 docs/tt/PERFORMANCE.md 2.9.7 中的数值,RAFT 尚未在我们的视频中运行(未实测)。 系列《阅读视觉模型 2》第 5 篇。从这里开始探讨“运动”。下一篇: 视频模型.

目录

1. 直觉:每个像素一个箭头

重叠查看视频的两帧时,移动的部分会错开,静止的部分会重合。 光流是一张图,它为第一帧的每一个像素附上了一个箭头(水平移动 u,垂直移动 v),表示“它在下一帧去了哪里”。对于 1080p 的帧,大约有 200 万个箭头。

光流不说明“什么”在运动,只说明“哪里”以及“移动了多少”。因此,它在不认识物体的情况下也能使用。在乒乓球视频中,仅凭光流的大小就能很好地区分选手大幅移动的区间(拉力赛中)和徘徊的区间(拉力赛之间)。

2. 经典方法的假设及其局限

经典方法从两个假设出发。

  1. 亮度保持不变。 即使一个点移动了,该点的亮度也不会变:I₁(x, y) = I₂(x+u, y+v)。
  2. 运动很小。 因此可以对右侧进行一阶泰勒展开:I_x·u + I_y·v + I_t ≈ 0。

方程只有一个,但未知数有两个(u, v)。Lucas–Kanade(1981)假设“小窗口内的像素是一起运动的”,从而收集窗口内的方程并用最小二乘法求解。

这种方法在三个地方会失效。

3. 学习模型的正确答案从何而来

无法在照片上手工标注每个像素的正确箭头。因此,基于学习的光流从 合成数据开始。FlowNet(2015)在照片背景上渲染并贴上了 809 种 3D 椅子模型,通过仿射变换移动,制作出了 Flying Chairs(22,872 对)。由于运动是人工制造的,正确答案是确切已知的(论文)。此后,延续到更加逼真的 FlyingThings3D、从动画电影中提取的 Sintel、以及汽车街景 KITTI 的训练顺序成为了标准。

损失函数通常是 端点误差(EPE, End-Point Error) 。它对预测箭头末端与真实箭头末端之间的距离(像素)求平均值。

4. 图解:RAFT

RAFT: 모든 짝을 한 번 비교, 같은 갱신을 반복 프레임 1 프레임 2 특징 인코더 ⅛ 해상도 두 프레임 공유 상관 부피(4차원) 4단 반복(학습 12번, 평가 24–32번) 지금 추정 둘레 반경 4칸 조회 4단 모두 합성곱 GRU 가중치 공유 추정 += Δ ⅛ 해상도 흐름 손실: 매 반복의 추정을 정답과 L1 로 비교 뒤 반복일수록 무겁게, 가중 0.8^(N−i) 마지막: 볼록 결합 업샘플링 이웃 3×3 의 가중 평균(가중치도 학습)으로 원래 해상도로
图解:RAFT:特征 → 4维相关体 → 半径查找 → 重复权重共享 GRU

RAFT(Teed & Deng, ECCV 2020)由三个部分组成。

  1. 特征编码器。 将两帧输入同一个 CNN 中,提取 ⅛ 分辨率的特征(256维)。由于比较的是特征而不是亮度,“亮度保持不变”的假设就被放宽了。
  2. 所有像素对的相关体(all-pairs correlation volume)。 一次性计算第一帧所有位置与第二帧所有位置之间的内积,并将其置于 4 维表(H×W×H×W)中。然后,通过对后两个维度进行 1、2、4、8 步池化,构建 4 层金字塔。计算一次便大功告成。
  3. 迭代更新器。 在 4 层金字塔中查找当前光流估计所指示位置周围半径 4 格的所有内容,将这些值输入卷积 GRU 中,得出“应修正估计多少”(Δ)。在训练时重复使用相同权重的 GRU 12 次,在评估时在 Sintel 上重复 32 次、在 KITTI 上重复 24 次。论文记录称,即使运行多达 200 次也不会发散。

与以往将金字塔用作“从粗糙分辨率求解并向下细化到精细分辨率”的分阶段结构(如 PWC-Net 等)不同,RAFT 从单一的 ⅛ 分辨率就已经知道了所有距离的像素对,因此从一开始就能看到快速大幅移动的物体。

5. 如何进行训练

L = Σᵢ γ^(N−i) · ‖ fᵢ − f_정답 ‖₁,   γ = 0.8,  N = 반복 횟수

对所有迭代的输出施加损失,越是后面的迭代权重越大(论文)。这意味着初期的迭代可以犯大错,但必须逐渐变得正确。由于这种损失,GRU 学到的不是“一次性猜对”,而是“一点点修正”。

当把 ⅛ 分辨率的光流放大到原始分辨率时,不使用简单的插值,而是用网络学到的权重计算相邻 3×3 格的加权平均值(凸组合上采样)。这是为了防止光流在物体边界处模糊。

训练顺序是从头开始(无预训练):Flying Chairs 10 万步 → FlyingThings 10 万步 → 混合 Sintel、KITTI 等 10 万步 → KITTI 5 万步,并使用两张桌面级 GPU 进行训练(论文)。

6. 动手尝试

code/05_flow_toy.py 仅使用 numpy 模拟了 RAFT 的两种思路。

  1. 将带有平滑纹理的 64×64 图像平移 (3.4, −2.2) 像素来创建第二帧(由于采用傅里叶平移,小数点后的移动也很精确)。
  2. 以每个像素周围 5×5 的图块作为特征,一次性计算两帧 所有像素对的相似度,形成一个 4,096×4,096 = 1,680 万格的表格(相关体)。
  3. 在出发点 (0, 0) 周围半径 8 格的范围内挑选最相似的位置(查找)。精度仅达到整数单位。
  4. 从该估计出发,重复“按照当前估计将第二帧复原,并用剩余的亮度差除以梯度进行修正”。RAFT 的 GRU 通过 学习 来完成的工作,这里用 Lucas–Kanade 方程的 手写 规则代替了。
[무늬 있는 그림] 상관 부피 4,096×4,096 = 16.8M 칸
  반경 안 argmax(정수) 추정: EPE 평균 0.6546px · 중앙 0.4472px, 가장 흔한 값 (3, -2)
  갱신 1회: EPE 평균 0.1649px · 중앙 0.0414px
  갱신 2회: EPE 평균 0.1726px · 중앙 0.0602px
  갱신 5회: EPE 평균 0.1593px · 중앙 0.0499px

仅通过比较所有像素对只能达到整数 (3, −2),误差中位数为 0.45px(真实值 3.4, −2.2 与整数之间的距离)。经过一次更新后降到了 0.04px。之后没有继续减小的原因是手写规则的局限性(复原时使用的双线性插值的误差)。这就是 RAFT 训练 GRU 的原因。如果从数据而不是规则中学习“修正多少”,就能把插值误差或遮挡等情况也考虑进去。

我们在竖条纹上尝试了同样的操作。

[세로줄(구경 문제)]
  반경 안 argmax(정수) 추정: EPE 평균 7.5758px, 가장 흔한 값 (-4, 0)
  갱신 1–5회: 변화 없음 (식이 풀리지 않는 화소 100.0%)
  → 가로 움직임 중앙값 -4.00(참값 3.4), 세로 움직임은 17가지 값으로 흩어짐

由于竖条纹上下移动时看起来完全一样,因此无法知晓垂直方向的运动(分散在 17 个值中)。水平方向由于条纹间距为 8 个像素,3.4 和 3.4−8 = −4.6 无法区分(选择了最近的整数 −4)。更新方程根本无法求解。这就是用数字观察到的孔径问题。在这种情况下,学习模型也只能根据周围的上下文(物体边界、其他部分的运动)进行猜测。

7. 论文数值

模型 数值(论文) 条件
FlowNetS / FlowNetC(2015) Sintel final 测试 EPE 7.42 / 7.28 Flying Chairs 训练。在桌面级 GPU 上 0.08 / 0.15 秒
PWC-Net(2018) Sintel final 5.04, KITTI-15 Fl-all 9.60%, 参数量 875 万 在 1024×436 下约 35fps(桌面级 GPU)
RAFT(2020) Sintel clean/final 1.94/3.18(两帧), 1.61/2.86(以前向光流初始化), KITTI-15 Fl-all 5.10% 参数量 530 万(小版本 100 万)。在 1088×436 下 10 次迭代 0.10 秒(桌面级 GPU),1080p 12 次 550ms
RAFT,仅用合成数据 Sintel 训练集 clean 1.43 · final 2.71, KITTI-15 EPE 5.04 · Fl-all 17.4% 仅训练 Chairs → Things 并在其他数据上直接应用
SEA-RAFT(2024) Spring 基准测试 1px 错误率 3.686, EPE 0.363 迭代 4 次(训练)· 4–12 次(推理),在 540×960 下 RAFT 140.7ms 对比 70.96ms(桌面级 GPU)

Fl-all 是端点误差同时超过 3 个像素且超过真实大小 5% 的像素比例。越低越好。

SEA-RAFT 将 RAFT 的损失改为了“两个拉普拉斯分布混合的负对数似然”。对于容易猜对的像素像 L1 一样处理,而对于本来就很模糊的像素(遮挡、孔径问题),则让网络自身输出不确定度,以减少误差惩罚。它直接回归初始估计而不是从 0 开始,从而减少了迭代次数(论文)。

8. 局限性

9. 与我们项目的联系

小蒂提示。 如果条纹衬衫上下移动,计算机并不知道它移动了。真的,我们通过示例亲自验证过。因此,光流用于“大致了解哪里移动了多少”,而球则需要单独寻找。

参考文献

登录后即可点赞

评论

还没有评论。

登录后即可发表评论