光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪。
**完整代码:https://github.com/YvanYan/image_processing/tree/master/ofe
**
流程:
1.读取视频
2.设置角点检测参数和lucas kanade参数
3.逐帧对图像进行灰度处理、检测
4.绘制行动轨迹
import cv2
import numpy as np
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, first_frame = cap.read()
first_gray = cv2.cvtColor(first_frame, cv2.COLOR_BGR2GRAY)
p0 = cv2.goodFeaturesToTrack(first_gray, mask=None, **feature_params)
mask = np.zeros_like(first_frame)
while (True):
ret, cur_frame = cap.read()
cur_frame_gray = cv2.cvtColor(cur_frame, cv2.COLOR_BGR2GRAY)
p1, st, err = cv2.calcOpticalFlowPyrLK(first_gray, cur_frame_gray, p0, None, **lk_params)
good_cur = p1[st == 1]
good_first = p0[st == 1]
for i, (new, old) in enumerate(zip(good_cur, good_first)):
a, b = new.ravel()
c, d = old.ravel()
mask = cv2.line(mask, (a, b), (c, d), color[i].tolist(), 2)
frame = cv2.circle(cur_frame, (a, b), 5, color[i].tolist(), -1)
img = cv2.add(cur_frame, mask)
cv2.imshow('frame', img)
k = cv2.waitKey(150) & 0xff
if k == 27:
break
# 更新
first_gray = cur_frame_gray.copy()
# p0 = good_cur.reshape(-1,1,2)
p2 = cv2.goodFeaturesToTrack(first_gray, mask=None, **feature_params)
if abs(len(p2) - len(p0)) >= 5:
p0 = p2
else:
p0 = p1
cv2.destroyAllWindows()
cap.release()
goodFeaturesToTrack(image, corners, maxCorners, qualityLevel, minDistance, mask, blockSize, useHarrisDetector, k) 。
image是输入图像。
corners是检测到的所有角点。maxCorners表示检测的点数的最大值。
qualityLevel表示检测到的角点的质量水平(通常是0.0.-0.1之间,不能大于1.0)。
minDistance表示两个相邻角点的最小距离,小于这个距离的将进行合并。
mask在指定的mask为0的地方不进行检测。
blockSize计算角点时参与计算的区域大小,常用值为3。
useHarrisDetector指定角点检测的方法,如果是true则使用Harris角点检测,false则使用Shi Tomasi算法。
k在使用Harris算法时使用,最好使用默认值0.04。calcOpticalFlowPyrLK(prevImage, nextImage, prevPts, winSize, maxLevel)
prevImage前一帧图像。
nextImage当前帧图像。
prevPts待跟踪的特征点向量。
winSize搜索窗口的大小。
maxLevel最大的金字塔层数。
返回值:nextPts 输出跟踪特征点向量。status表示特征点是否找到,找到的状态为1,未找到的状态为0。err为错误信息。
由于原代码中,只能检测第一帧画面画面中的人物轨迹,因此我将角点更新那里进行了简单的修改。