光流估计与运动分析深度解析(Optical Flow  Motion Analysis) 目录光流基础理论经典光流方法深度学习光流RAFT 系列视频插帧运动估计与跟踪场景流评估指标与数据集应用与前沿术语速查表1. 光流基础理论1.1 什么是光流光流 (Optical Flow) 的定义: 图像中像素在相邻帧之间的位移向量场 设图像 I(x, y, t) 在时间 t 到 t1 之间: 像素 (x, y) 移动到 (x u, y v) 光流场: F (u, v) u: 水平位移 v: 垂直位移 ┌─────────────────────────────────────────────────────────────────┐ │ │ │ 帧 t 帧 t1 │ │ ┌──────────┐ ┌──────────┐ │ │ │ ●─────│──────────►│─────● │ │ │ │ (x,y) │ │ (xu,yv) │ │ │ │ │ │ │ │ └──────────┘ └──────────┘ │ │ │ │ 光流: F(x,y) (u, v) │ │ │ └─────────────────────────────────────────────────────────────────┘ 光流的含义: 描述了场景中物体的运动 是视频分析的基础1.2 光流约束方程光流约束方程 (Optical Flow Constraint Equation): 假设亮度恒定: I(x, y, t) I(x u, y v, t 1) 泰勒展开: I(x u, y v, t 1) ≈ I(x, y, t) I_x·u I_y·v I_t 代入恒定假设: I_x·u I_y·v I_t 0 或写成: ∇I · F I_t 0 其中: I_x ∂I/∂x: 水平梯度 I_y ∂I/∂y: 垂直梯度 I_t ∂I/∂t: 时间梯度 F (u, v): 光流 问题: 一个方程两个未知数 (u, v) 存在孔径问题 (Aperture Problem)1.3 孔径问题孔径问题 (Aperture Problem): 问题: 只能估计梯度方向上的运动分量 无法估计垂直于梯度方向的运动 ┌─────────────────────────────────────────────────────────────────┐ │ │ │ 孔径 (局部窗口): │ │ ┌─────────┐ │ │ │ ───── │ 只能看到水平边缘 │ │ │ │ 只能估计垂直运动 │ │ │ │ 无法估计水平运动 │ │ └─────────┘ │ │ │ │ 解决: 引入额外约束 │ │ 1. 平滑性约束 │ │ 2. 全局约束 │ │ 3. 特征匹配 │ │ │ └─────────────────────────────────────────────────────────────────┘1.4 光流的类型光流的类型: 1. 稀疏光流: 只计算特征点的运动 例: Lucas-Kanade 2. 稠密光流: 计算每个像素的运动 例: Horn-Schunck, RAFT 3. 半稠密光流: 计算部分像素的运动 例: 梯度较大的区域2. 经典光流方法2.1 Lucas-Kanade 方法论文: An Iterative Image Registration Technique with an Application to Stereo Vision (Lucas Kanade, 1981) 核心思想: 局部窗口内的运动是恒定的 在窗口内求解超定方程组 假设: 窗口内所有像素有相同的运动 (u, v) 对于窗口内的每个像素 i: I_x_i · u I_y_i · v I_t_i 0 写成矩阵形式: [I_x_1, I_y_1] [u] [-I_t_1] [I_x_2, I_y_2] [v] [-I_t_2] [ ..., ] [ ... ] 最小二乘解: [u, v]^T (A^T A)^{-1} A^T bimportnumpyasnpclassLucasKanade: Lucas-Kanade 光流 理论: 局部窗口内运动恒定 最小二乘求解 假设: 小运动 (线性化成立) 局部恒定运动 def__init__(self,window_size15,num_iterations3):self.window_sizewindow_size self.num_iterationsnum_iterationsdefcompute_flow(self,image1,image2,points): 计算稀疏光流 image1: [H, W] 帧1 image2: [H, W] 帧2 points: [N, 2] 特征点坐标 返回: [N, 2] 位移向量 # 计算梯度Ix,Iyself.compute_gradients(image1)Itimage2-image1 flows[]half_wself.window_size//2forx,yinpoints:x,yint(x),int(y)# 提取窗口Ix_winIx[y-half_w:yhalf_w1,x-half_w:xhalf_w1].flatten()Iy_winIy[y-half_w:yhalf_w1,x-half_w:xhalf_w1].flatten()It_winIt[y-half_w:yhalf_w1,x-half_w:xhalf_w1].flatten()# 构建方程组Anp.stack([Ix_win,Iy_win],axis1)b-It_win# 最小二乘解flownp.linalg.lstsq(A,b,rcondNone)[0]flows.append(flow)returnnp.array(flows)defcompute_gradients(self,image):计算图像梯度Ixnp.gradient(image,axis1)Iynp.gradient(image,axis0)returnIx,Iy Lucas-Kanade 的理论: 最小二乘解: [u, v]^T (A^T A)^{-1} A^T b 矩阵 A^T A 的特征值: λ₁, λ₂: 反映梯度分布 两个特征值都大: 角点 (可以估计两个方向) 一个大一个小: 边缘 (只能估计一个方向) 都小: 纹理 (无法估计) Shi-Tomasi 角点检测: min(λ₁, λ₂) threshold 选择好的特征点进行跟踪 2.2 Horn-Schunck 方法论文: Determining Optical Flow (Horn Schunck, 1981) 核心思想: 全局平滑性约束 假设光流场是平滑的 目标函数: E ∫∫ [(I_x·u I_y·v I_t)² α²(‖∇u‖² ‖∇v‖²)] dx dy 第一项: 光流约束 (数据项) 第二项: 平滑性约束 (正则项) α: 平滑权重classHornSchunck: Horn-Schunck 光流 理论: 全局平滑性约束 假设光流场是平滑的 目标函数: E (I_x·u I_y·v I_t)² α²(‖∇u‖² ‖∇v‖²) def__init__(self,alpha1.0,num_iterations100):self.alphaalpha self.num_iterationsnum_iterationsdefcompute_flow(self,image1,image2): 计算稠密光流 image1: [H, W] image2: [H, W] 返回: [H, W, 2] # 计算梯度Ix,Iyself.compute_gradients(image1)Itimage2-image1 H,Wimage1.shape unp.zeros((H,W))vnp.zeros((H,W))# 迭代求解for_inrange(self.num_iterations):# 邻域平均u_avgself.neighborhood_average(u)v_avgself.neighborhood_average(v)# 更新numeratorIx*u_avgIy*v_avgIt denominatorself.alpha**2Ix**2Iy**2uu_avg-Ix*numerator/denominator vv_avg-Iy*numerator/denominatorreturnnp.stack([u,v],axis-1)defneighborhood_average(self,f):邻域平均fromscipy.ndimageimportuniform_filterreturnuniform_filter(f,size3)defcompute_gradients(self,image):Ixnp.gradient(image,axis1)Iynp.gradient(image,axis0)returnIx,Iy Horn-Schunck 的迭代公式: u ū - Ix·(Ix·ū Iy·v̄ It) / (α² Ix² Iy²) v v̄ - Iy·(Ix·ū Iy·v̄ It) / (α² Ix² Iy²) 其中 ū, v̄ 是邻域平均 α 的作用: α 大: 更平滑 (全局运动) α 小: 更精确 (局部运动) 3. 深度学习光流3.1 FlowNet论文: FlowNet: Learning Optical Flow with Convolutional Networks (Fischer et al., 2015) 核心思想: 用 CNN 直接预测光流 输入: 两帧图像 输出: 光流场 架构: 1. FlowNetS: 简单拼接 2. FlowNetC: 相关层 (Correlation)importtorchimporttorch.nnasnnclassFlowNetS(nn.Module): FlowNetS (Simple) 理论: 直接拼接两帧图像 CNN 预测光流 输入: [B, 6, H, W] (两帧拼接) 输出: [B, 2, H, W] (光流) def__init__(self):super().__init__()# 编码器self.encodernn.Sequential(nn.Conv2d(6,64,7,stride2,padding3),nn.LeakyReLU(0.1),nn.Conv2d(64,128,5,stride2,padding2),nn.LeakyReLU(0.1),nn.Conv2d(128,256,5,stride2,padding2),nn.LeakyReLU(0.1),nn.Conv2d(256,256,3,stride1,padding1),nn.LeakyReLU(0.1),nn.Conv2d(256,512,3,stride2,padding1),nn.LeakyReLU(0.1),nn.Conv2d(512,512,3,stride1,padding1),nn.LeakyReLU(0.1),nn.Conv2d(512,1024,3,stride2,padding1),nn.LeakyReLU(0.1))# 解码器self.decodernn.Sequential(nn.ConvTranspose2d(1024,512,4,stride2,padding1),nn.LeakyReLU(0.1),nn.ConvTranspose2d(512,256,4,stride2,padding1),nn.LeakyReLU(0.1),nn.ConvTranspose2d(256,128,4,stride2,padding1),nn.LeakyReLU(0.1),nn.ConvTranspose2d(128,64,4,stride2,padding1),nn.LeakyReLU(0.1),nn.Conv2d(64,2,3,padding1))defforward(self,image1,image2): image1: [B, 3, H, W] image2: [B, 3, H, W] 返回: [B, 2, H, W] # 拼接xtorch.cat([image1,image2],dim1)# 编码featuresself.encoder(x)# 解码flowself.decoder(features)returnflow FlowNet 的理论: FlowNetS: 简单拼接 CNN 自动学习如何匹配 FlowNetC: 显式计算相关 更高效的匹配 两者都使用编码器-解码器结构 多尺度预测 3.2 RAFT论文: RAFT: Recurrent All-Pairs Field Transforms for Optical Flow (Teed Deng, 2020) 核心创新: 1. 全对相关: 计算所有像素对的相关 2. 迭代优化: GRU 迭代更新光流 3. 高精度: 超过之前所有方法 ┌─────────────────────────────────────────────────────────────────┐ │ │ │ RAFT 架构: │ │ │ │ 图像 → 特征提取 → 全对相关 → GRU 迭代 → 光流 │ │ │ │ 1. 特征提取: 提取两帧的特征 │ │ 2. 全对相关: 计算所有像素对的相关 │ │ 3. GRU 迭代: 迭代更新光流 │ │ 4. 上采样: 恢复原始分辨率 │ │ │ └─────────────────────────────────────────────────────────────────┘classRAFT(nn.Module): RAFT (Recurrent All-Pairs Field Transforms) 核心创新: 1. 全对相关: 计算所有像素对的相关 2. GRU 迭代: 迭代更新光流 3. 高精度 理论: 全对相关: 捕获所有可能的匹配 GRU 迭代: 逐步优化光流 def__init__(self,hidden_dim128,num_iterations12):super().__init__()self.hidden_dimhidden_dim self.num_iterationsnum_iterations# 特征提取器self.feature_encoderFeatureEncoder(output_dim256)self.context_encoderContextEncoder(output_dimhidden_dim)# 相关金字塔self.corr_pyramidCorrPyramid(num_levels4)# GRU 更新self.update_blockUpdateBlock(hidden_dimhidden_dim)defforward(self,image1,image2,itersNone): image1: [B, 3, H, W] image2: [B, 3, H, W] 返回: 光流列表 (每次迭代的光流) ifitersisNone:itersself.num_iterations# 特征提取fmap1self.feature_encoder(image1)fmap2self.feature_encoder(image2)# 上下文特征contextself.context_encoder(image1)# 全对相关corrself.compute_correlation(fmap1,fmap2)corr_pyramidself.corr_pyramid(corr)# 初始化光流B,_,H,Wfmap1.shape flowtorch.zeros(B,2,H,W,deviceimage1.device)# GRU 隐藏状态htorch.tanh(context[:,:self.hidden_dim])ccontext[:,self.hidden_dim:]# 迭代更新flow_list[]for_inrange(iters):# 查找相关corr_featuresself.lookup_correlation(corr_pyramid,flow)# GRU 更新h,delta_flowself.update_block(h,flow,corr_features)# 更新光流flowflowdelta_flow flow_list.append(flow)returnflow_listdefcompute_correlation(self,fmap1,fmap2): 计算全对相关 理论: 对于 fmap1 中的每个位置 计算与 fmap2 中所有位置的相关 C(i,j) fmap1[i] · fmap2[j] B,C,H,Wfmap1.shape fmap1fmap1.view(B,C,H*W)fmap2fmap2.view(B,C,H*W)corrtorch.bmm(fmap1.transpose(1,2),fmap2)corrcorr.view(B,H,W,H,W)returncorr RAFT 的理论优势: 1. 全对相关: 捕获所有可能的匹配 不受局部窗口限制 2. 迭代优化: 逐步优化光流 每次迭代可以修正错误 3. 高精度: 在多个基准上达到 SOTA 4. 视频插帧4.1 基于光流的插帧classFlowBasedInterpolation(nn.Module): 基于光流的视频插帧 理论: 1. 估计光流 2. 变形两帧到中间时刻 3. 融合得到中间帧 def__init__(self,flow_model):super().__init__()self.flow_modelflow_modeldefforward(self,frame1,frame2,t0.5): frame1: [B, 3, H, W] frame2: [B, 3, H, W] t: 插值时刻 (0-1) # 估计光流flow_forwardself.flow_model(frame1,frame2)flow_backwardself.flow_model(frame2,frame1)# 变形warped1self.warp(frame1,flow_forward*t)warped2self.warp(frame2,flow_backward*(1-t))# 融合weightt interpolatedweight*warped1(1-weight)*warped2returninterpolateddefwarp(self,image,flow):使用光流变形图像B,C,H,Wimage.shape# 生成网格grid_y,grid_xtorch.meshgrid(torch.arange(H),torch.arange(W),indexingij)gridtorch.stack([grid_x,grid_y],dim0).float()# 加上光流gridgridflow# 归一化到 [-1, 1]grid[:,0]2*grid[:,0]/(W-1)-1grid[:,1]2*grid[:,1]/(H-1)-1gridgrid.permute(0,2,3,1)# 双线性采样warpedF.grid_sample(image,grid,modebilinear,padding_modeborder,align_cornersTrue)returnwarped 基于光流插帧的问题: 1. 光流误差: 光流估计不准确 导致变形错误 2. 遮挡: 被遮挡的区域没有对应 需要特殊处理 3. 模糊: 变形后的融合可能模糊 5. 运动估计与跟踪5.1 特征跟踪classFeatureTracker: 特征跟踪器 使用光流跟踪特征点 理论: 检测特征点 使用光流跟踪 丢失的点重新检测 def__init__(self,detectorshi_tomasi):self.detectordetector self.pointsNonedefdetect(self,image):检测特征点importcv2 pointscv2.goodFeaturesToTrack(image,maxCorners100,qualityLevel0.01,minDistance10)returnpointsdeftrack(self,image1,image2):跟踪特征点importcv2ifself.pointsisNone:self.pointsself.detect(image1)# 光流跟踪new_points,status,_cv2.calcOpticalFlowPyrLK(image1,image2,self.points,None)# 保留成功跟踪的点good_maskstatus.flatten()1self.pointsnew_points[good_mask].reshape(-1,1,2)# 如果点太少重新检测iflen(self.points)50:new_detectionsself.detect(image2)ifnew_detectionsisnotNone:self.pointsnp.vstack([self.points,new_detections])returnself.points 特征跟踪的流程: 1. 检测: 在第一帧检测特征点 2. 跟踪: 使用光流跟踪到下一帧 3. 更新: 丢失的点重新检测 4. 重复: 持续跟踪 6. 场景流6.1 场景流概述场景流 (Scene Flow): 3D 空间中的运动场 与光流的区别: 光流: 2D 图像平面的运动 场景流: 3D 空间的运动 场景流 3D 位移向量场 F (u, v, w) u, v: 对应光流 w: 深度变化 应用: 1. 自动驾驶: 3D 运动估计 2. 机器人: 抓取运动规划 3. 3D 重建: 动态场景重建7. 评估指标与数据集7.1 评估指标┌─────────────────────────────────────────────────────────────────────┐ │ 光流评估指标 │ ├─────────────────┬───────────────────────────────────────────────────┤ │ 指标 │ 定义与说明 │ ├─────────────────┼───────────────────────────────────────────────────┤ │ EPE │ End-Point Error │ │ │ EPE ‖F_pred - F_gt‖₂ │ │ │ 预测光流与真实光流的欧氏距离 │ ├─────────────────┼───────────────────────────────────────────────────┤ │ AEE │ Average End-Point Error │ │ │ 所有像素的平均 EPE │ ├─────────────────┼───────────────────────────────────────────────────┤ │ Fl │ Flow Accuracy │ │ │ EPE 3 或 EPE 5% 的像素比例 │ └─────────────────┴───────────────────────────────────────────────────┘7.2 数据集┌─────────────────────────────────────────────────────────────────────┐ │ 光流数据集 │ ├─────────────────┬───────────────────────────────────────────────────┤ │ 数据集 │ 说明 │ ├─────────────────┼───────────────────────────────────────────────────┤ │ FlyingChairs │ 合成数据椅子在背景上移动 │ │ FlyingThings3D │ 合成 3D 场景 │ │ Sintel │ 合成电影场景高质量 │ │ KITTI │ 真实驾驶场景 │ │ Middlebury │ 室内场景高精度 │ └─────────────────┴───────────────────────────────────────────────────┘8. 应用与前沿8.1 应用领域光流与运动分析的应用: 1. 视频压缩: 利用运动信息压缩视频 只传输运动和残差 2. 视频稳定: 估计相机运动 补偿抖动 3. 动作识别: 运动信息识别动作 光流作为特征 4. 目标跟踪: 跟踪物体运动 光流辅助跟踪 5. 自动驾驶: 障碍物运动估计 碰撞预警 6. 视频插帧: 生成慢动作视频 提升视频帧率8.2 前沿方向光流与运动分析的前沿: 1. 实时光流: 高效模型 边缘设备部署 2. 高分辨率光流: 4K/8K 视频 大位移 3. 3D 场景流: 结合深度估计 3D 运动理解 4. 事件相机光流: 新型传感器 高时间分辨率9. 术语速查表术语英文定义光流Optical Flow像素在相邻帧之间的位移稠密光流Dense Flow每个像素的运动稀疏光流Sparse Flow特征点的运动场景流Scene Flow3D 空间的运动场孔径问题Aperture Problem局部无法确定完整运动亮度恒定Brightness Constancy光流的基本假设相关层Correlation Layer计算特征相似度迭代优化Iterative Refinement逐步优化光流视频插帧Frame Interpolation生成中间帧运动估计Motion Estimation估计物体运动附录A. 发展时间线1981 ──┬── Lucas-Kanade, Horn-Schunck │ 2003 ──┼── Farneback │ 2015 ──┼── FlowNet │ 2017 ──┼── FlowNet2 │ 2020 ──┼── RAFT │ 2023 ──┴── 光流基础模型B. 核心公式速查公式含义I_x·u I_y·v I_t 0光流约束方程[u,v]^T (A^T A)^{-1} A^T bLucas-Kanade 解C(i,j) f₁[i]·f₂[j]相关计算EPE ‖F_pred - F_gt‖₂端点误差