LK光流算法:提高计算精度和增加搜索范围

关于LK算法的基本理论,见:http://www.cnblogs.com/dzyBK/p/4960630.html

这里主要阐述如何提高LK算法的计算精度和在高斯金字塔上应用LK算法。

1.提高LK算法的精度

其实这也并不是什么高大尚的东西。通俗地讲,就是反复调用LK算法来提高精度。这种反复调用算法本身来提高算法精度的方法,不仅对LK算法可以使用,对其它光流算法也可以使用。的确也有很多光流算法是这么做的。除了光流算法,其它领域的很算法也都可以这么做。其实,就是一个迭代的思想。既然是一种思想,应用当然就很广啦。

在阐述如何提高LK算法精度之前,先来作一个通俗形象的比喻。假设你在A点,你想跳到离你不远处的B点。也许你想一下就跳到B点,但是你并不能保证你跳一下(步)就能准确地到达B点。也许更好的方法是允许你跳很多步,这样你就可以精确地(至少比跳一步精确)到达B点。具体跳多少步,还可以这样来决定,当你的位置与B的位置小于指定值时,就认为你已经到过了B点,此时你就可以停止跳跃,好好休息一下啦。这个过程就包含迭代的思想。其实,你到B点不一要选择跳啊,你还可以选择爬啊(比喻有点不恰当哈,但能明白什么意思就行),具体爬多少步了,也是可以人为定的。

这里的跳或者爬就是你要选择的方法。对应到我们这篇文章的目的上来,你选择计算光流,也可以有很多种方法。只是我们这里以LK为例来讲解而已。

以下对如何提高LK算法的计算精度作正式阐述。

设前一帧I上的某个像素点的位置是P(a,b),这个像素点在当前帧J的位置是Q(c,d),于是两帧之间的偏移量(偏移量对时间的导数就光流,所以得到偏移量也就间接地得到了光流啦)(u,v)=(c,d)-(a,b)。LK算法可表示为:

这里的F就表法LK算法,算法的输入是前后帧图像I及J和要计算其偏移量的点P,输出是点P的偏移量。对于多个点的情况,则每个点都这样表示即可。对于稠密光流的情况(即图像上每个点的光流都计算),则可表示为:

这里的E表示光流图,尺寸与I或J一样,但E是双通道图像。一个通道表示x方向的偏移量,一个通道表示y方向的偏移量。

前面已经说到,提高LK算法的计算精度就是一个迭代的过程。那到底是怎么一回事勒?其实就是当我们得到一个光流(u,v)以后,就将当前帧J平移(u,v)(也可以将I平移(-u,-v))。平移之后,I和J就更接近重合了,P和Q也更接近了。然后我们再对I和平移后的J使用LK算法,又得到一个光流,然后又平移J。如此反复,P和Q越来越接近,我们得到光流也会越来越小。于是我们设置一个阈值,当得到光流小于此阈值时,我们认为P和Q已经完全重合。此时,我们把所有得到光流相加,就是最终的结果,即P和Q之间的偏移量。这个过程,我们可以表示为如下代码:

以上每个步骤中,我们还需判断Ui的模长Di,当Di小于指定的值d则终步迭代,于是更好表示代码如下:

2.在高斯金字塔应用LK算法

应用高斯金字塔的目的是为了增加LK算法的搜索范围,使得算法对于长距离移动的像素点也有效。怎么理解这个长距离了?同前面一样,我们设前一帧上有个像素点P,相对于当前帧它移动了U,它在当前帧的位置为Q,则P+U=Q。当U小于一定的值时,LK算法有效,当U大于一定值时,LK算法就一不定有效了。这时,就发挥高斯金字塔的作用啦。高斯金字塔可以得到一系列缩小的图像,在缩小的图像上的移动量U也会相应地缩小。此时,再应用LK算法不就可以有效啦。当然,也不是说有了高斯金字塔,移动量多大,光流算法都有效,还得看算法本身的性能。

现在我们来详细阐述下如何在高斯金字塔上应用LK算法。

首先,要为前后帧建立高斯金字塔(能看到这里不会不知道如何建高斯金字吧)。设前后帧分别为I和J,我们用Ii-1表示金字塔的第i层,用I0表示金字塔的最底层,I0=I。对于J,表示法也一样。设金字塔共有N层。在金字塔上应用LK算法的代码如下:

其中PN-1等于P坐标除以2N。从代码中可以看出,LK算法从金字塔顶层到底层逐层应用,上一层的偏移量乘以2后(乘以2的前提是金字塔是按原图缩小一半来建立的)作为下一层的初始偏移量,下一层的J先按这个偏移量平移之后再作为LK算法的输入,金字塔减小LK算法搜索范围的关键就在这里,因为平移之后,这层的I和J就更接近重合啦,所以搜索范围也就自然地减小啦。

值得注意的是,初始的Un设置为(0,0)是因为不知道初始的大约偏移量,若已知初始的大约偏移量,则可以在此指定,但记得要先除以2N

3.综合代码

以下是在OpenCV下的代码,但并没有实现具体的细节,只是给出了算法的原理及算法的接口,只要实现给出的接口就可以实现LK算法啦。

 #include <opencv2/opencv.hpp>
 using namespace cv;
 using namespace std;

 Mat SobelX(Mat &src){ return src; }
 Mat SobelY(Mat &src){ return src; }
 vector<Mat> buildPyramid(Mat &sr){ vector<Mat> vecMat(); return vecMat; }
 Mat Shift(Mat &src, Point2f d) { return src; }
 Point2f MatToPoint(InputArray &src) { Point2f x; return x; }

 void LK_Pyramid()
 {
     Mat I, J;//给定前一帧和当前帧(输入)
     Point2f P;//给定前一帧上的某个位置(输入)
     int winSize;//给定的位置领域内多少个像素的光流都相等(输入)
     float acy;//程序跳出循环的阈值精度(输入)
     Point2f Q;//给定位置在当前帧对应的位置(返回 或 返回+输入)

     vector<Mat> pyramidI, pyramidJ;//给定前一帧和当前帧的金字塔
     Mat Ixi, Iyi, P_Ixi_ROI, P_Iyi_ROI, Gi;//变量中的i表示金字塔的第i层
     Mat Itij, bij;//变量中的i表示金字塔的第i层,j表示在金字塔的第i层的第j次执行LK算法

     Point2f Pi;//给定的位置在金字塔的第i层的值
     Point2f Ui, Di;//
     Point2f Uij, Dij;//

     I = imread("./../TestData/I.png");
     J = imread("./../TestData/J.png");
     P = Point2f(, );
     winSize = ;
     acy = 0.001f;

     pyramidI = buildPyramid(I);
     pyramidJ = buildPyramid(J);

     ; i >= ; i--)
     {//每层循环改变Di从而改变下一层的Ui,即将每层循环的微小变化(即Di)累加到Ui上从而得到精确的Ui(最初的Ui为0或给定的值)
         Pi = P / pow(.f, i);//给定的位置在金字塔的第i层的值

         Ixi = SobelX(pyramidI[i]);//金字塔的第i层的x微分
         Iyi = SobelY(pyramidI[i]);//金字塔的第i层的y微分

         Gi.create(, , CV_32F);//金字塔第i层的空间梯度矩阵(原理见LK算法)
         P_Ixi_ROI = Ixi(Rect(Pi.x - winSize / , Pi.y - winSize / , winSize, winSize));//P领域的x微分
         P_Iyi_ROI = Iyi(Rect(Pi.x - winSize / , Pi.y - winSize / , winSize, winSize));//P领域的y微分
         Gi = (Mat_<, ) << sum(P_Ixi_ROI*P_Ixi_ROI)[], sum(P_Ixi_ROI*P_Iyi_ROI)[], sum(P_Ixi_ROI*P_Iyi_ROI)[], sum(P_Iyi_ROI*P_Iyi_ROI)[]);

         )    Ui = Point2f(, );//当前帧是金字塔的最顶层的初始偏移量(即偏移量) 或 等于Q-P(Q存储有给定的大约位置,此时Q即是返回变量也是输入变量)
          * (Ui + Di);//当前帧的金字塔的第i层的初始偏移量(即大约偏移量) = 2 * (前一层的Ui + 前一层的Di)

         ; sqrt(Dij.x*Dij.x + Dij.y*Dij.y)< acy; j++)
         {//每层循环改变Dij从而改变下一层的Uij,即将每层循环的微小变化(即Dij)累加到Uij上从而得到精确的Uij(最初的Uij为0)
             )    Uij = Point2f(, );//首次循环的偏移量(即大约偏移量)
             else        Uij = Uij + Dij;//第j次循环的初始偏移量(即大约偏移量)= 前一次循环的Uij + 前一次循环的Dij

             Itij = pyramidI[i] - (Shift(pyramidJ[i], Ui + Uij));//前一帧的金字塔的第i层的第j次循环的t微分
             bij = (Mat_<, ) << sum(Itij*Ixi)[], sum(Itij*Iyi)[]);
             Dij = MatToPoint(Gi.inv()*bij);//本层循环的Dij被改变,但Uij不变
         }
         Di = Uij + Dij;//最后一次循环的Uij还没有叠加到Dij上,所以再加一次
     }
     Q = P + Ui + Di; //最后一次循环的dL还没有叠加到gL上,所以再加一次。
 }

LK光流算法:提高计算精度和增加搜索范围的更多相关文章

  1. Java实现 蓝桥杯 算法提高 计算超阶乘(暴力)

    试题 算法提高 计算超阶乘 问题描述 计算1*(1+k)(1+2k)(1+3k)-(1+n*k-k)的末尾有多少个0,最后一位非0位是多少. 输入格式 输入的第一行包含两个整数n, k. 输出格式 输 ...

  2. Java实现 蓝桥杯VIP 算法提高 计算时间

    算法提高 计算时间 时间限制:1.0s 内存限制:512.0MB 问题描述 给定一个t,将t秒转化为HH:MM:SS的形式,表示HH小时MM分钟SS秒.HH,MM,SS均是两位数,如果小于10用0补到 ...

  3. Java实现 蓝桥杯 算法提高 计算行列式

    试题 算法提高 计算行列式 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 //据说很多人的题目会有一大堆废话,本傻×就不在这里废话了. 给定一个N×N的矩阵A,求|A|. 输入格式 ...

  4. LK光流算法的三个假设

    在实际过程中采用 Lucas-Kanade 光流算法跟踪运动物体特征点的时候,一个很明显的特点是LK算法(包括其他光流算法)不能计算"大运动",加上金子塔的方法稍微好点. 这是什么 ...

  5. 光流算法:灰度恒常约束,LK算法,HS算法

    关于如何提高计算精度和增加搜索范围,见:http://www.cnblogs.com/dzyBK/p/4982420.html

  6. 光流法详解之一(LK光流)

    Lucas–Kanade光流算法是一种两帧差分的光流估计算法.它由Bruce D. Lucas 和 Takeo Kanade提出 [1]. LK光流法有三个假设条件: 1. 亮度恒定:一个像素点随着时 ...

  7. 优化梯度计算的改进的HS光流算法

    前言 在经典HS光流算法中,图像中两点间的灰度变化被假定为线性的,但实际上灰度变化是非线性的.本文详细分析了灰度估计不准确造成的偏差并提出了一种改进HS光流算法,这种算法可以得到较好的计算结果,并能明 ...

  8. 算法笔记_155:算法提高 概率计算(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 生成n个∈[a,b]的随机整数,输出它们的和为x的概率. 输入格式 一行输入四个整数依次为n,a,b,x,用空格分隔. 输出格式 输出一行 ...

  9. Java实现 蓝桥杯 算法提高 概率计算

    算法提高 概率计算 时间限制:1.0s 内存限制:256.0MB 问题描述 生成n个∈[a,b]的随机整数,输出它们的和为x的概率. 输入格式 一行输入四个整数依次为n,a,b,x,用空格分隔. 输出 ...

随机推荐

  1. caller 属性和callee属性

    1.caller 属性 返回一个对函数的引用,即调用了当前函数的函数体. functionName.caller :functionName 对象是所执行函数的名称. 说明: 对于函数来说,calle ...

  2. 搭建EF6.0+MVC4搭建框架——之路由配置

    为了适应项目需求,需要将前后台的控制器和视图等文件分开,便于修改和维护: 方案一:在原有的Controller下新增Admins文件夹用于放置后台控制器文件: 控制器文件目录如下图: 视图文件目录:

  3. 解决weblogic启动缓慢 linux系统随机数问题

    这是SUN,JDK一个bug解决办法是在weblogic启动脚本里setDomainEnv.sh: 加入以下内容 JAVA_OPTIONS="${JAVA_OPTIONS} -Djava.s ...

  4. openstack奠基篇:devstack (liberty)于centos 7安装

    openstack是什么,能做什么,我就不说了,他的优势和伟大,可以想想AWS的云服务平台.学习和研究openstack(IaaS),个人的习惯是有一个可以操作的平台,然后结合代码看看详细逻辑,这个过 ...

  5. .NET RSACryptoServiceProvider PEM + DER Support

    http://www.christian-etter.de/?p=771 In .NET, RSACryptoServiceProvider greatly simplifies common tas ...

  6. Silverlight开源框架SL提供便捷的二次开发银光框架

    Silverlight开发框架SilverFrame欢迎咨询 基于Silverlight4.0开发,兼容Silverlight 5.0,SQLServer2005数据库.WCF: 本框架有清爽的前端界 ...

  7. gcc内嵌汇编详解

    [作者:byeyear    首发:cnblogs    Email:east3@163.com    转载请注明] 有时候我们希望在C/C++代码中使用嵌入式汇编,因为C中没有对应的函数或语法可用. ...

  8. php测试程序运行时间和占用内存情况

    php测试程序运行时间和占用内存情况: $HeaderTime = microtime(true);//参数true表示返回浮点数值 /** *CODE */ printf(" total ...

  9. php提高效率

    1. foreach效率更高,尽量用foreach代替while和for循环. 2. 循环内部不要声明变量,尤其是对象这样的变量. 3. 在多重嵌套循环中,如有可能,应当将最长的循环放在内层,最短循环 ...

  10. How to install Wordpress 4.0 on CentOS 7.0

    This document describes how to install and configure Wordpress 4.0 on CentOS 7.0. WordPress started ...