一、什么是光流?
光流(Optical Flow)是计算机视觉中描述图像序列中像素运动模式的重要概念。它表示图像中物体在连续帧之间的表观运动,是由物体或相机的运动引起的。
光流的基本假设
- 亮度恒常性:同一物体点在连续帧中的亮度保持不变
- 时间持续性:运动随时间缓慢变化
- 空间一致性:邻近点有相似的运动
二、OpenCV中的光流算法
OpenCV提供了多种光流算法的实现,主要包括:
1. Lucas-Kanade方法
import cv2
import numpy as np
# 读取视频
cap = cv2.VideoCapture('test.mp4')
# 参数设置
feature_params = dict(maxCorners=100, qualityLevel=0.3, minDistance=7, blockSize=7)
lk_params = dict(winSize=(15,15), maxLevel=2,
criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
# 读取第一帧
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
# 创建随机颜色
color = np.random.randint(0,255,(100,3))
while(1):
ret, frame = cap.read()
if not ret:
break
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 计算光流
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# 选择好的点
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()
frame = cv2.line(frame, (a,b),(c,d), color[i].tolist(), 2)
frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)
cv2.imshow('frame',frame)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
# 更新前一帧和特征点
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1,1,2)
cv2.destroyAllWindows()
cap.release()
2. Farneback稠密光流
import cv2
import numpy as np
cap = cv2.VideoCapture('test.mp4')
ret, frame1 = cap.read()
prvs = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
hsv = np.zeros_like(frame1)
hsv[...,1] = 255
while(1):
ret, frame2 = cap.read()
if not ret:
break
next = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
# 计算稠密光流
flow = cv2.calcOpticalFlowFarneback(prvs, next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
# 转换为极坐标
mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1])
hsv[...,0] = ang*180/np.pi/2
hsv[...,2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
cv2.imshow('frame2', bgr)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
elif k == ord('s'):
cv2.imwrite('opticalfb.png',frame2)
cv2.imwrite('opticalhsv.png',bgr)
prvs = next
cap.release()
cv2.destroyAllWindows()
3. DeepFlow和DIS光流
OpenCV还提供了基于深度学习的DIS(Dense Inverse Search)光流算法:
# 初始化DIS光流
dis = cv2.DISOpticalFlow_create(cv2.DISOPTICAL_FLOW_PRESET_FAST)
# 计算光流
flow = dis.calc(prev_frame, next_frame, None)
三、光流估计的应用
- 运动检测与跟踪:通过光流可以检测视频中的运动物体
- 视频稳定:利用光流估计相机运动并进行补偿
- 动作识别:分析人体关节点的光流模式来识别动作
- 自动驾驶:估计车辆自身运动和周围物体的运动
- 视频插帧:基于光流生成中间帧
四、光流估计的挑战与改进
- 光照变化:亮度恒常性假设在实际中常被违反
- 遮挡问题:物体被遮挡时难以追踪
- 快速运动:大位移运动难以捕捉
- 计算效率:实时性要求高的场景需要优化
改进方法:
- 使用深度学习模型如FlowNet、PWC-Net
- 多尺度处理
- 结合其他特征如深度信息
五、总结
OpenCV提供了丰富的光流估计算法实现,从经典的Lucas-Kanade到基于深度学习的方法。理解光流的基本原理并掌握OpenCV中的实现方法,能够为计算机视觉应用的开发奠定坚实基础。在实际应用中,需要根据具体场景选择合适的光流算法,并考虑其精度和效率的平衡。