LK光流算法:提高计算精度和增加搜索范围
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光流算法:提高计算精度和增加搜索范围的更多相关文章
- Java实现 蓝桥杯 算法提高 计算超阶乘(暴力)
试题 算法提高 计算超阶乘 问题描述 计算1*(1+k)(1+2k)(1+3k)-(1+n*k-k)的末尾有多少个0,最后一位非0位是多少. 输入格式 输入的第一行包含两个整数n, k. 输出格式 输 ...
- Java实现 蓝桥杯VIP 算法提高 计算时间
算法提高 计算时间 时间限制:1.0s 内存限制:512.0MB 问题描述 给定一个t,将t秒转化为HH:MM:SS的形式,表示HH小时MM分钟SS秒.HH,MM,SS均是两位数,如果小于10用0补到 ...
- Java实现 蓝桥杯 算法提高 计算行列式
试题 算法提高 计算行列式 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 //据说很多人的题目会有一大堆废话,本傻×就不在这里废话了. 给定一个N×N的矩阵A,求|A|. 输入格式 ...
- LK光流算法的三个假设
在实际过程中采用 Lucas-Kanade 光流算法跟踪运动物体特征点的时候,一个很明显的特点是LK算法(包括其他光流算法)不能计算"大运动",加上金子塔的方法稍微好点. 这是什么 ...
- 光流算法:灰度恒常约束,LK算法,HS算法
关于如何提高计算精度和增加搜索范围,见:http://www.cnblogs.com/dzyBK/p/4982420.html
- 光流法详解之一(LK光流)
Lucas–Kanade光流算法是一种两帧差分的光流估计算法.它由Bruce D. Lucas 和 Takeo Kanade提出 [1]. LK光流法有三个假设条件: 1. 亮度恒定:一个像素点随着时 ...
- 优化梯度计算的改进的HS光流算法
前言 在经典HS光流算法中,图像中两点间的灰度变化被假定为线性的,但实际上灰度变化是非线性的.本文详细分析了灰度估计不准确造成的偏差并提出了一种改进HS光流算法,这种算法可以得到较好的计算结果,并能明 ...
- 算法笔记_155:算法提高 概率计算(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 生成n个∈[a,b]的随机整数,输出它们的和为x的概率. 输入格式 一行输入四个整数依次为n,a,b,x,用空格分隔. 输出格式 输出一行 ...
- Java实现 蓝桥杯 算法提高 概率计算
算法提高 概率计算 时间限制:1.0s 内存限制:256.0MB 问题描述 生成n个∈[a,b]的随机整数,输出它们的和为x的概率. 输入格式 一行输入四个整数依次为n,a,b,x,用空格分隔. 输出 ...
随机推荐
- caller 属性和callee属性
1.caller 属性 返回一个对函数的引用,即调用了当前函数的函数体. functionName.caller :functionName 对象是所执行函数的名称. 说明: 对于函数来说,calle ...
- 搭建EF6.0+MVC4搭建框架——之路由配置
为了适应项目需求,需要将前后台的控制器和视图等文件分开,便于修改和维护: 方案一:在原有的Controller下新增Admins文件夹用于放置后台控制器文件: 控制器文件目录如下图: 视图文件目录:
- 解决weblogic启动缓慢 linux系统随机数问题
这是SUN,JDK一个bug解决办法是在weblogic启动脚本里setDomainEnv.sh: 加入以下内容 JAVA_OPTIONS="${JAVA_OPTIONS} -Djava.s ...
- openstack奠基篇:devstack (liberty)于centos 7安装
openstack是什么,能做什么,我就不说了,他的优势和伟大,可以想想AWS的云服务平台.学习和研究openstack(IaaS),个人的习惯是有一个可以操作的平台,然后结合代码看看详细逻辑,这个过 ...
- .NET RSACryptoServiceProvider PEM + DER Support
http://www.christian-etter.de/?p=771 In .NET, RSACryptoServiceProvider greatly simplifies common tas ...
- Silverlight开源框架SL提供便捷的二次开发银光框架
Silverlight开发框架SilverFrame欢迎咨询 基于Silverlight4.0开发,兼容Silverlight 5.0,SQLServer2005数据库.WCF: 本框架有清爽的前端界 ...
- gcc内嵌汇编详解
[作者:byeyear 首发:cnblogs Email:east3@163.com 转载请注明] 有时候我们希望在C/C++代码中使用嵌入式汇编,因为C中没有对应的函数或语法可用. ...
- php测试程序运行时间和占用内存情况
php测试程序运行时间和占用内存情况: $HeaderTime = microtime(true);//参数true表示返回浮点数值 /** *CODE */ printf(" total ...
- php提高效率
1. foreach效率更高,尽量用foreach代替while和for循环. 2. 循环内部不要声明变量,尤其是对象这样的变量. 3. 在多重嵌套循环中,如有可能,应当将最长的循环放在内层,最短循环 ...
- 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 ...