光流估计是计算机视觉领域的一项重要任务,它用于分析图像序列中像素在时间上的移动情况。光流估计可以帮助我们理解运动物体的轨迹、检测视频中的动作、实现目标跟踪和视频稳定等应用。OpenCV提供了多种光流估计算法来满足不同场景的需求,其中最常用的是基于Lucas-Kanade光流法和Farneback光流法。
- Lucas-Kanade光流法:
Lucas-Kanade光流法是一种稀疏光流估计方法,它基于一个关键假设:在图像中相邻像素的运动具有一定的空间一致性,即局部邻域内的像素运动相似。该方法假设像素的灰度值在时间上的变化可以通过一个2D运动向量来描述。
基本步骤:
首先,选择感兴趣的关键点或特征点,这些特征点在相邻帧中能够稳定检测到。
对每个特征点,构建一个窗口(或局部邻域),在该窗口内寻找对应的特征点。在相邻帧中,特征点周围的像素灰度值在时间上的变化由一个2D运动向量表示。
使用最小二乘法来优化运动向量,使得在窗口内的像素灰度值的误差最小化。
重复以上过程,直到所有特征点的运动向量被估计。
2. Farneback光流法:
Farneback光流法是一种稠密光流估计方法,它能够计算图像中每个像素的运动向量。相对于Lucas-Kanade光流法,Farneback光流法具有更高的计算复杂度,但能够提供更丰富的光流信息。
基本步骤:
先计算两帧图像之间的稠密光流场,得到每个像素的粗略运动向量。
对稠密光流场进行优化和插值,以得到更精确的光流信息。
最终得到图像中每个像素的运动向量,这些向量描述了像素在时间上的位移情况。
总的来说,光流估计方法能够帮助我们捕捉图像序列中的运动信息,从而实现目标跟踪、动作检测和视频稳定等应用。在OpenCV中,您可以通过调用相关函数如cv.calcOpticalFlowPyrLK()(Lucas-Kanade法)和cv.calcOpticalFlowFarneback()(Farneback法)来进行光流估计操作。
import numpy as np
import cv2
cap = cv2.VideoCapture('test.avi')
# 角点检测所需参数
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7)
# lucas kanade参数
lk_params = dict( winSize = (15,15),
maxLevel = 2)
# 随机颜色条
color = np.random.randint(0,255,(100,3))
# 拿到第一帧图像
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
# 返回所有检测特征点,需要输入图像,角点最大数量(效率),品质因子(特征值越大的越好,来筛选)
# 距离相当于这区间有比这个角点强的,就不要这个弱的了
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
# 创建一个mask
mask = np.zeros_like(old_frame)
while(True):
ret,frame = cap.read()
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 需要传入前一帧和当前图像以及前一帧检测到的角点
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# st=1表示
good_new = p1[st==1]
good_old = p0[st==1]
# 绘制轨迹
for i,(new,old) in enumerate(zip(good_new,good_old)):
a,b = new.ravel()
c,d = old.ravel()
mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2)
frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)
img = cv2.add(frame,mask)
cv2.imshow('frame',img)
k = cv2.waitKey(150) & 0xff
if k == 27:
break
# 更新
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1,1,2)
cv2.destroyAllWindows()
cap.release()
展示一下结果