85 视频分析—KLT光流跟踪 02
代码
import numpy as np
import cv2 as cv
cap = cv.VideoCapture('../images/color_object.mp4')
def caldist(a, b, c, d):
return abs(a-c) + abs(b-d)
def KLTdemo():
# 角点检测参数
feature_params = dict(maxCorners=100, qualityLevel=0.01, minDistance=10, blockSize=3)
# KLT光流参数
lk_params = dict(winSize=(31, 31), maxLevel=3, criteria=(cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 30, 0.01))
# 随机颜色
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)
# 光流跟踪
while True:
ret, frame = cap.read()
if ret is False:
break
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# 计算光流
p1, st, err = cv.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# 根据状态选择
good_new = p1[st == 1]
good_old = p0[st == 1]
# 删除静止点
inits = 0
for i, (new, old) in enumerate(zip(good_new,good_old)):
a, b = new.ravel()
c, d = old.ravel()
distance = caldist(a, b, c, d)
if distance > 2:
good_new[inits] = good_new[i]
good_old[inits] = good_old[i]
inits += 1
good_new = good_new[:inits]
good_old = good_old[:inits]
# 绘制跟踪线
for i, (new, old) in enumerate(zip(good_new,good_old)):
a,b = new.ravel()
c,d = old.ravel()
frame = cv.line(frame, (a,b),(c,d), color[i].tolist(), 2)
frame = cv.circle(frame,(a,b),5,color[i].tolist(),-1)
cv.imshow('frame',frame)
k = cv.waitKey(30) & 0xff
if k == 27:
break
# 更新
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1, 1, 2)
if inits < 20:
p0 = cv.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
cv.destroyAllWindows()
cap.release()
if __name__ == '__main__':
KLTdemo()
实验结果
解释
光流跟踪方法分为稠密光流跟踪与稀疏光流跟踪算法,KLT是稀疏光流跟踪算法,这个算法最早是由Bruce D. Lucas and Takeo Kanade两位作者提出来的,所以又被称为KLT。稀疏光流算法工作有三个假设前提条件:
- 亮度恒定
- 短距离移动
- 空间一致性
OpenCV中KLT算法API及其参数解释如下:
nextPts, status, err = cv.calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, nextPts[, status[, err[, winSize[, maxLevel[, criteria[, flags[, minEigThreshold]]]]]]])
prevImg
前一帧图像nextImg
后一帧图像prevPts
前一帧的稀疏光流点nextPts
后一帧光流点status
输出状态,1 表示正常该点保留,否则丢弃err
表示错误winSize
= Size(21, 21) 光流法对象窗口大小maxLevel
= 3 金字塔层数,0表示只检测当前图像,不构建金字塔图像criteria
= TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01) 窗口搜索时候停止条件flags
= 0 操作标志minEigThreshold
= 1e-4 最小特征值响应,低于最小值不做处理
在84的知识点分享中我们已经可以跟踪到前后两帧之前的位置移动,但是这个还不足够,我们需要绘制移动对象从初始到最终的完整可以检测的运动轨迹,同时对一些静止的角点进行删除,所以我们需要对状态为1的角点,计算它们之间的距离,只有dx+dy > 2(dx=abs(p1.x –p2.x), dy=abs(p1.y-p2.y))的我们才对它进行保留跟踪。
所有内容均来源于贾志刚老师的知识星球——OpenCV研习社,本文为个人整理学习,已获得贾老师授权,有兴趣、有能力的可以加入贾老师的知识星球进行深入学习。