Fork me on GitHub

LK光流法分析及其源码

光流法简介

光流的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。

光流法,是利用目标物体在监控场景中的空间运动,体现在视频图像序列中为不同图像颜色分布变化。导致目标物在监控场景中的空间运动场,在图像中转化为光流场,体现图像中每一个像素点的变化趋势。光流场可视为监控场景中的瞬时速度场。

研究光流场的目的就是为了从图片序列中近似得到不能直接得到的运动场。运动场,其实就是物体在三维真实世界中的运动;光流场,是运动场在二维图像平面上(人的眼睛或者摄像头)的投影。

算法原理

光流法的三种计算方法:LK,HS,最常用的还是LK。

Lucas–Kanade算法

这个算法是最常见,最流行的。它计算两帧在时间t到t+δt之间每个每个像素点位置的移动。由于它是基于图像信号的泰勒级数,这种方法称为差分,这就是对于空间和时间坐标使用偏导数。

图像约束方程,也是光流法的基本方程,可以写为$I(x,y,z,t)=I(x +δx,y+δy,z+δz,t+δt)$

$I(x,y,z,t)$ 为在$(x,y,z)$位置的体素。

我们假设移动足够的小,那么对图像约束方程使用泰勒公式,我们可以得到:

H.O.T.指更高阶,在移动足够小的情况下可以忽略。从这个方程中我们可以得到:

或者

我们得到:

Vx ,Vy ,Vz 分别是$I(x,y,z,t)$的光流向量中x,y,z的组成。 $\frac{∂I}{∂x}$, $\frac{∂I}{∂y}$, $\frac{∂I}{∂z}$和 $\frac{∂I}{∂t}$则是图像在$(x,y,z,t)$这一点向相应方向的差分。
所以
$$I_x V_x + I_y V_y + I_z V_z = −I_t$$
写做:

这个方程有三个未知量,尚不能被解决,这也就是所谓光流算法的光圈问题。那么要找到光流向量则需要另一套解决的方案。而Lucas-Kanade算法是一个非迭代的算法:
假设流(Vx,Vy,Vz)在一个大小为$m*m*m$(m>1)的小窗中是一个常数,那么从像素 $1,2,…,n,n =m^3$ 中可以得到下列一组方程:

$$I_{x1} V_x + I_{y1} V_y + I_{z1} V_z = -I_{t_1} $$

$$I_{x2} V_x + I_{y2} V_y + I_{z2} V_z = -I_{t_2} $$

$$ \vdots $$

$$I_{xn} V_x + I_{yn} V_y + I_{zn} V_z = -I_{t_n} $$

三个未知数但是有多于三个的方程,这个方程组自然是个超定方程,也就是说方程组内有冗余,方程组可以表示为:

记作:

$$A \vec{v} = -b $$

为了解决这个超定问题,我们采用最小二乘法:

$$A^T A \vec{v} = A^T (-b) $$

or

$$ \vec{v} = (A^T A)^{-1} A^T (-b) $$

得到:

其中的求和是从1到n。

另外,由于LK算法假设是小位移,为了解决大位移问题,需要在多层图像缩放金字塔上求解,每一层的求解结果乘以2后加到下一层:

代码示例

C++代码来自于:

http://download.csdn.net/download/crzy_sparrow/4183674

有两点修改的地方:

①void handleTrackedPoint(Mat &frame;,Mat &output;)声明过程中循环条件points[i]要改为points[1]

②新建项目时加上预编译头。

如果出现这个:
warning:opening fiile(../../modules/highgui/src/cap_ffmpeg_impl.hpp:545)
注意要把avi格式的视频文件放在debug下,可以用格式工厂转,注意视频编码那里要换成avc

效果:可以检测到运动目标。

参考资料:

http://blog.csdn.net/crzy_sparrow/article/details/7407604
http://blog.csdn.net/u014568921/article/details/46638557
http://www.cnblogs.com/gnuhpc/archive/2012/12/04/2802124.html

------ 本文结束感谢您的阅读 ------
坚持原创技术分享,您的支持将鼓励我继续创作!