感知基础:光流

Views: --

对应 PPT:光流专题 前面四篇都在讲「怎么决策、怎么控制」,但有个前提一直被默认:机器人得先「看懂」环境在怎么动。光流(Optical Flow) 就是 OODA 闭环里「感知」那一环的核心工具,也是第 6 篇视觉导航的基础。


1. 光流是什么

定义:光流是空间运动物体在观察成像平面上、像素运动的瞬时速度。某个真实物体在动,它在画面上对应的像素会从这一帧的位置挪到下一帧,光流就是描述「每个像素朝哪个方向、移动多快」的速度场。

对二维平面,任一点的光流是一个矢量 (u,v)(u, v),叫光流矢量uu = 水平方向速度分量,vv = 垂直方向速度分量。直觉:坐在行驶的车里往窗外看,近处的树飞快向后掠过、远处的山缓缓移动——每个点「掠过」的方向和速度就是光流。

按「算多少个点」分两类:稀疏光流(只挑画面里少数特征明显的点算并跟踪,省算力,代表 LK 法);稠密光流(算每个像素的运动,通常映射到 HSV 颜色空间可视化——颜色表方向、深浅表速度,信息全但费算力,代表 Farneback 法)。

2. 两条基本假设 + 核心约束方程

光流要从「两帧图像」反推「每个像素的速度」,必须先立两条假设:

  • 假设一:亮度恒定。 同一物体点在相邻两帧之间,亮度(灰度值)基本不变。
  • 假设二:时间持续性(小运动)。 时间变化很短,像素位置不会剧烈跳变。

推导核心约束:设 tt 时刻位于 (x,y)(x,y) 的像素亮度是 I(x,y,t)I(x,y,t),到 t+dtt+dt 时刻挪到 (x+dx,y+dy)(x+dx, y+dy)。由假设一(亮度恒定):

I(x,y,t)=I(x+dx,y+dy,t+dt)I(x,y,t) = I(x+dx,\, y+dy,\, t+dt)

由假设二(小运动),右边泰勒展开只留一阶项:

I(x+dx,y+dy,t+dt)I(x,y,t)+Ixdx+Iydy+ItdtI(x+dx, y+dy, t+dt) \approx I(x,y,t) + \frac{\partial I}{\partial x}dx + \frac{\partial I}{\partial y}dy + \frac{\partial I}{\partial t}dt

代回消去 I(x,y,t)I(x,y,t)、整个除以 dtdt,注意 dxdt=u\frac{dx}{dt}=udydt=v\frac{dy}{dt}=v,记 Ix=IxI_x=\frac{\partial I}{\partial x}Iy=IyI_y=\frac{\partial I}{\partial y}It=ItI_t=\frac{\partial I}{\partial t},得到光流基本约束方程

Ixu+Iyv+It=0I_x\, u + I_y\, v + I_t = 0

这个方程是整个光流的基石,但有个致命问题Ix,Iy,ItI_x, I_y, I_t 都能从图像直接算出来,可是一个方程里有两个未知数 u,vu, v,无法唯一求解!这就是著名的孔径问题。所以还需要一个额外约束。三代算法的本质区别,就是各自用不同办法补上这个「缺失的约束」。

3. 第一代:Lucas-Kanade 法(传统稀疏)

LK 法(1981,Bruce Lucas 和 Takeo Kanade)是最经典的稀疏光流算法。它补约束的办法叫空间一致性假设:一个像素点周围一小块邻域(n×nn\times n 窗口)内的所有像素,光流值都一样。

怎么解决「一个方程两个未知数」的困境:单像素只能列 1 个方程(欠定)。但假设窗口里 n×nn\times n 个像素共享同一个 (u,v)(u,v),那每个像素都贡献一个方程——n×nn\times n 个方程、却只有 2 个未知数,从「欠定」变成「超定」,用最小二乘法求最优解。写成矩阵 Ax=bAx=bAA 是各点梯度堆叠、x=[u,v]Tx=[u,v]^{\mathsf T}bb 是各点 It-I_t):

x=(ATA)1ATbx = (A^{\mathsf T}A)^{-1} A^{\mathsf T} b

只要 ATAA^{\mathsf T}A 可逆就能解。

孔径问题(Aperture Problem):当 ATAA^{\mathsf T}A 不可逆时出现多解。直觉是——从一个小圆孔里看一组移动的斜条纹,「沿垂直于条纹方向移动」和「斜着移动」看起来一模一样,分不清真实方向。原因:窗口里若只有一条直边(纯色墙边缘),所有像素梯度方向相同,ATAA^{\mathsf T}A 退化。解决办法:专挑角点(两个方向边缘、梯度丰富、ATAA^{\mathsf T}A 必可逆),配角点检测算法选点——这正是它「稀疏」的原因。

金出武雄有句名言:「像外行一样思考,像专家一样实践」——思考时敢于回归本质、不被惯例束缚,实践时用专业能力把大胆想法落地。

4. 第二代:Farneback 法(传统稠密)

Farneback 法(2003,Gunner Farneback)是经典的稠密光流算法。思路是用二次多项式拟合局部图像:每像素邻域的灰度近似为

f(x,y)r1+r2x+r3y+r4x2+r5y2+r6xy=XTAX+bTX+cf(x,y) \approx r_1 + r_2 x + r_3 y + r_4 x^2 + r_5 y^2 + r_6 xy = \mathbf X^{\mathsf T} A\, \mathbf X + b^{\mathsf T}\mathbf X + c

其中 AA 对称矩阵、bb 向量、cc 标量,系数由加权最小二乘拟合邻域得到(把局部明暗近似成光滑二次曲面)。利用「同一像素相邻帧外观不变」:设位移 dd,则 f2(X)=f1(Xd)f_2(\mathbf X)=f_1(\mathbf X - d),两帧多项式系数对应相等,推出光流:

d=12A1(b2b1)d = -\tfrac{1}{2}A^{-1}\big(b_2 - b_1\big)

直觉:两帧各拟合一个二次曲面,比较系数差异(尤其一次项 bb 的变化)反推位移;对每个像素都算得稠密光流。

5. 第三代:FlowNet(深度学习)

前两代是手工设计(人工推假设、列方程求解)。深度学习思路——让卷积神经网络从大量数据里自己学「两帧图像 → 光流」这个映射(正是连接主义的思想)。

FlowNet 是第一个用 CNN 预测光流的工作,两种结构:FlowNetSimple(把两张图直接叠在一起输入网络);FlowNetCorr(先对两张图分别卷积提特征,再用一个「相关」操作合并匹配)。

关键结构收缩 + 扩张:前期用池化聚合大区域信息(看得广)但分辨率降低(变糊);后期用扩张路径(refinement) 恢复分辨率,把扩张的特征图与前期高分辨率低层特征图融合——既保留粗糙图的高层语义、又找回低层的局部细节;重复 refine 四次,最后双线性上采样恢复原始大小。FlowNet2 是优化版,由 FlowNetC/FlowNetS/FlowNet-SD 子网络堆叠应对不同物体运动。

工具箱:OpenCV 的 cv2.calcOpticalFlowPyrLK()(LK 稀疏)、cv2.calcOpticalFlowFarneback()(Farneback 稠密);深度学习光流可用 MMFlow。

6. 本篇小结

光流 = 像素在画面上运动的瞬时速度 (u,v)
  地基:两假设(亮度恒定 + 小运动)→ 核心约束 Ix·u + Iy·v + It = 0
       但一个方程两个未知数,解不出(孔径问题)
  三代算法各补「缺失的约束」:
    LK 法     —— 邻域光流一致 → 超定方程组、最小二乘解(稀疏、靠角点)
    Farneback —— 二次多项式拟合局部图像、比较两帧系数(稠密)
    FlowNet   —— CNN 从数据直接学映射(深度学习,收缩+扩张)

它补上了 OODA 闭环「感知」这一环。下一篇就是全课的集大成——具身智能 + VLA + NaVILA 实验,把感知、神经网络、强化学习汇聚成「看 + 听 → 行动」的端到端智能体。

评论