光流基础与视频分析 - 运动估计原理到实现
什么是光流 - 图像间的运动向量场
光流 (Optical Flow) 是描述图像序列中像素表观运动的 2D 向量场。对于每个像素,光流向量 (u, v) 表示该像素从一帧到下一帧的水平和垂直位移。
基本假设:
- 亮度恒常性: 物体移动时像素亮度不变。I(x,y,t) = I(x+u, y+v, t+1)
- 小位移: 帧间运动足够小,可用一阶泰勒展开近似
光流约束方程: 对亮度恒常性假设进行泰勒展开得到: Ix×u + Iy×v + It = 0,其中 Ix、Iy 是空间梯度,It 是时间梯度。一个方程两个未知数 (u,v),这就是著名的孔径问题 (Aperture Problem)。
稀疏光流 vs 稠密光流:
- 稀疏光流: 仅计算特征点 (角点) 的运动。速度快,适合目标跟踪
- 稠密光流: 计算每个像素的运动。信息完整,适合视频分析
应用领域: 视频稳定、动作识别、自动驾驶、视频插帧、运动分割、视频压缩 (MPEG 运动补偿)。
经典方法 - Lucas-Kanade 和 Horn-Schunck
两种经典光流方法通过不同的额外约束解决孔径问题,各有优缺点。
Lucas-Kanade (1981):
- 假设局部窗口 (如 15×15) 内所有像素具有相同运动
- 在窗口内建立超定方程组,最小二乘求解
- 稀疏光流方法,通常在角点处计算
- 金字塔 LK: 多尺度处理大位移。从粗到细逐级精修
- OpenCV:
cv2.calcOpticalFlowPyrLK(prev, next, points, None)
Horn-Schunck (1981):
- 全局方法,假设光流场整体平滑
- 最小化: 数据项 (亮度恒常性) + 平滑项 (光流梯度)
- 通过迭代求解产生稠密光流
- 平滑权重 α 控制平滑程度: α 大则光流平滑但细节丢失
Farneback 方法 (2003): 使用多项式展开近似每个像素邻域,计算稠密光流。OpenCV 默认的稠密光流方法: cv2.calcOpticalFlowFarneback(prev, next, None, 0.5, 3, 15, 3, 5, 1.2, 0)。速度和精度的良好平衡。
深度学习光流 - 从 FlowNet 到 RAFT
深度学习方法通过端到端训练大幅超越经典方法的精度,尤其在大位移和遮挡区域。
FlowNet (2015): 首个端到端光流 CNN。FlowNetS (单流) 和 FlowNetC (相关层) 两种架构。在合成数据 (Flying Chairs) 上训练。开创了学习光流的先河。
PWC-Net (2018): 金字塔、变形、代价体积的组合。多尺度特征金字塔,逐级变形和精修。参数量小 (8.75M),速度快。
RAFT (2020): 当前最先进的光流方法之一:
- 构建全对相关体积 (4D): 计算所有像素对的相似度
- GRU 迭代更新: 从初始零流开始,迭代精修光流估计
- 多尺度相关查找: 在不同分辨率的相关体积中查找
- Sintel 基准 EPE: 1.43 (clean), 2.71 (final)
最新进展:
- FlowFormer (2022): Transformer 编码代价体积,捕获全局上下文
- VideoFlow (2023): 利用多帧信息提升时间一致性
- UniMatch: 统一光流、立体匹配和深度估计的框架
光流应用 - 动作识别到视频编辑
光流作为视频理解的基础表示,在多个领域有广泛应用。
动作识别: 双流网络 (Two-Stream) 将 RGB 帧和光流作为两个输入流,融合空间和时间信息。光流流捕获运动模式,对动作分类贡献显著。TVL1 光流是常用的预计算方法。
视频插帧: 利用前后帧的光流,在中间时刻合成新帧。双向光流 + 变形 + 融合是标准流程。RIFE、IFRNet 等方法可实时将 30fps 视频转为 60/120fps。
视频稳定: 估计帧间全局运动 (仿射变换或单应性),补偿相机抖动。区分前景运动和相机运动是关键。
运动分割: 利用光流将独立运动的物体从背景中分离。光流幅度和方向的不连续性指示物体边界。
视频编辑:
- 光流引导的风格迁移: 保持时间一致性
- 视频修复: 利用光流从相邻帧传播信息填充缺失区域
- 慢动作生成: 光流插帧实现时间超分辨率
光流可视化与评估指标
光流的可视化和定量评估对于算法开发和调试至关重要。
颜色编码可视化: 标准方法使用 HSV 色轮: 色相 (H) 表示运动方向,饱和度 (S) 表示运动幅度。Middlebury 色轮是最常用的编码方案。OpenCV 实现: 将光流转换为极坐标 (幅度, 角度),映射到 HSV,再转 BGR 显示。
箭头可视化: 在图像上绘制运动向量箭头。适合稀疏光流或下采样后的稠密光流。箭头长度和方向直观表示运动。
评估指标:
- EPE (End-Point Error): 预测光流与真实光流的欧氏距离平均值。主要指标
- Fl-all: 误差超过 3 像素且超过 5% 的像素比例 (KITTI 指标)
- AE (Angular Error): 预测和真实光流向量的角度差
基准数据集:
- Sintel: 动画电影渲染的合成数据,有 clean 和 final (含运动模糊、雾) 两个版本
- KITTI: 真实驾驶场景,LiDAR 提供稀疏真值
- Flying Chairs/Things: 大规模合成训练数据
实现指南 - 使用 OpenCV 和 RAFT 进行运动估计
从 OpenCV 经典方法到 RAFT 深度学习方法的具体实现代码和部署指南。
OpenCV 稀疏光流 (Lucas-Kanade):
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)next_gray = cv2.cvtColor(next_frame, cv2.COLOR_BGR2GRAY)points = cv2.goodFeaturesToTrack(prev_gray, 100, 0.3, 7)new_points, status, err = cv2.calcOpticalFlowPyrLK(prev_gray, next_gray, points, None)
OpenCV 稠密光流 (Farneback):
flow = cv2.calcOpticalFlowFarneback(prev_gray, next_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)# flow.shape = (H, W, 2), flow[...,0]=水平, flow[...,1]=垂直
RAFT 部署:
- 安装:
pip install torch torchvision,克隆 RAFT 仓库 - 预训练模型: raft-things.pth (通用), raft-sintel.pth (动画风格)
- 推理: 输入两帧 RGB 图像,输出稠密光流场
- GPU 推理速度: 1080p 约 100-200ms (RTX 3090)
实时光流技巧: 降低输入分辨率 (1/2 或 1/4) 可大幅提速; 使用 RAFT-Small 变体; TensorRT 优化可提速 2-3 倍。对于实时应用,Farneback 在 CPU 上仍是实用选择。