光流与视频理解
光流(Optical Flow)描述的是连续两帧图像之间每个像素的运动向量——即”这个像素从第 t 帧的哪里移动到了第 t+1 帧”。光流是视频理解的基础:动作识别、视频跟踪、视频稳定都离不开它。从 FlowNet 到 RAFT,深度学习让光流估计精度大幅提升。前置阅读:CNN 卷积网络、RNN 与序列模型。
把光流想象成看雨夜车灯:
- 光流 = 每个雨滴(像素)在一瞬间移动了多远、往哪个方向。你看到的不是雨滴本身,而是它们划过的轨迹——这就是运动向量场。
- 稠密光流(Dense Optical Flow) = 图像中每个像素都有一个运动向量——像全覆盖的速度场。计算量大但信息完整。
- 稀疏光流(Sparse Optical Flow) = 只追踪几个关键点(如角点、车道线端点),计算更快——Lucas-Kanade 方法。适合实时应用。
视频理解就是在光流和外观信息的基础上理解”发生了什么”:
- 视频分类 = 看完一段视频后判断是什么活动(打篮球?做饭?)。
- 动作识别 = 更细粒度——具体是什么动作(投篮?三步上篮?扣篮?)。
- 目标跟踪 = 视频中同一物体在每一帧的位置——这辆车从画面左开到右。
光流估计的数学基础
Section titled “光流估计的数学基础”光流基于一个核心假设——亮度恒定假设(Brightness Constancy Assumption):同一个物体点在两帧之间的亮度不变。设点 (x, y) 在时间 dt 后移动到 (x+dx, y+dy),则:
其中 I(x, y, t) 是图像在位置 (x, y)、时刻 t 的亮度值。这个假设在实际中并不总是成立——光照变化、遮挡、阴影都会违反它,这也是光流估计本质上是一个”病态问题”(ill-posed problem,即信息不足,无法唯一确定解)的原因。
对亮度恒定等式做一阶泰勒展开(Taylor Expansion,用线性近似表示函数在某点附近的行为):
代入亮度恒定假设 :
两边除以 (令 为光流分量):
这就是经典的光流基本方程(Optical Flow Constraint Equation),其中:
Ix = ∂I/∂x:图像在 x 方向的空间梯度(spatial gradient,描述亮度在水平方向的变化率)Iy = ∂I/∂y:图像在 y 方向的空间梯度It = ∂I/∂t:图像在时间方向的时间梯度(temporal gradient,描述同位置亮度随时间的变化)u, v:待求的光流分量(水平和垂直方向的像素位移速度)
核心矛盾:一个方程,两个未知数 (u, v)——这就是孔径问题(Aperture Problem):通过一个小孔看一条运动中的直线,你只能感知到垂直于线方向的运动,平行于线方向的运动无法确定。因此需要额外约束。
Lucas-Kanade 方法(1981)
Section titled “Lucas-Kanade 方法(1981)”Lucas-Kanade 假设局部邻域内所有像素的光流相同(局部恒定假设)。在一个 k × k 窗口内,有 k² 个像素都满足光流方程,于是得到 k² 个方程、2 个未知数的超定方程组(overdetermined system,方程数多于未知数),用最小二乘法求解:
设窗口内有 个像素,每个像素 给出一个方程:
写成矩阵形式 ,其中:
最小二乘解:
只有当 可逆(即窗口内有足够纹理/梯度变化)时才有唯一解。纹理稀疏区域(如白墙) 奇异,光流无法确定——这就是 LK 方法需要”角点”或”纹理丰富区域”作为追踪点的原因。
Horn-Schunck 方法(1981)
Section titled “Horn-Schunck 方法(1981)”Horn-Schunck 假设全局光流场是平滑的(global smoothness),通过变分优化(variational optimization)求解。目标函数 = 数据项(亮度恒定约束)+ 平滑项(光流空间梯度小):
其中:
- 第一项 = 数据项,惩罚违反亮度恒定约束的程度
- 第二项 = 平滑项,惩罚光流场在空间上的剧烈变化
- = 平滑权重( 大→更平滑但可能过度模糊运动边界)
- = 光流分量在 x、y 方向的空间梯度
FlowNet:深度学习光流的开创者
Section titled “FlowNet:深度学习光流的开创者”FlowNet(2015)是深度学习光流的开创者,核心创新是将光流估计重新定义为端到端的像素级回归问题——输入两帧图像,直接输出每个像素的位移向量。不再依赖人工设计约束方程。
两种架构设计:
- FlowNetS(Simple):将两帧图像在通道维度直接拼接(6 通道输入:帧 1 的 RGB + 帧 2 的 RGB),送入一个编码器-解码器 CNN。编码器逐步提取多尺度特征并降低分辨率,解码器通过反卷积(transposed convolution)逐步恢复分辨率并融合高分辨率细节。简单但有效。
- FlowNetC(Correlated):采用双流架构——两帧分别经过独立的 CNN 特征提取器,然后在特征层计算**相关性(correlation)**来匹配两帧中对应的区域。相关性操作类似于卷积,但在特征图之间做块匹配(patch matching),显式编码了两帧间的运动对应关系。精度更高但计算量更大。
FlowNet 的训练依赖大规模合成数据——FlyingChairs 数据集(用随机背景图 + 3D 椅子模型 + 仿射变换生成),这是深度学习光流的标志性数据集。
RAFT:循环全对相关变换
Section titled “RAFT:循环全对相关变换”RAFT(Recurrent All-Pairs Field Transform, 2020)是当前光流 SOTA(State-of-the-Art,最优技术水平)的代表,架构由三个核心组件构成:
1. 特征提取器(Feature Encoder)
两个共享权重的 CNN 分别为帧 1 和帧 2 提取特征图。使用 ResNet 风格的骨干网络,输出 1/8 分辨率的特征图(256 维)。同时训练一个独立的上下文网络(Context Network),只从帧 1 提取特征用于初始化 GRU 的隐藏状态。
2. 全对相关体(All-Pairs Correlation Volume)
这是 RAFT 的核心创新。对于帧 1 特征图中的每个像素 i 和帧 2 特征图中的每个像素 j,计算它们的余弦相似度:
其中 是帧 1 在位置 的 256 维特征向量, 是帧 2 在位置 的 256 维特征向量。结果是一个 4D 张量:,例如 的图像 → 万个相关值。
为处理不同大小的运动,RAFT 构建了多尺度相关金字塔——对帧 2 维度做 2× 平均池化得到 4 个尺度。大运动在低分辨率匹配,小运动在高分辨率匹配。
3. GRU 循环更新器(ConvGRU Update Operator)
使用门控循环单元(GRU,Gated Recurrent Unit,一种轻量 RNN)迭代更新光流场。每次迭代:
输入到 GRU 的特征:
- 当前光流估计
- 从相关体中查找的值(以当前 flow 指向的位置为中心做局部相关体采样)
- 上下文特征
GRU 更新:
通常迭代 12-32 次,从粗糙逐步细化到精确。
RAFT 的循环优化思路使光流精度大幅提升,成为后续工作的基线。其成功的关键在于:(1) 全对相关体穷举了所有可能的运动匹配,不遗漏任何运动;(2) GRU 循环使得模型可以”逐步修正”初始估计,而非一步到位。
传统方法 vs 深度学习光流
Section titled “传统方法 vs 深度学习光流”光流估计经历了从经典数学方法到深度学习的完整演进:
| 维度 | 传统方法(LK / HS) | 深度学习(FlowNet / RAFT) |
|---|---|---|
| Lucas-Kanade(1981) | 假设局部邻域内光流恒定,解小窗口内的超定方程——稀疏光流标准方法 | — |
| Horn-Schunck(1981) | 假设全局光流场平滑,通过变分优化求解——稠密光流经典方法 | — |
| FlowNet(2015) | — | 首个用 CNN 端到端回归光流的开创性工作 |
| RAFT(2020) | — | 全对相关体 + GRU 循环优化,当前 SOTA |
| 计算速度 | 极快(无需 GPU),适合实时嵌入式 | RAFT 需 GPU,推理约 100ms/帧 |
| 精度 | 在纹理稀疏、大位移区域严重退化 | 在所有场景下大幅领先 |
| 参数依赖 | 无需训练,零参数 | 需要大规模光流标注数据(FlyingChairs 等) |
| 典型用途 | 实时追踪(视频稳定、AR)、特征点跟踪 | 精度优先(视频插帧、动作识别中间表示) |
实践选择:资源受限或只需追踪少数关键点时用 Lucas-Kanade(OpenCV 内置,一行调用);需要全像素精确光流时用 RAFT。详见传统方法 vs 深度学习。
视频分类与动作识别
Section titled “视频分类与动作识别”处理视频的核心挑战:如何同时建模空间信息(每帧画面内容)和时序信息(帧之间的关系)。
| 方法 | 时序建模方式 | 特点 |
|---|---|---|
| C3D | 3D 卷积同时在空间和时间维度滑动 | 3D CNN 开山之作 |
| I3D | 将 2D 预训练权重 inflate 到 3D | 利用 ImageNet 预训练,效果好 |
| Two-Stream | RGB 流 + 光流流双网络 | 光流显式编码运动信息 |
| SlowFast | 慢通路(低帧率)+ 快通路(高帧率) | 兼顾语义和快速运动 |
| TimeSformer | Transformer 时空注意力 | 无卷积,纯注意力建模 |
| VideoMAE | 视频 Masked Autoencoder 预训练 | 自监督学习,大数据有效 |
| MViT | 多尺度 Vision Transformer + 池化注意力 | 层级结构,视频理解 SOTA |
SlowFast Network(Facebook, 2019)的直觉:人的视觉系统有”what”通路(慢速、细节丰富)和”where/how”通路(快速、捕捉运动)。SlowFast 用两个分支模拟——慢通路低帧率高通道数(语义),快通路高帧率低通道数(运动),最后融合。具体参数:慢通路采样 8 帧、通道数 64;快通路采样 32 帧(4× 采样率)、通道数 16(1/4 通道),通过侧向连接(lateral connection)让快通路特征注入慢通路。
视频目标跟踪
Section titled “视频目标跟踪”跟踪(Tracking)= 在视频每一帧中持续定位目标。多目标跟踪(MOT, Multi-Object Tracking)的通用范式是 检测+关联:
- 检测:每帧用目标检测器(如 YOLO)得到目标框。
- 关联:把相邻帧的检测框匹配到同一个目标(轨迹)。
| 方法 | 关联策略 | 特点 |
|---|---|---|
| SORT | 卡尔曼滤波预测 + IoU 匹配 | 极简,速度快 |
| DeepSORT | 外观特征(ReID)+ 运动信息 | SORT 加入外观特征,鲁棒性大幅提升 |
| ByteTrack | 低分检测框也参与关联 | 不丢弃低置信度框,MOT SOTA |
| FairMOT | 检测+ReID 联合 | 单网络完成检测和特征提取 |
SORT 的核心算法:使用卡尔曼滤波(Kalman Filter)——一种递归估计器,通过预测+更新两步来估计目标的运动状态(位置、速度)。先用上一帧的状态预测当前帧的位置,再用检测器的观测结果修正预测。关联阶段用**匈牙利算法(Hungarian Algorithm)**做检测框与轨迹的二分图最优匹配,匹配代价是 IoU(交并比,Intersection over Union)。
ByteTrack 的创新:传统方法只保留高置信度检测框(分数 > 阈值),丢弃低分框。但低分框可能是真实目标被遮挡后的检测结果。ByteTrack 分两阶段关联——先用高分框与现有轨迹匹配,未匹配的轨迹再用低分框进行第二次匹配,有效减少了 ID 切换。
使用 OpenCV 做稀疏光流(Lucas-Kanade)
Section titled “使用 OpenCV 做稀疏光流(Lucas-Kanade)”import cv2import numpy as np
cap = cv2.VideoCapture("traffic.mp4")ret, old = cap.read()old_gray = cv2.cvtColor(old, cv2.COLOR_BGR2GRAY)# 用 Shi-Tomasi 检测角点作为追踪点(角点是有两个方向梯度变化的点,# LK 方法在此类纹理丰富区域才能可靠求解)p0 = cv2.goodFeaturesToTrack(old_gray, maxCorners=100, qualityLevel=0.3, minDistance=7)lk_params = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))# winSize=15: LK 局部窗口大小,越大越鲁棒但越模糊# maxLevel=2: 金字塔层数,处理大位移运动while True: ret, frame = cap.read() if not ret: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, gray, p0, None, **lk_params) good = p1[st == 1] # 成功追踪的点(st=1 表示成功) old_gray = gray.copy(); p0 = good.reshape(-1, 1, 2)使用 RAFT 做稠密光流(概念代码)
Section titled “使用 RAFT 做稠密光流(概念代码)”import torchfrom torchvision.models.optical_flow import raft_large # PyTorch 内置import torchvision.transforms.functional as Ffrom PIL import Image
model = raft_large(weights="DEFAULT").eval() # 加载预训练 RAFT# 读取连续两帧,尺寸需为 8 的倍数(RAFT 内部有 3 次下采样)img1 = torch.rand(1, 3, 480, 640) # 第 t 帧(实际应从图片读取并归一化到 [0,1])img2 = torch.rand(1, 3, 480, 640) # 第 t+1 帧
with torch.no_grad(): flows = model(img1, img2) # 返回多尺度光流预测(训练时用于中间监督) flow = flows[-1] # 取最高分辨率 (1, 2, 480, 640)# flow[:, 0] 是水平位移 dx,flow[:, 1] 是垂直位移 dy# 每个 (dx, dy) 向量描述了该像素从帧 1 到帧 2 的运动
# 可视化:用 HSV 色彩空间编码方向和大小# 色调(H) = 方向,饱和度(S) = 255,明度(V) = 归一化的位移大小RAFT 损失函数解析
Section titled “RAFT 损失函数解析”RAFT 训练时使用序列损失(sequence loss),对 GRU 每次迭代的预测都施加监督:
# RAFT 风格的序列损失(概念代码)def sequence_loss(flow_predictions, flow_gt, gamma=0.8): """ flow_predictions: GRU 每次迭代的光流预测列表 [flow_0, flow_1, ..., flow_N] flow_gt: 真实光流(ground truth) gamma: 指数衰减权重,越后面的迭代权重越大 """ N = len(flow_predictions) loss = 0 for i, pred in enumerate(flow_predictions): # 使用 L1 损失(比 L2 更鲁棒,对异常值不敏感) l1 = (pred - flow_gt).abs() # 指数加权:后期迭代权重更大(gamma^(N-1-i),i 越大权重越大) loss += gamma ** (N - 1 - i) * l1.mean() return loss训练技巧与实践要点
Section titled “训练技巧与实践要点”- 光流不是完美的:遮挡区域、光照突变、无纹理区域(白墙)的光流会不准确。使用光流作为中间表示时,要有容错机制。
- 稠密 vs 稀疏:稠密光流(RAFT)精度高但慢,适合离线分析;稀疏光流(LK)只追踪关键点,适合实时应用(如视频稳定、增强现实)。
- 视频分类的效率:不要逐帧送入 CNN(太慢)。高效策略:均匀采样 8-16 帧 → 3D CNN / SlowFast 编码 → 时序池化。Action Recognition 数据集(Kinetics-400)是标准评测基准。
- 跟踪的 ID Switch 问题:目标遮挡后重新出现时可能被分配新 ID。ByteTrack 的创新是把低置信度检测框也纳入匹配,减少 ID 切换。
- 光流可微化:RAFT 的光流估计是可微的,可以作为视频插帧、视频超分的可微中间模块——训练时梯度可以直接流过光流。
- RAFT 训练策略:
- 学习率调度:使用 OneCycleLR,最大学习率 0.0004(AdamW 优化器),先热身后衰减。
- 数据增强:颜色抖动(color jitter)、随机裁剪、随机翻转。翻转时光流的水平分量取反。
- 混合数据集训练:FlyingChairs → FlyingThings3D → Sintel → KITTI 的课程学习(curriculum learning)——先在简单的合成数据上学基础运动模式,再在复杂的真实数据上微调。
- 梯度裁剪:设为 1.0,防止 GRU 训练时梯度爆炸。
- 合成数据 → 真实数据的域适应:光流数据集多为合成数据(因为真实光流极难标注),直接迁移到真实场景会有域差距。常用方法包括:自监督学习(用前后向一致性约束)、微调(在少量真实标注上继续训练)。
最新进展(2024-2025)
Section titled “最新进展(2024-2025)”光流估计领域在 RAFT 之后持续进化,主要方向包括全局匹配、高效推理和通用化:
- GMFlow / GMFlow+(2022-2023):将光流重新表述为全局特征匹配问题——用 Transformer 做特征增强,然后在高分辨率上做 softmax 全局匹配,最后用 self-attention 做传播细化。GMFlow 在大位移运动上显著超越 RAFT,且无需循环迭代,推理更高效。核心思想是”先把匹配做对,再做亚像素细化”。
- SEA-RAFT(2024):对 RAFT 的关键改进——用**高斯混合分布(Mixture of Laplacians)**替代简单的 L1 损失来建模光流预测的不确定性,引入 MAE(Masked Autoencoder)预训练提升特征提取质量,并在更大数据集上训练。SEA-RAFT 在 Sintel 和 KITTI 基准上刷新了 SOTA,同时推理速度比 RAFT 快 2 倍。
- Universal Flow Models:2024-2025 年的趋势是训练通用光流模型——一个模型适应所有场景(室内/室外/合成/真实、大位移/小位移、透明物体/反射)。UniMatch 和 FlowFormer++ 通过更强的 Transformer 架构和多数据集联合训练实现了跨域泛化。
- 视频扩散模型中的光流:随着视频生成模型(如 Sora、Kling)的爆发,光流被用作视频扩散模型的条件信号和评估指标。2024 年的工作如 FlowDiff 探索了将光流与扩散过程融合,生成更时间一致的视频。
- 高效光流(移动端部署):FlowFormer-Lite 和 MobileFlow 针对移动端优化,在手机上实现实时高精度光流估计,支撑 AR/MR 场景的运动追踪。知识蒸馏(从 RAFT 蒸馏到小模型)是主要技术路线。
- 自监督光流:减少对合成标注数据的依赖。UPFlow 和 SMURF 利用前后向一致性约束(forward flow 和 backward flow 应该互为逆)、遮挡检测等自监督信号,让模型直接从无标注真实视频中学习光流。
- 视频稳定:手机拍视频时防抖——用光流估计全局运动,反向补偿,得到稳定画面。GoPro、大疆无人机的标配功能。
- 动作识别:安防监控中识别异常行为(打架、跌倒)、体育赛事自动剪辑精彩片段(如 NBA 自动生成集锦)。
- 自动驾驶运动分析:从摄像头序列中估计其他车辆和行人的运动方向和速度——光流是纯视觉方案的核心组件。
- 视频插帧与慢动作:用光流做中间帧插值(如 RIFE 模型),将 30fps 视频提升到 60fps/120fps 的丝滑慢动作。
- 视频压缩:用运动补偿(光流)减少帧间冗余——H.264/H.265 编码标准的核心思想。
- AR/MR 运动追踪:HoloLens、Quest 等设备用光流 + IMU 做视觉惯性里程计(VIO),实时追踪头部运动。
- 视频生成质量评估:2024 年视频生成模型(Sora 等)使用光流一致性来评估生成视频的时间连贯性——光流场的不连续处暴露了生成伪影。
典型类库与工具
Section titled “典型类库与工具”| 类库 | 语言 | 说明 |
|---|---|---|
| OpenCV (cv2.optflow) | Python/C++ | 经典光流算法:Farneback、Lucas-Kanade、DeepFlow |
| RAFT (torchvision) | Python | PyTorch 内置 RAFT 实现,预训练权重即用 |
| GMFlow | Python | 基于全局特征匹配的光流模型,擅长大位移运动 |
| FlowFormer | Python | Transformer 架构的光流模型,高性能通用光流 |
| MMAction2 | Python | 商汤开源的动作识别工具箱,含 SlowFast/I3D/TimeSformer |
| MMTracking | Python | 商汤开源的视频目标跟踪工具箱,含 DeepSORT/ByteTrack |
| ByteTrack | Python/C++ | 高效多目标跟踪,COCO MOT 挑战赛冠军方案 |
| SlowFast | Python | Facebook 开源的视频理解框架,SlowFast Network 原版实现 |
| RIFE | Python | 实时视频插帧模型,光流引导的中间帧生成 |
| 术语 | 英文 | 解释 |
|---|---|---|
| 光流 | Optical Flow | 连续两帧之间每个像素的运动向量场 |
| 稠密光流 | Dense Optical Flow | 图像中每个像素都有运动向量的光流 |
| 稀疏光流 | Sparse Optical Flow | 仅追踪少数关键点的运动 |
| 亮度恒定假设 | Brightness Constancy | 光流的基本假设:同一点的亮度在帧间不变 |
| 孔径问题 | Aperture Problem | 从局部窗口无法唯一确定运动方向的经典问题 |
| 相关体 | Correlation Volume | 两帧特征图所有位置对的相关性矩阵 |
| 卡尔曼滤波 | Kalman Filter | 利用预测+更新递归估计目标运动状态的经典算法 |
| 3D 卷积 | 3D Convolution | 在空间(H, W)和时间(T)三个维度同时滑动卷积 |
| 双流网络 | Two-Stream Network | 分别用 RGB 和光流输入两个网络 |
| SlowFast | SlowFast Network | 双帧率分支网络,兼顾语义和运动建模 |
| 多目标跟踪 | MOT (Multi-Object Tracking) | 在视频中同时跟踪多个目标的轨迹 |
| ReID | Re-Identification | 跨摄像头/跨帧重新识别同一目标的技术 |
| 运动补偿 | Motion Compensation | 用运动向量预测下一帧以减少数据量 |
| 全局匹配 | Global Matching | GMFlow 等方法在高分辨率上做 softmax 匹配的思路 |
- Dosovitskiy et al.,「FlowNet: Learning Optical Flow with Convolutional Networks」(ICCV 2015):深度学习光流开山论文,首次用 CNN 端到端回归光流。
- Teed & Deng,「RAFT: Recurrent All-Pairs Field Transform for Optical Flow」(ECCV 2020):RAFT 论文,循环优化 + 全对相关体,光流精度革命性提升。
- Xu et al.,「GMFlow: Learning Optical Flow via Global Matching」(CVPR 2022):将光流重新表述为全局匹配问题,用 Transformer 替代循环迭代,大位移运动显著提升。
- Feichtenhofer et al.,「SlowFast Networks for Video Recognition」(ICCV 2019):SlowFast 论文,双帧率分支设计,视频理解 SOTA。
- Wojke et al.,「Simple Online and Realtime Tracking with a Deep Association Metric」(IPIN 2017):DeepSORT 论文,在 SORT 基础上引入外观特征,多目标跟踪实用化。
- Zhang et al.,「ByteTrack: Multi-Object Tracking by Associating Every Detection Box」(ECCV 2022):ByteTrack 论文,利用低分检测框提升跟踪性能。
- Horn & Schunck,「Determining Optical Flow」(AI 1981):光流经典论文,提出全局平滑约束的变分光流方法,至今被引用超过 20000 次。
- Lucas & Kanade,「An Iterative Image Registration Technique」(1981):LK 方法原文,局部恒定假设的光流估计,稀疏光流的标准方法。
- SEA-RAFT,「Sealed-Area RAFT」(CVPR 2024):对 RAFT 的重大改进,混合损失 + MAE 预训练,在多个基准上刷新 SOTA。
- MMAction2 GitHub:
https://github.com/open-mmlab/mmaction2——最全面的视频理解工具箱,适合上手实践。