在上次的博文OpenCV4学习笔记(33)——KLT稀疏光流跟踪算法中,整理记录的OpenCV中对于KLT稀疏光流跟踪的实现,同时也提到了光流跟踪算法除了稀疏光流跟踪以外,还有稠密光流跟踪算法。所以今天要整理的笔记内容就是在OpenCV中对于稠密光流跟踪算法的实现。
先来回顾一下KLT稀疏光流跟踪算法,它是基于shi-tomas角点检测来实现的,只需要每个特征角点的邻域空间窗口内的局部信息来实现光流跟踪。这种基于局部点的光流跟踪方法带来的优点是运行速度快,但是缺点则是跟踪效果较为一般。
而Farneback稠密光流算法则是基于前后两帧图像中所有像素点的移动估算算法,通过前后两帧图像中所有像素点的位移矢量来实现光流跟踪。由于Fb稠密光流算法需要检测所有像素点的光流,所以其效果比稀疏光流算法要更好,但是相对而言其速度更慢,如果没有经过特殊优化的化是不适合用于实时处理的。
Farneback稠密光流算法的主要实现思路是通过每个像素点的邻域信息(由邻域像素点的像素值大小和位置来确定权重)来对该像素点的坐标位置进行多项式展开,得到一个以原坐标(x0,y0)为自变量,新坐标(x,y)为因变量的多项式,并代入坐标数据来求取该像素点在x和y方向上的移动量(dx,dy)。这样就得到了每个像素点在前后两帧图像中的位移矢量,包含振幅和相位。
如果我们将每个像素点位移矢量的振幅和相位信息转化为H、S、V三通道信息,就可以在视频流中直观地观察运动物体的运动情况了,也就实现了对于运动物体的稠密光流跟踪。
在OpenCV中提供了calcOpticalFlowFarneback()
这个API来进行稠密光流的计算,这个API使用的是图像金字塔的FB稠密光流算法,它是对上一帧和当前帧图像分别建立图像金字塔,再分别对两个图像金字塔自顶向底地对同一层图像进行FB算法的计算。由于在低分辨率层图像中,运动速度较快的物体不易逃脱检测窗口的捕捉,有利于检测运动程度较大的目标,所以使用图像金字塔的FB稠密光流算法相比一般的FB稠密光流算法具有更好的鲁棒性,能够允许目标比较大程度的运动。
calcOpticalFlowFarneback()
的参数含义如下:
第一个参数prev:输入的上一帧图像,为8位单通道图;
第二个参数next:输入的当前帧(或者叫下一帧)图像,为8位单通道图;
第三个参数flow:输出的光流矩阵,其尺寸和输入图像一致,矩阵中每个元素都是一个Point2f
类型的点,表示在输入图像中相同位置的像素点在上一帧和当前帧图像中分别在x方向和y方向的位移,即(dx,dy);
第四个参数pyr_scale:生成图像金字塔时上下两层的缩放比例,取值范围是0~1;当该参数为0.5时,即为经典的图像金字塔;
第五个参数level:生成的图像金字塔的层数;当level=0时表示不使用图像金字塔的FB稠密光流算法;一般取level=3;
第六个参数winsize:表示滤波和检测的窗口大小,该参数越大对噪声抑制能力越强,并且能够检测快速移动目标(目标像素点不会移出窗口),但会引起运动区域的模糊;
第七个参数iterations:对每层金字塔图像进行FB算法时的迭代次数;
第八个参数poly_n:对当前像素点进行多项式展开时所选用的邻域大小,该参数值越大,运动区域模糊程度越大,对目标运动检测更稳定,会产生更鲁棒的算法和更模糊的运动场,官方推荐poly_n = 5或7;
第九个参数poly_sigma:进行多项式展开时的高斯系数;推荐值为:当poly_n = 5时,poly_sigma = 1.1;当poly_n = 7时,poly_sigma = 1.5;
第十个参数flag:进行光流估算的滤波器,有以下两种选择:
(1)OPTFLOW_USE_INITIAL_FLOW
使用输入流作为初始流近似值,并使用盒子滤波器进行光流估算;
(2)OPTFLOW_FARNEBACK_GAUSSIAN
使用高斯滤波器进行光流估算,高斯滤波器相比盒子滤波器的估算结果更精确,但运行速度较慢。
下面是具体的代码演示:
VideoCapture capture;
//capture.open("D:\\opencv_c++\\opencv_tutorial\\data\\images\\video.avi");
capture.open("D:\\OpenCV\\opencv\\sources\\samples\\data\\vtest.avi");
if (!capture.isOpened<