视频处理
1. 提取前景模版–[当前帧和背景模型之间执行减法运算]
from __future__ import print_function
import cv2 as cv
import argparse
# argparse将命令行全部信息解析成python数据类型可使用的数据
parser = argparse.ArgumentParser(description='此程序显示如何使用\提供的背景减法OpenCV。您可以同时处理视频和图像。') #创建一个解析器
parser.add_argument('--input', type=str, help='视频/图像序列路径', default='vtest.avi')
parser.add_argument('--algo', type=str, help='背景减法方法(KNN, MOG2).', default='MOG2')
# parser.add_argument(命名/列表,类型,...) 添加参数
args = parser.parse_args() #解析参数
# 创建背景减法器对象
if args.algo == 'MOG2':
# cv.createBackgroundSubtractorMOG2(history长度,像素与模型之间的Mahalanobis距离平方的阈值,是否检测并标记阴影)
backSub = cv.createBackgroundSubtractorMOG2()
else:
backSub = cv.createBackgroundSubtractorKNN() #参数同上
# 读取输入视频或输入图像序列
capture = cv.VideoCapture(cv.samples.findFileOrKeep(args.input))
if not capture.isOpened:
print('Unable to open: ' + args.input)
exit(0)
while True:
ret, frame = capture.read() #获取每一帧
if frame is None:
break
fgMask = backSub.apply(frame) #将背景应用在每一帧,用于计算前景蒙版和更新背景
cv.rectangle(frame, (10, 2), (100,20), (255,255,255), -1) #frame上绘制白色矩形,用于突出显示黑色的帧编号
# 在图像上绘制文字cv.putText(待绘制的图像,待绘制文字,文本框左下角,字体,字体尺寸,线条颜色,线条宽度)
cv.putText(frame, str(capture.get(cv.CAP_PROP_POS_FRAMES)), (15, 15),
cv.FONT_HERSHEY_SIMPLEX, 0.5 , (0,0,0)) #将当前帧号标注在左上角
# 显示当前帧和前景蒙版
cv.imshow('Frame', frame)
cv.imshow('FG Mask', fgMask)
keyboard = cv.waitKey(30)
if keyboard == 'q' or keyboard == 27:
break
2. 跟踪视频对象–Meanshift和Camshift
- 原理:我们通常会传递直方图反投影图像和初始目标位置。当对象移动时,显然该移动会反映在直方图反投影图像中。结果,meanshift算法将我们的窗口以最大密度移动到新位置。
Meanshift
import numpy as np
import cv2 as cv
import argparse
parser = argparse.ArgumentParser(description='This sample demonstrates the meanshift algorithm. \
The example file can be downloaded from: \
https://www.bogotobogo.com/python/OpenCV_Python/images/mean_shift_tracking/slow_traffic_small.mp4')
parser.add_argument('image', type=str, help='图像文件路径')
args = parser.parse_args()
cap = cv.VideoCapture(args.image)
# 读视频的第一帧
ret,frame = cap.read()
# 设置窗口的初始位置
x, y, w, h = 300, 200, 100, 50
track_window = (x, y, w, h)
# 设置用于跟踪的ROI
roi = frame[y:y+h, x:x+w] #取一帧的某块(x,y,w,h)
hsv_roi = cv.cvtColor(roi, cv.COLOR_BGR2HSV) #颜色从BGR变成HSV
# 取出在上下限范围内的图像区域 cv.inRange(目标图像,阈值下限,阈值上限)
mask = cv.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
roi_hist = cv.calcHist([hsv_roi],[0],mask,[180],[0,180]) #获取hsv_roi的直方图
cv.normalize(roi_hist,roi_hist,0,255,cv.NORM_MINMAX) #归一化到(0,255)内
# 设置终止条件,可以是10次迭代或至少移动1 pt
term_crit = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 )
while(1):
ret, frame = cap.read()
if ret == True:
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
dst = cv.calcBackProject([hsv],[0],roi_hist,[0,180],1) #获取输入图像直方图的反向投影图
# 应用meanshift获取新位置
# cv.meanShift(反向投影图,跟踪目标初始矩形框,算法结束条件)
ret, track_window = cv.meanShift(dst, track_window, term_crit)
# 在图像上绘制
x,y,w,h = track_window
img2 = cv.rectangle(frame, (x,y), (x+w,y+h), 255,2)
cv.imshow('img2',img2)
k = cv.waitKey(30) & 0xff
if k == 27:
break
else:
break
Camshift
import numpy as np
import cv2 as cv
import argparse
parser = argparse.ArgumentParser(description='This sample demonstrates the camshift algorithm. \
The example file can be downloaded from: \
https://www.bogotobogo.com/python/OpenCV_Python/images/mean_shift_tracking/slow_traffic_small.mp4')
parser.add_argument('image', type=str, help='path to image file')
args = parser.parse_args()
cap = cv.VideoCapture(args.image)
ret,frame = cap.read()
x, y, w, h = 300, 200, 100, 50
track_window = (x, y, w, h)
roi = frame[y:y+h, x:x+w]
hsv_roi = cv.cvtColor(roi, cv.COLOR_BGR2HSV)
mask = cv.inRange(hsv_roi, np.array((0., 60.,32.)), np.array((180.,255.,255.)))
roi_hist = cv.calcHist([hsv_roi],[0],mask,[180],[0,180])
cv.normalize(roi_hist,roi_hist,0,255,cv.NORM_MINMAX)
term_crit = ( cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1 )
while(1):
ret, frame = cap.read()
if ret == True:
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
dst = cv.calcBackProject([hsv],[0],roi_hist,[0,180],1)
# 应用Camshift获取新位置
# cv.CamShift()参数同上
ret, track_window = cv.CamShift(dst, track_window, term_crit)
# 在图像上绘制
pts = cv.boxPoints(ret)
pts = np.int0(pts)
img2 = cv.polylines(frame,[pts],True, 255,2)
cv.imshow('img2',img2)
k = cv.waitKey(30) & 0xff
if k == 27:
break
else:
break
3. 光流
跟踪计算稀疏特征集的光流
import numpy as np
import cv2 as cv
import argparse
parser = argparse.ArgumentParser(description='This sample demonstrates Lucas-Kanade Optical Flow calculation. \
The example file can be downloaded from: \
https://www.bogotobogo.com/python/OpenCV_Python/images/mean_shift_tracking/slow_traffic_small.mp4')
parser.add_argument('image', type=str, help='path to image file')
args = parser.parse_args()
cap = cv.VideoCapture(args.image)
# 用于shiTomasi角点检测的参数[maxCorners角点最大数量、quanlityLevel可接受最小特征值、minDistance角点间最小距离、blockSize计算角点时参与运算的区域大小]
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7,
blockSize = 7 )
# lucas kanade光流的参数[winSize每个金字塔等级的搜索窗口的winSize大小、maxLevel最大金字塔等级数、criteria指定迭代搜索算法的终止条件]
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) #转为灰度图
# 返回角点cv.goodFeaturesToTrack(输入图像,mask如果指定,它的维度必须和输入图像一致,且在mask值为0处不进行角点检测,feature_params其他参数)
p0 = cv.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
# 创建用于绘画的遮罩图像[全0数组]
mask = np.zeros_like(old_frame)
while(1):
ret,frame = cap.read()
frame_gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# 计算光流量
# 使用带有金字塔的迭代Lucas-Kanade方法计算稀疏特征集的光流 cv.calcOpticalFlowPyrLK(第一帧图像、下一帧图像、...、计算的光流点、金字塔缩放比例、初始图像金字塔层数、lk_params)
p1, st, err = cv.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() #转为一维数组,(x,y)
c,d = old.ravel()
mask = cv.line(mask, (a,b),(c,d), color[i].tolist(), 2)
frame = cv.circle(frame,(a,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)
查找密集光流
import numpy as np
import cv2 as cv
cap = cv.VideoCapture(cv.samples.findFile("vtest.avi"))
ret, frame1 = cap.read()
prvs = cv.cvtColor(frame1,cv.COLOR_BGR2GRAY)
hsv = np.zeros_like(frame1)
hsv[...,1] = 255
while(1):
ret, frame2 = cap.read()
next = cv.cvtColor(frame2,cv.COLOR_BGR2GRAY)
# cv.calcOpticalFlowFarneback(前一帧、后一帧、金字塔缩放比例、金字塔层数、窗口大小、金字塔每层迭代次数、在每个像素点计算多项式展开的相邻像素点个数、标准差[与前一个参数有对应关系]、flag[OPTFLOW_USE_INITIAL_FLOW/OPTFLOW_FARNEBACK_GAUSSIAN])
# 返回一个两通道的光流向量,实际上是每个点的像素位移值
flow = cv.calcOpticalFlowFarneback(prvs,next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
# cv.cartToPolar()笛卡尔坐标转化为极坐标
mag, ang = cv.cartToPolar(flow[...,0], flow[...,1])
hsv[...,0] = ang*180/np.pi/2 #角度
hsv[...,2] = cv.normalize(mag,None,0,255,cv.NORM_MINMAX) #归一化到0-255范围之内
bgr = cv.cvtColor(hsv,cv.COLOR_HSV2BGR) #再从HSV转换成BGR
cv.imshow('frame2',bgr)
k = cv.waitKey(30) & 0xff
if k == 27:
break
elif k == ord('s'):
cv.imwrite('opticalfb.png',frame2)
cv.imwrite('opticalhsv.png',bgr)
prvs = next