Lucas–Kanade光流算法

         光流的概念是Gibson在1950年首先提出来的。它是空间运动物体在观察成像平面上的像素运动的瞬时速度,是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的对应关系,从而计算出相邻帧之间物体的运动信息的一种方法。一般而言,光流是由于场景中前景目标本身的移动、相机的运动,或者两者的共同运动所产生的。

      那通俗的讲就是通过一个图片序列,把每张图像中每个像素的运动速度和运动方向找出来就是光流场。那怎么找呢?咱们直观理解肯定是:第t帧的时候A点的位置是(x1, y1),那么我们在第t+1帧的时候再找到A点,假如它的位置是(x2,y2),那么我们就可以确定A点的运动了:(ux, vy) = (x2, y2) - (x1,y1)。

      L-K算法需要满足如下3个假设:

1)亮度恒定假设。即假设场景中目标在运动时外观颜色是不变的,也即在图像中的像素在两帧中的亮度保持不变。

2)时间连续或运动是小运动。即图像中物体的运动随时间变化缓慢,在连续的两帧图像间,物体的位移比较小。

3)空间一致性假设。图像中同一物体表面上邻近的像素点的运动是一致的,且这些点一定是聚集在一个区域内的。

      假设以M点为中心的灰度区域内的光流均一致,那么对于不同的像素点赋予不同的权值,就可以将光流的计算方程式转化为以下形式: 


由于之前的L-K光流法对于大运动的跟踪束手无策,然后有人又提出图像金字塔的方法来解决这个问题。通过建立金字塔,在多尺度下计算光流,使得光流的计算的准确性又跨越了一步。

        金字塔光流的思想是对每个图像帧向下采样,分别建立多级金字塔,当采样到足够小以后,相邻的图像帧之间的运动将变得很小,以至于可以看成是物体的运动随时间变化很慢的运动情况,这时候就可以用L-K方法计算目标的光流,再将计算出来的光流向底层投影,计算下一层的光流,直到估算出原图像帧的光流。





    实际运用中,通常只计算到3-4层金字塔,没有必要建立更多的金字塔层数,因为随着图像的移动,算法可以应对光流大于窗口尺寸的特征点跟踪问题。

金字塔L-K光流通常用来估计图像特征点的光流,以提高图像光流场的计算速度。若给定图像I中的像素点u,计算图像J中与其匹配的像素点v,使得v=u+d。

其计算的总体流程如下:

    首先,计算金字塔最顶层图像的光流,根据最顶层光流结果计算其次上层的光流初始值,再进一步估算其光流的精确值。最后,用计算的次上层光流结果估计下一层光流的初始值,计算其精确的值后再继续带入下一层计算,直到金字塔的最底层。下面以伪代码的形式给出金字塔L-K光流的计算过程:






    Opencv的光流实现由好几个方法可以(也就是说有好几个函数可以用),每个函数当然也对应着不同的原理,那么它的效果以及算法的速度等等就会有一些差别。主要包括以下几种:
calcOpticalFlowPyrLK
calcOpticalFlowFarneback
calcOpticalFlowBM
calcOpticalFlowHS
calcOpticalFlowSF

这里先简单介绍下calcOpticalFlowPyrLK函数
calcOpticalFlowPyrLK(prevImg,nextImg,prevPts,nextPts,status,err)

prevImg:就是你需要输入计算光流的前一帧图像

nextImg就是下一帧图像(可以看到一次光流就是在两针图像之间找不同)。

prevPts是前一帧图像中的特征点,这个特征点必须自己去找,所以在使用calcOpticalFlowPyrLK函数的时候,前面需要有一个找特征点的操作,那么一般就是找图像的角点,就是一个像素点与周围像素点都不同的那个点,这个角点特征点的寻找,opencv也提供夜歌函数:goodFeatureToTrack()(后面再介绍这个函数)。那么关于特征点有没有其他的方式呢?肯定是有的而且还很多吧。

nextPts参数就是计算特征点在第二幅图像中的新的位置,然后输出。特征点的新位置可能变化了,也可能没有变化,那么这种状态就存放在后一个参数status中。err就是新旧两个特征点位置的误差了,也是一个输出矩阵。
其他参数默认吧。

      基于特征点的跟踪算法大致可以分为两个步骤:

1)探测当前帧的特征点;

2)通过当前帧和下一帧灰度比较,估计当前帧特征点在下一帧的位置;

3)过滤位置不变的特征点,余下的点就是目标了。


#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;
int main()
{
    Mat I1;
    Mat I2;
    vector features;
    vector features_after;
    vector status;
    vector err;
    int maxCout = 400;//定义最大个数
    double minDis = 5;//定义最小距离
    double qLevel = 0.01;//定义质量水平
    //读取两个图像---相邻帧
    I1 = imread("1.bmp",0);//读取为灰度图像
    I2 = imread("2.bmp",0);
    //检测第一帧的特征点
    goodFeaturesToTrack(I1,features,maxCout,qLevel,minDis);
    //计算出第二帧的特征点
    calcOpticalFlowPyrLK(I1,I2,features,features_after,status,err);
    //判别哪些属于运动的特征点
    int k = 0;
    for(int i=0;i4))
        {
            features_after[k++] = features_after[i];
        }
    }
    features_after.resize(k);//截取
    cout<





车是运动的物体,大体检测出来了

参考文献:http://www.cnblogs.com/dverdon/p/5325498.html     Lucas–Kanade光流算法学习

http://www.voidcn.com/blog/on2way/article/p-4178535.html    目标检测光流法(二):opencv下的光流L-K算法

http://www.voidcn.com/blog/ZHE123ZHE123ZHE123/article/p-4939958.html


你可能感兴趣的:(Lucas–Kanade光流算法)