33运动与跟踪-LK光流
一.基于特征点的目标跟踪的一般方法
基于特征点的跟踪算法大致可以分为两个步骤:
1)探测当前帧的特征点;
2)通过当前帧和下一帧灰度比较,估计当前帧特征点在下一帧的位置;
3)过滤位置不变的特征点,余下的点就是目标了。
很显然,基于特征点的目标跟踪算法和1),2)两个步骤有关。特征点可以是Harris角点(见我的另外一篇博文),也可以是边缘点等等,而估计下一帧位置的方法也有不少,比如这里要讲的光流法,也可以是卡尔曼滤波法
二.光流法
这一部分《learing opencv》一书的第10章Lucas-Kanade光流部分写得非常详细,推荐大家看书。我这里也粘帖一些选自书中的内容。
另外我对这一部分附上一些个人的看法(谬误之处还望不吝指正):
1.首先是假设条件:
(1)亮度恒定,就是同一点随着时间的变化,其亮度不会发生改变。这是基本光流法的假定(所有光流法变种都必须满足),用于得到光流法基本方程;
(2)小运动,这个也必须满足,就是时间的变化不会引起位置的剧烈变化,这样灰度才能对位置求偏导(换句话说,小运动情况下我们才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数),这也是光流法不可或缺的假定;
(3)空间一致,一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度一致。这是Lucas-Kanade光流法特有的假定,因为光流法基本方程约束只有一个,而要求x,y方向的速度,有两个未知变量。我们假定特征点邻域内做相似运动,就可以连立n多个方程求取x,y方向的速度(n为特征点邻域总点数,包括该特征点)。
2.方程求解
多个方程求两个未知变量,又是线性方程,很容易就想到用最小二乘法,事实上opencv也是这么做的。其中,最小误差平方和为最优化指标。
3.好吧,前面说到了小运动这个假定,聪明的你肯定很不爽了,目标速度很快那这货不是二掉了。幸运的是多尺度能解决这个问题。首先,对每一帧建立一个高斯金字塔,最大尺度图片在最顶层,原始图片在底层。然后,从顶层开始估计下一帧所在位置,作为下一层的初始位置,沿着金字塔向下搜索,重复估计动作,直到到达金字塔的底层。聪明的你肯定发现了:这样搜索不仅可以解决大运动目标跟踪,也可以一定程度上解决孔径问题(相同大小的窗口能覆盖大尺度图片上尽量多的角点,而这些角点无法在原始图片上被覆盖)。
4.另外还需要了解时域导数和空域导数,通过这两个值可以求出像素点的速度,从而估计出像素点在下一帧中的位置:
Ix=dI/dx|t
It=dI/dt|x=p点的位置
V=-Ix/It
5.稠密光流:是一种针对图像进行逐点匹配的图像配准方法,不同于稀疏光流只针对图像上若干个特征点,稠密光流计算图像上所有的点的偏移量,从而形成一个稠密的光流场。通过这个稠密的光流场,可以进行像素级别的图像配准,所以其配准后的效果也明显优于稀疏光流配准的效果。但是其副作用也是明显的,由于要计算每个点的偏移量,其计算量也明显大于稀疏光流
三 函数接口:
1.下面函数实现了非金字塔的Lucas-Kannade稠密光流的算法:
void cvCacOpticalFlowLK(
const CvArr* imgA,
const CvArr* imgB,
CvSize win_Size,
CvSize velx,
CvSize vely,
)
这个函数的输出只记录了可以计算最小误差的像素。对于最小误差不能被可靠的计算出的像素,相关的速度被设置为0,多数情况下我们不会使用这个函数。
2.下面函数在图像金字塔中计算Lucas-kanade光流的算法,这个计算光流的函数使用了“易于跟踪的特征点”并返回每个点被跟踪的情况:
void cvCalcOpticalFlowPyrLK(
const CvArr* prev,
const CvArr* curr,
CvArr* prevPyr,