在我们平常做目标检测或者目标追踪时,经常要画出目标的轨迹图。绘制轨迹图的一种方法就是利用光流估计来进行绘制。
本期我们主要来介绍视频中光流估计的使用和效果,利用光流估计来绘制运动轨迹。
完成本期内容,你可以:
若要运行案例代码,你需要有:
操作系统:Ubuntu 16.04
工具软件:PyCharm 2020.1.5, Anaconda3 2020.07
硬件环境:无特殊要求
核心库:python 3.6.13, opencv-python 3.4.2.16
(1) OpenCV中的函数 cv2.VideoCapture() 可以用来完成摄像头的初始化工作。其语法格式如下:
dst = cv2.VideoCapture(index)
说明:
(2) OpenCV中的函数 cv2.isOpened() 可以用来判断当前的摄像头是否初始化成功。其语法格式如下:
retval = cv2.VideoCapture.isOpened()
说明:
(3) OpenCV中的函数 cv2.VideoCapture.read()可以用来进行帧捕捉。其语法格式如下:
retval, image=cv2.VideoCapture.read()
说明:
(4) OpenCV中的函数 cv2.VideoCapture.release()可以用来进行释放摄像头。其语法格式如下:
None=cv2.VideoCapture.release()
说明:
**(1)**OpenCV中的函数 cv2.VideoWriter() 可以用来创建类对象。其语法格式如下:
<VideoWriter object> = cv2.VideoWriter( filename, fourcc, fps, frameSize)
参数说明:
**(2)**OpenCV中的函数 cv2.VideoWriter.write()可以用来进行帧捕捉。其语法格式如下:
None=cv2.VideoWriter.write(image)
说明:
**(3)**OpenCV中的函数 cv2.VideoCapture.release()可以用来进行释放摄像头。其语法格式如下:
None=cv2.VideoCapture.release()
说明:
Opencv中使用cv2.calcOpticalFlowPyrLK()函数计算一个稀疏特征集的光流其语法格式如下:
nextPts,status,err = cv2.calcOpticalFlowPyrLK(prevImg,nextImg,prevPts,nextPts,[, status[, err[, winSize[, maxLevel[, criteria[, flags[, minEigThreshold]]]]]]])
参数说明:
Opencv的函数cv2.calcOpticalFlowFarneback寻找稠密光流。其语法格式如下:
flow=cv.calcOpticalFlowFarneback(prev,next, flow,pyr_scale, levels, winsize,iterations, poly_n, poly_sigma, flags)
参数说明:
光流估计的流程通常包含以下步骤:
使用高通滤波提取图像边缘。
创建项目名为绘制物体的运动轨迹,项目根目录下新建code文件夹储存代码,新建dataset文件夹储存数据,项目结构如下:
绘制物体的运动轨迹 # 项目名称
├── code # 储存代码文件
├── dataset # 储存数据文件
注:如项目结构已存在,无需再创建。
dataset文件夹下的dog.mp4 视频;代码实现
import numpy as np
import cv2 as cv
# 读取视频
cap = cv.VideoCapture('../dataset/dog.mp4')
代码实现
# 设置ShiTomasi 角点检测的参数
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7,
blockSize = 7 )
代码实现
# 设置lucas kanade 光流的参数
lk_params = dict( winSize = (15,15),
maxLevel = 2,
criteria = (cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 0.03))
# 创建一些随机颜色
color = np.random.randint(0,255,(100,3))
代码实现
# 读取第一帧
ret, old_frame = cap.read()
old_gray = cv.cvtColor(old_frame, cv.COLOR_BGR2GRAY)
# 跟踪检测图像中的角点
p0 = cv.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
# 为绘图目的创建掩码图像
mask = np.zeros_like(old_frame)
代码实现
while(1):
ret,frame = cap.read()
if frame is None:
break
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# 需要传入前一帧和当前图像以及前一帧检测到的角点
p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# 选择好的点,st=1表示找到特征点
if p1 is not None:
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 = cv.line(mask, (int(a),int(b)),(int(c),int(d)), color[i].tolist(), 2)
frame = cv.circle(frame,(int(a),int(b)),5,color[i].tolist(),-1)
img = cv.add(frame,mask)
cv.imshow('frame',img)
k = cv.waitKey(30) & 0xff
if k == 27:
break
# 现在更新上一帧和之前的点
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1,1,2)
cv.destroyAllWindows()
cap.release()

本期重点是使用稀疏光流进行图像运动轨迹的绘制,这对于目标检测或追踪有着重要的意义。