光流法的工作原理基于如下假设:
光流问题涉及尝试找出一幅图像中的许多点在第二幅图像中移动的位置–通常是以视频序列完成的,因此可以假定第一幅图像中的大部分点框架都可以在第二幅图像中找到。
光流可以用于场景中物体的运动估计,设置用于相机相对于整个场景的自运动估计。
根据是否选取图像稀疏点进行光流估计,可以将光流估计分为稀疏光流和稠密光流,如图,左图选取了一些特征明显(梯度较大)的点进行光流估计和跟踪,右图为连续帧稠密光流示意图。
稠密光流描述图像每个像素向下一帧运动的光流,为了方便表示,使用不同的颜色和亮度表示光流的大小和方向,如图右图的不同颜色。图展示了一种光流和颜色的映射关系,使用颜色表示光流的方向,亮度表示光流的大小。
最为常用的视觉算法库OpenCV中,提供光流估计算法接口,包括稀疏光流估计算法cv2.calcOpticalFlowPyrLK(),和稠密光流估计cv2.calcOpticalFlowFarneback()。
其中稀疏光流估计算法为Lucas-Kanade算法,该算法为1981年由Lucas和Kanade两位科学家提出的,最为经典也较容易理解的算法
LK算法是一种两帧差分的光流估计算法,其基本思想基于以下三个假设。
三个基本假设中前两个是光流法的基本假设,第三个是LK算法特有的。
待补充????
Jean-Yves Bouguet提出一种基于金字塔分层,针对仿射变换的改进Lucas-Kanade算法构建图像金字塔可以解决大运动目标跟踪,也可以一定程度上解决孔径问题(相同大小的窗口能覆盖大尺度图片上尽量多的角点,而这些角点无法在原始图片上被覆盖)
主要思想
考虑物体的运动速度较大时,算法会出现较大的误差。那么就希望能减少图像中物体的运动速度。一个直观的方法就是,缩小图像的尺寸。假设当图像为400×400时,物体速度为[16,16],那么图像缩小为200×200时,速度变为[8,8]。缩小为100*100时,速度减少到[4,4]。所以光流可以通过生成
原图像的金字塔图像,逐层求解,不断精确来求得
上层金字塔(低分辨率)中的一个像素可以代表下层的两个
对于Lucas-Kanade改进算法来说,主要的步骤有三步:建立金字塔,基于金字塔跟踪,迭代过程
Bouguet J. Pyramidal Implementation of the AÆne Lucas Kanade Feature
Tracker Description of the Algorithm, Intel
Corporation–Microprocessor Research Labs, 2000[J].
除了基于亮度不变假设和邻域光流相似假设,为了解决图像偏移较大的情况,Lucas-Kanade算法还借助了图像金字塔(Pyramid)的方式,在高层低分辨率图像上,大的偏移将变为小的偏移。
首先需要对原始图像建立金字塔,其中原始图像位于底层,其上每一层均基于上一层进行计算。
金字塔中每一层均是上一层的下采样,其计算公式为:
其中IL(x,y)为 L 层图像中 x, y 位置所在像素点的灰度值,其相当于通过[0.25 0.5 0.25]的低通滤波器进行迭代计算。
计算光流使用顶层(Lm)层开始,通过最小化每个点领域范围内的匹配误差和,得到每个顶层图像中每个点的光流,该步骤同LK光流法。
假设图像的尺寸每次缩放为原来的一半,一共缩放了Lm层,则第0层为原始图像,设已知原图的位移为u,则每一层的位移可以表示为:
所以顶层的光流计算结果,也就是位移,反应到Lm-1层,作为该层初始时的光流值的估计g表示为:
沿着金字塔向下反馈,重复估计每一层的位移,直到最底层也就是原始图像计算像素的位移。
可以理解为 :
准确值=估计值+残差,
对于每一层L,每个点的光流的计算都是基于邻域内所有点的匹配误差和最小化。
由于顶层图像尺寸较小,其初始的光流估计量可以设置为0,即 gL = [0, 0] 。
介绍了对于整个金字塔迭代过程,还需要提供对于每一层的残余光流计算方法。
求解光流最重要的是最小化上文提到的残差方程:
最终,Lucas-Kanade方法给出了一种求解稀疏(明显特征的角点)光流的方法。
OpenCV 库提供函数 cv.calcOpticalFlowPyrLK()-
一个简单应用示例:
我们要跟踪视频中某些点,
先使用 cv.goodFeaturesToTrack() 来获取这些点-
首先取第一帧,检测其中的 Shi-Tomasi 角点,然后使用 Lucas-Kanade 算法来迭代地跟踪这些特征点。
迭代的方式就是向 cv.calcOpticalFlowPyrLK() 函数传入上一帧图片和其中的特征点以及当前帧图片,
函数会返回当前帧的特征点,每个点都带有一个状态值(0 或 1),
如果在当前帧找到了上一帧中的点,这个点的状态值就是 1,否则就是 0。
将状态值为 1 的点作为下次特征点的输入,不停迭代
nextPts, status, err = cv.calcOpticalFlowPyrLK(
prevImg, nextImg, prevPts, nextPts[, status[, err[, winSize[, maxLevel[, criteria[, flags[, minEigThreshold]]]]]]])
实现原理: - 在第一帧图像中检测Shi-Tomasi角点, - 使用LK算法来迭代的跟踪这些特征点。迭代的方式就是不断向cv2.calcOpticalFlowPyrLK()中传入上一帧图片的特征点以及当前帧的图片。 - 函数会返回当前帧的点,这些点带有状态1或者0,如果在当前帧找到了上一帧中的点,那么这个点的状态就是1,否则就是0。
实现流程:
Farneback稠密光流的主要思想是利用多项式对每个像素的邻域信息进行近似表示,例如考虑二次多项式。
A是对称矩阵,b是向量,c为标量,~表示像素邻域信息的近似
A是通过像素的邻域信息的最小二乘加权拟合得到的,权重系数与邻域的像素大小和位置有关。
如前一帧图像用
表示,两帧图像唯一用d表示,那么
等价于
因为图像场景中像素的外观信息在帧间运动不变,可以得到对应系数相同,如果A1非奇异,则
再经过对误差的优化和调整结合图像金字塔对图像中的特征点进行跟踪,稠密光流的大致流程就算完事了。
下面样例显示如何找到稠密光流,我们得到的一个两个通道的向量(u,v)。得到的该向量的大小和方向。用不同的颜色编码来使其可视化。
Lucas-Kanade方法计算稀疏特征集的光流,OpenCV提供了另一种算法来查找密集的光流,它计算帧中所有点的光流。它基于Gunner Farneback于2003年的《Two-Frame Motion Estimation Based on Polynomial Expansion》。
我们可以通过Opencv的函数cv2.calcOpticalFlowFarneback寻找稠密光流,我们得到的一个两个通道的向量(u,v)。得到的该向量的大小和方向。用不同的颜色编码来使其可视化。
方向与Hue值相关,大小与Value值相关。
使用calcOpticalFlowFarneback函数得到:
flow=cv.calcOpticalFlowFarneback
(prev,
next,
flow,
pyr_scale,
levels,
winsize,
iterations,
poly_n,
poly_sigma,
flags)
返回值是每个像素点的位移
FlowNet的作者于2015年首先使用CNN解决光流估计问题,取得了较好的结果,并且在CVPR2017上发表改进版本FlowNet2.0,成为当时State-of-the-art的方法。截止到现在,FlowNet和FlowNet2.0依然和深度学习光流估计算法中引用率最高的论文,分别引用790次和552次。因此,深度学习光流估计算法将以FlowNet/FlowNet2.0为例介绍。
ICCV2015提出的FlowNet是最早使用深度学习CNN解决光流估计问题的方法,并且在CVPR2017,同一团队提出了改进版本FlowNet2.0。FlowNet2.0 是2015年以来光流估计邻域引用最高的论文。
待补充???
待补充???
光流,从物理意义的角度看,描述了视频中物体、对象在时间维度上的关联性,从而建立了视频中连续图像之间的关联关系。
因此,最为直接而自然的应用就是视频中物体的跟踪,在物体跟踪领域知名的TLD算法便借助了光流估计,
在视觉里程计和SLAM同步定位与建图领域,光流可以作为图像特征点匹配的一种方式,比如知名的视觉惯性里程计开源算法VINS-Mono。英伟达也提供了基于其GPU的光流SDK,其中展示了利用光流进行视频动作识别(video action recognition)和视频插帧的应用,