光流计算基于物体移动的光学特性提出了2个假设:
①运动物体的灰度在很短的间隔时间内保持不变;
②给定邻域内的速度向量场变化是缓慢的。
假设图像上一个像素点(x,y),在t时刻的亮度为E(x+Δx,y+Δy,t+Δt)
同时用u(x,y)和v(x,y)来表示该点光流在水平和垂直方向上的移动分量:u=dx/dt v=dy/dt
当该点的亮度有变化时,将移动后点的亮度由Taylor公式展幵,可得:
忽略其二阶无穷小,由于Δt趋近于0时,有:
式中w=(u,v),所以上式就是基本的光流约束方程。
其中令表示图像中像素点灰度沿x,y,t方向的梯度,可将上式改写成:
令I0 = I 是第 0 层的图像,它是金字塔图像中分辨率最高的图像,图像的宽度和高度分别定义为nx0 = nx 和 ny0 = ny 。以一种递归的方式建立金字塔:从I0中计算I1,从I1中计算I2 ,···。令L =1, 2,...代表金字塔的层数,L通常取2,3,4。IL−1 是第L−1层的图像,nxL−1 和 nyL−1分别是图像IL−1 的宽度和高度。图像IL可按如下方式由IL−1 求得:
即用一个[0.25 0.5 0.25]的低通滤波器对IL-1进行卷积。
总体来讲,金字塔特征跟踪算法描述如下:首先,光流和仿射变换矩阵在最高一层的图像上计算出;将上一层的计算结果作为初始值传递给下一层图像,这一层的图像在这个初始值的基础上,计算这一层的光流和仿射变化矩阵;再将这一层的光流和仿射矩阵作为初始值传递给下一层图像,直到传递给最后一层,即原始图像层,这一层计算出来的光流和仿射变换矩阵作为最后的光流和仿射变换矩阵的结果。
对于L=0,1,2,…L,定义是图像中像素点u在第L层对应点的坐标。根据上一步中图像金字塔的定义,可以计算出
我们用数学的思想重新描述在L层和L+1层迭代运算,假定在第L层有对被跟踪目标的位置有个大致估计,而从第L+1层传递到L层的运动矢量,即光流计算初值为(后面会对gL做一个解释)并且对于最上层的变换矩阵猜测
为了在L层上计算光流和仿射变换矩阵,需要重新定义在L层上的匹配误差ξL:
其中图像和是原始图像在L层上采样出来的图像,基于这层中的光流和仿射矩阵初值gL和GL可以计算出两个对应图像和:
这里用L+1层得到的最初估计gL对L层作预平移,L层在gL的基础上求该层的光流dL,这样求得的残余光流向量dL= [dLx, dLy]T就足够小,因此能够通过标准的光流法来求出这个运动矢量。然后得到的dL结合gL又可以对L-1层的gL-1做估计。最终的光流和就是在所有层的分段光流d的叠加。使用金字塔图像计算光流的一个明显的好处是,对于一个有着较大的像素偏移的矢量d,可以通过计算几个比较小的残余光流来得到。这里就是金字塔跟踪算法的核心。
接下来就是计算该层上的光流dL和变换矩阵AL,我们将在下一步中谈论。现在,假设在这一层上的光流和变换矩阵己经计算出来。接着将结果传递给下一层,计算出下一层的假设初值:
将gL-1和GL-1作为初值,重新循环上面的步骤,直到最上一层,计算出光流d和仿射变换矩阵A。
由于金字塔的缩放减小了光流值,最高层的光流估计值可以设为0,设顶层时的初始为:
这种算法最明显的优势在于对于每一层的光流都会保持很小,但是最终计算来的光流可以进行累积,便于有效地跟踪特征点。
这一步是算法的核心步骤。在金字塔的每一层,目标是计算出光流dL和仿射变换矩阵AL从而使误差ξL最小。由于每一层的迭代过程是相同的,所以我们就描述从一层到下一层的迭代过程。首先将上一层的光流u和A传给这一层,计算这一帧图像中像素点的光照,同时计算出图像在该点x方向和y方向上的偏导
Ix=[I(x+1,y)-I(x-1,y)]/2
Iy=[I(x,y+1)-I(x,y-1)]/2
在此基础上,计算出空间梯度矩阵:
更新光流v=2*v
迭代过程:计算后一帧图像中对应像素点的灰度,计算两
帧图像间相同位置点的灰度值之差,在计算图像之间的误差
向量:
最后计算针对仿射光流
,
更新跟踪结果
直到某个阈值,结束在这一层的迭代过程。
因此,可按照以下的步骤选择特征点:
1、计算图像 I 中每一个像素的矩阵G和最小特征值λm。
2、寻找整副图像中最小特征值 λm 中的最大特征值λmax。
3、保留最小特征值 λm 大于给定阈值的像素点。阈值通常取5% λmax ~10% λmax 。
4、保留 λm 局部最大值的像素:像素特征值 λm 大于其3*3 邻域中其他像素的特征值 λm 。
5、剔除像素密集区域中的一些像素,确保图像中相邻像素的距离都大于给定的阈值(常取5~10 pixels)。
上述操作完成后,图像 I 中剩下的像素即为选择的特征点,并作为跟踪特征点。特征点选择算法的步骤5 确保了特征点间的最小距离。
没有必要取一个大的综合窗口选择特征点(或计算矩阵G)。大量实验证明,wx = wy =1的 3*3 大小的综合窗口能够取得满意的效果。
在大多数的情况下,超过4的金字塔图像层次没有太大的意义。
有时为了简化可以将仿射变换矩阵G简化为单位矩阵。
1.首先是假设条件:
(1)亮度恒定,就是同一点随着时间的变化,其亮度不会发生改变。这是基本光流法的假定(所有光流法变种都必须满足),用于得到光流法基本方程;
(2)小运动,这个也必须满足,就是时间的变化不会引起位置的剧烈变化,这样灰度才能对位置求偏导(换句话说,小运动情况下我们才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数),这也是光流法不可或缺的假定;
(3)空间一致,一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度一致。这是Lucas-Kanade光流法特有的假定,因为光流法基本方程约束只有一个,而要求x,y方向的速度,有两个未知变量。我们假定特征点邻域内做相似运动,就可以连立n多个方程求取x,y方向的速度(n为特征点邻域总点数,包括该特征点)。
2.方程求解
多个方程求两个未知变量,又是线性方程,很容易就想到用最小二乘法,事实上opencv也是这么做的。其中,最小误差平方和为最优化指标。
算法步骤如下:
(1)令i=1,获得第i帧图像I(x,i);
(2)获得第i+1帧图像I(x,i+1);
(3)对图像去噪,得到去燥后图像I '(x, i)和I '(x, i+1);
(4)利用I '(x, i)和I '(x, i+1)计算得到光流场;
(5)计算得到局部动能场K(i);
(6)利用边缘检测算法(如基于小波的方法)局部动能场并分割图像得到不同的运动单元也理解为一个运动单元);
(7)由于目标一般较背景小,故提取出体积较运动单元作为检测目标;
(8)计算其质心作为目标位置;
(9)置i=i+1,重复(2)~(8),直至检测结束。
cvCalcOpticalFlowPyrLK 函数在使用时,首先要确定特征点,也就是目标旧的位置。
本程序通过使用cvGoodFeaturesToTrack 函数选择角点作为特征点。
prev_pyramid = cvCreateImage (cvSize (src_img1->width + 8, src_img1->height / 3), IPL_DEPTH_8U, 1);
curr_pyramid = cvCreateImage (cvSize (src_img1->width + 8, src_img1->height / 3),IPL_DEPTH_8U, 1);
cvGoodFeaturesToTrack (src_img1, eig_img, temp_img, corners1, &corner_count, 0.001, 5, NULL);
cvCalcOpticalFlowPyrLK (src_img1, src_img2, prev_pyramid,curr_pyramid,
corners1, corners2, corner_count, cvSize (10, 10), 4, status, NULL, criteria, 0);
for (i = 0; i < corner_count; i++)
{
if (status[i])
cvLine (dst_img, cvPointFrom32f (corners1[i]), cvPointFrom32f (corners2[i]),CV_RGB (255, 0, 0), 1, CV_AA, 0);
}
在光流理论中,前提是下面两个假设成立:
1)摄像头采集到的两帧图像之间的像素灰度不变;
2)相邻的两帧像素具有相对运动;
根据第一个假设,如果两帧的灰度值不变,那么有以下关系成立:
其中 I(x,y,t)表示在时间dt后移动到第二帧图像(x+dx,y+dy)的位置,采用泰勒级数对两边进行展开,消去相同的项,就可以得到如下方程:
其中:
以上就是光流方程,其中fx和fy表示图像的梯度,ft表示时间梯度,但是上述方法是无法得到(u,v),因为一个等式无法求解两个未知数,为了解决这个问题,我们可以采用经典的lucas-Kanade方法来进行求解。
在lucas-Kanade方法中,我们需要用到我们第二个假设了,即在目标点的邻域内所有的点都具有相似的运动,这就是lucas-kanade方法的核心,基于该假设,其利用一个3X3邻域中的9个点具有相同运动得到9个光流方程,然后采用最小二乘进行拟合求解,最终得到(u,v)如下:
以上就是光流法计算像素点的移动速度的方法,在使用的时候,我们只需要对图像中的一些点去跟踪,采用上面的方法就可以计算得到光流向量,根据得到的光流向量,就可以进一步优化无人机的姿态控制,实现更加准确的控制