光流跟踪算法及OpenCV源代码探索

本文主要记录看光流跟踪算法的感悟,以及OpenCV中对应的实现源码的整理

原文:Pyramidal Implementation of theLucas Kanade Feature Tracker Description of the algorithm 1

光流算法相关概念

  1. 特征跟踪的目的:对于第一张图像I上的位置u,在第二张图像J上找到一个位置v,使得I(u)和J(v)相近
  2. 点x处的光流:在x点处的图像速度1
  3. 图像速度d是一个向量,使得残差ε最小。其中,相似性方程是在邻域尺寸(2ωx+1)x(2ωy+1)内计算的,这个邻域又叫做integration window
    在这里插入图片描述
  4. 对于特征跟踪器,有两个关键因素:
    1. 正确率:与跟踪相关联的局部亚像素准确性。因此,为了避免将细节部分平滑掉,所以窗口尺寸应该小一些。当图像中的两个块具有不同的速度导致有遮挡时,这很重要
    2. 强健性:跟踪过程中对于光照、图像运动等因素的敏感性。为了处理大的运动,主观上就觉得应该是选择一个大一点的integration window
    3. 因此,存在正确率和强健性两者之间的平衡
  5. 图像的金字塔表示:背后的中心思想是可以处理大于integration window尺寸的大的像素运动。图片的第0层具有最高分辨率(原始图像),然后以迭代方式向下构建金字塔层,且满足下述公式
    光流跟踪算法及OpenCV源代码探索_第1张图片由于引入了dummy值,于是就可以得出下述不等式!光流跟踪算法及OpenCV源代码探索_第2张图片
    根据经验,金字塔高度为2,3,4
  6. 金字塔特征跟踪:对于L层的金字塔层,对于每个坐标位置,它的位置可以使用下述公式进行计算:
    在这里插入图片描述
    其中,在这里插入图片描述是指在L层的初始光流位移估计值,从Lm(金字塔的最深的那一层 the deepest pyramid level)到L+1层计算得到在这里插入图片描述,其中dL需要使得新的图像匹配误差函数最小。误差函数为:在这里插入图片描述
    最后的光流残差向量值为:在这里插入图片描述,即开篇第一个公式的解。根据观察,可以发现,光流残差可以使用下述公式进行表示:光流跟踪算法及OpenCV源代码探索_第3张图片。此时,即使整体像素位移向量d很大,dL也可以保持在一个很小的范围。假设每一个单位光流计算步骤可以处理最大为dmax的像素运动,那么金字塔实现可以处理的整体像素运动就变成了在这里插入图片描述
  7. 在这里插入图片描述。对B(…)进行一阶Taylor展开,得到在这里插入图片描述。引入下述标记在这里插入图片描述在这里插入图片描述,所以就可以推出下述公式
  8. 在这里插入图片描述其中,在这里插入图片描述
    因此,最优的光流向量等于在这里插入图片描述。这个公式即成立需要G可以,也就是说在点p周围,A(x,y)周围的x和y方向上都包含梯度信息
    这是标准的Lucas-Kanade光溜方式,仅当像素位移很小的时候才有效(因为在推导的过程中对B矩阵进行了一阶Taylor展开,如果位移很大的话,此时的Taylor一阶展开就引入了较大的误差)

光流算法OpenCV实现

理清了LK算法的来龙去脉,下面我们来仔细的阅读一下源代码,opencv\sources\modules\video\src\lkpyramid.cpp
1.

void cv::calcOpticalFlowPyrLK( InputArray _prevImg, InputArray _nextImg,
	                               InputArray _prevPts, InputOutputArray _nextPts,
	                               OutputArray _status, OutputArray _err,
	                               Size winSize, int maxLevel,
	                               TermCriteria criteria,
	                               int flags, double minEigThreshold )
	{
	    Ptr optflow = cv::SparsePyrLKOpticalFlow::create(winSize,maxLevel,criteria,flags,minEigThreshold);
	    optflow->calc(_prevImg,_nextImg,_prevPts,_nextPts,_status,_err);
	}

找到调用的calcOpticalFlowPyrLK(…)函数实现方式,创建稀疏金字塔LK光流类的对象,并调用其上的calc函数
3. SparsePyrLKOpticalFlow类:对于一个稀疏特征集,可以使用金字塔式的迭代LK算法来计算光流
4. 对于calc方法,一开始就是一系列的OpenCL代码,关键的是首先调用了ocl_calcOpticalFlowPyrLK(…)
诶,现在编码能力还不够,,还看不懂,,并没有发现论文中出现的算法,,, !!
即使这样,继续,虽然还是大部分看不懂,但是在该函数的返回值处,看到了希望!

return sparse(_prevImg.getUMat(), _nextImg.getUMat(), _prevPts.getUMat(), umatNextPts, umatStatus, umatErr);

在这个函数中,开始了真正的金字塔创建等内
5. sparse(…)
首先创建两个图像金字塔。

// build the image pyramids	 
std::vector prevPyr; prevPyr.resize(maxLevel + 1);
 std::vector nextPyr; nextPyr.resize(maxLevel + 1);

继续跟踪next_points, status两个变量的状态,后续发现调用了下述函数,且传入的是引用,可以直接对下述变量直接进行修改

bool lkSparse_run(UMat &I, UMat &J, const UMat &prevPts, UMat &nextPts, UMat &status, UMat& err,
            int ptcount, int level)

在这个函数中,就是创建一个ocl::Kernel kernel对象,为其设置各个所需要的参数,返回时执行kernel::run(…)
接下来就是妥妥的全是模板了,,,

诶,还是太菜了,,,待我再好好学学,回来填坑!

你可能感兴趣的:(SLAM,光流跟踪)