Optical Flow
光流将视频两帧之间每个像素的移动估计为运动矢量场。了解经典方法和深度学习方法、用途及 OpenCV 代码。
光流是两幅图像之间亮度模式呈现出的表观运动,这两幅图像通常是连续的视频帧。光流算法会估计第一帧中每个像素对应的二维位移向量 (dx, dy),该向量指向该像素所表示的内容在第二帧中出现的位置。这个结果称为光流场,它捕捉移动物体和摄像机本身产生的运动,使计算机视觉系统能够进行视频稳像、估计自运动、插帧和识别动作。光流衡量的是摄像机所看到的内容,而非真实的三维运动:一个完全均匀、原地旋转的球体不会产生光流,而移动的阴影会在没有任何实体发生运动的地方产生光流。
光流的估计方法#
大多数方法从亮度恒常性出发,即假设某个点移动时其强度保持不变。将其线性化后,每个像素会得到一个方程,Ix·u + Iy·v + It = 0,其中 Ix、Iy 和 It 分别是图像在 x、y 和时间方向上的导数,(u, v) 是未知的光流。一个方程无法确定两个未知数,这就是孔径问题:透过一个小窗口观察直线边缘时,只能测量垂直于边缘的运动。经典方法会加入第二个假设来解决这个问题:
- Lucas-Kanade 方法(1981 年):假设小窗口内的光流恒定,并用最小二乘法求解窗口中所有像素的方程。当窗口包含两个方向的梯度(例如角点)时,该方法效果良好,因此通常会在选定的特征点上以稀疏光流的方式运行。
- Horn-Schunck 方法(1981 年):假设光流场在整幅图像上平滑,并通过求解全局优化问题,为每个像素生成稠密光流。
这两种假设在大幅运动时都会失效,因此实际方法会在图像金字塔上由粗到细地估计光流;在图像金字塔中,全分辨率下 16 像素的运动在向下三层后相当于 2 像素的运动:
OpenCV 实现了用于稀疏点的金字塔 Lucas-Kanade 方法,以及 Gunnar Farnebäck 在 2003 年提出、用于稠密光流的多项式展开算法。下面的代码将随机纹理移动已知距离,并用稠密 Farnebäck 光流恢复运动:
import cv2
import numpy as np
# A smooth random texture, then the same texture moved 3 px right and 2 px down
rng = np.random.default_rng(0)
texture = cv2.GaussianBlur(rng.random((240, 320)), (0, 0), 3)
frame1 = cv2.normalize(texture, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
frame2 = np.roll(frame1, shift=(2, 3), axis=(0, 1))
# Dense Farneback optical flow: one (dx, dy) displacement vector for every pixel
flow = cv2.calcOpticalFlowFarneback(
frame1, frame2, None, pyr_scale=0.5, levels=3, winsize=15, iterations=3, poly_n=5, poly_sigma=1.2, flags=0
)
print(f"flow field shape: {flow.shape}")
print(f"median motion: dx={np.median(flow[..., 0]):.2f}, dy={np.median(flow[..., 1]):.2f} pixels")它会打印 flow field shape: (240, 320, 2) 和 median motion: dx=3.00, dy=2.00 pixels:为 76,800 个像素中的每个像素生成一个二维向量,并恢复出水平 3 像素、垂直 2 像素的位移。
深度学习方法#
FlowNet 在 2015 年证明,卷积神经网络可以从合成训练数据中端到端地学习光流,因为真实视频很少附带光流真值。PWC-Net 将经典方法中的金字塔、扭曲和代价体思路整合进一个紧凑的网络中。RAFT 获得了 ECCV 2020 最佳论文奖,它会在相关性体中比较第一帧的每个像素与第二帧的每个像素,并通过反复进行循环更新来优化单个高分辨率光流场。学习型方法在处理大位移、运动模糊和无纹理区域时,远胜经典方法,而且 torchvision 提供预训练的 RAFT 模型。准确度通常用端点误差 (EPE) 表示,即预测光流向量与真实光流向量之间的平均像素距离,并在 MPI Sintel 和 KITTI 2015 等基准上进行评估。
光流与相关术语的区别#
- 目标跟踪:在多帧中使用持久 ID 跟踪完整目标,而光流描述两帧之间逐像素的运动,并不理解目标。跟踪器会将光流作为线索:在 Ultralytics YOLO 的跟踪模式中,默认的 TrackTrack 跟踪器和 BoT-SORT 会用稀疏 Lucas-Kanade 光流 (
gmc_method: sparseOptFlow) 估计摄像机运动,在半分辨率帧中跟踪最多 400 个角点,用 RANSAC 拟合旋转、缩放和平移,然后在将每个预测跟踪框与新检测结果匹配前,按该运动对其进行偏移。 - 点跟踪:在较长的视频中跟踪选定的点,包括点被遮挡的情况,而不是估计两帧之间每个像素的运动。
- 场景流:空间中各点的三维运动,通过立体视觉或深度数据估计。光流是场景流在图像平面上的投影。
- 视频编解码器运动向量:H.264、HEVC 和 AV1 编码器会为每个块存储一个运动向量,以尽量减少编码帧所需的比特数,因此运动向量往往与真实运动不同。










