大家好,又见面了,我是你们的朋友全栈君。
1. 定义
空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。也就是说,由空间域到图像平面的投影。而通俗来讲,把图像中的每一个点的瞬时速度和方向找出来就是光流。
2. 光流有什么用
通过光流判断物体距离我们的远近。 一般而言,远景的物体相对来说光流较小,而近景物体光流较大,尤其是动态场景中的运动物体。
3. 如何计算光流
光流法的第一层推导
3.1 计算光流的几个假设
(1)相邻帧之间的亮度恒定;
(2)相邻视频帧的取帧时间连续,或者,相邻帧之间物体的运动比较“微小”;
(3)保持空间一致性;即,同一子图像的像素点具有相同运动
3.2 光流的基本方程
假设位于 (x,y,t) 的像素的亮度是 I(x,y,t) , 该像素在两个图像帧之间移动了 Δx Δy Δt ,由泰勒展开式我们可以得到:
I(x+Δx,y+Δy,t+Δt)=I(x,y,t)+∂I∂xΔx+∂I∂yΔy+∂I∂tΔt+o
由假设1可知
I(x+Δx,y+Δy,t+Δt)=I(x,y,t)
故有:
∂I∂xΔx+∂I∂yΔy+∂I∂tΔt=0
或者
∂I∂xΔxΔt+∂I∂yΔyΔt+∂I∂t=0
这个方程便是我们计算光流的基本方程。
其中 ΔxΔt 和 ΔyΔt 为该点在x和y方向上的瞬时速度,也就是光流。
∂I∂t 代表 像素点在时间上的变化。 可以通过在像素位置(x,y)处两张图像之间的像素差。
但是这个我们要计算一个点的光流,有两个未知数,只有一个方程,该如何解呢?针对这个问题,有很多解决方法:
– 基于梯度的方法
– 基于匹配的方法
– 基于能量的方法
– 基于相位的方法
下面我们介绍一个很经典的算法, LK光流提取算法
LK-光流算法
基本假设:光流在像素点的邻域是一个常数
然后使用最小二乘法对邻域中的所有像素点求解基本的光流方程。因为方程个数已经超过了为未知量个数
假定像素位置p周围的领域像素由 q1q2q3... ,那么就有
Ix(q1)Vx+Iy(q1)Vy+It(q1)=0 ;
Ix(q2)Vx+Iy(q2)Vy+It(q2)=0 ;
Ix(q3)Vx+Iy(q3)Vy+It(q3)=0 ;
…
将其写为矩阵的形式,则有
然后通过伪逆的形式解最小二乘就可以求解到光流 v
v=(ATA)−1ATb
L-K 光流算法的缺点
我们首先要设置一个邻域的窗口,之后计算光流
当窗口较大时,光流计算更鲁棒
当窗口较小时,光流计算更正确
原因在于,当图像中每一个部分的运动都不一致的时候,如果开的窗口过大,很容易违背假设:窗口(邻域)内的所有点光流一致,这可能与实际不一致,所以窗口小,包含的像素少,更精确些。当运动较为剧烈的时候,无法实现光流的基本假设,即 I(x+Δx,y+Δy,t+Δt)=I(x,y,t) ,因为 Δx Δy 而我们的领域小于实际运动的位移,所以当我们的领域加大的时候,算法更鲁棒。
如何解决这一问题,我们采用了金字塔的方法,即窗口固定,将图像生成金字塔,在每一层金字塔上都用同一个大小的窗口来进行光流计算。那么在图像大小较小的时候,窗口显得较大,此时的光流可以跟踪速度较快的目标,而在原始图像的时候,光流窗口相对较小,得到的光流就更准确。这是一个由粗到精的过程。
以上是光流的第一层推导
光流法的第二层推导
光流法的基本方程
其中 I(x,y) 指原图, J(x,y) 指参考图。 dx,dy 为在 (ux,uy) 处的光流向量。 wx,wy 为基于坐标点 (ux,uy) 的搜索窗口(半径)。
默认情况下,我们认为 dx,dy 应该小于 (ux,uy) ,也就是在I图中的一个点对应J图时,应该不会超过 (ux,uy) 这个窗口的。那么基于这个假设就出现了上面提到的关于窗口大小与光流准确性及鲁棒性带来的矛盾。下面讲如何利用图像金字塔来解决这个矛盾。
1. 如何建立图像金字塔
按照此公式建立,其中 IL 代笔第L层的图像金字塔。初始情况下使 I0 为原始图像。按照上述公司,由第L-1层图像到第L层图像是通过以下步骤
– 对L-1层图像进行低通滤波,滤波模板如下
– 将滤波后的图像抽取偶数行偶数列的像素重组为第L层图像,因此最后L-1层的图像大小是L层的一半。
但是对于图像滤波时边缘像素怎么办呢?由于模板的半径是1,那么就首先将原始图像的像素扩展一圈,宽度为一个像素,扩展出来的像素值与其相近的原始图像边缘像素一致,即
2. 根据金字塔逐层计算光流
首先引入两个光流量:剩余光流量 dL 和猜测光流量 gL 。
核心思想在于:对第L层的光流,是通过由第L-1层的精确光流得到的导出光流量 gL 以及这一层以 gL 为基准再次进行匹配微调后得到的剩余光流量 dL 。即第L层的光流 kL 为
gL 由上一层的精确光流猜测得来
基于的事实是:既然第L-1到第L层是降采样一半,那么光流量也应该减一半。
但是这样粗略的估算是不准确的,所以第L层还需要通过基本的光流方程得出剩余光流量
dL
去修正这个值,使得第L层的光流更精确.怎么得到
dL
,就是基本的光流方程
这里可以发现,关于最终光流的搜索范围事实上是变大了的,如图所示
所有都归功于上一层光流提供的先验信息使得光流跳出了 wx,wy 的约束,可以到更远的地方,这样就解决了上面提到的关于窗口大小的矛盾。事实上,对于在原始图像(L=0)上开一个d*d的搜索框,在金字塔的情况下,总的搜索半径可以达到
对于一般的视频做光流而言,采用3*3的窗口,图像金字塔的层数有2-3层就够了。因为覆盖范围以及很广了
最后得到的原始图像的光流按照一下公式计算而来
3. 计算光流基本方程
首先光流基本方程是一个最优化的问题,可以通过求导求其最优解
对基本光流方程求导
对 B(x+vx,y+vy) 进行一阶泰勒展开
计算两张图像的差
计算图像在 wx,wy 邻域内的差分,这里可以采用Sharr算子代表差分
这样就算出了LK光流。但是这一光流的假设是泰勒一阶展开足够精确。那么为了进一步使得计算出来的光流更加精确,我们采用牛顿逼近法进行迭代。
核心思想在于:在上一次计算出LK光流后,将得到的光流 vk 用来更新参考图像的像素位置(平移),之后再次计算光流。重新更新 vk 。如此循环直到迭代次数达到上限或者误差量 ε 小于设定的阈值时停止。 按照上述情况来看,停止迭代后,A图和B图两张图在 (x,y) 点处像素完全重合的。
这里是最终迭代结束后的精确光流量
总结算法
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/163529.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...