CV_tutorial3
- 摄像头调用
- +实时播放
- +保存视频
- 运动目标识别
- 帧差法
- 背景减除法
摄像头调用
创建视频捕捉对象:cv2.VideoCapture()
参数为视频设备的索引号,就一个摄像投的话写0默认;
或者是指定要读取视频的路径。
+实时播放
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
# 创建循环结构连续按帧读取视频
while (True):
# ret返回布尔值,frame三维矩阵(每一帧的图像)
ret, frame = cap.read()
# 并展示
cv2.imread('frame', frame)
# 按下‘q’键退出循环
if cv2.waitKey(1) && 0xFF ==ord('q'):
break
cap.release() # 释放资源
cv2.destroyAllWindows()
+保存视频
cv2.VideoWriter()
import cv2
cap = cv2.VideoCapture(0)
#创建编码方式
# mp4:'X','V','I','D'
# avi:'M','J','P','G'或'P','I','M','1'
# flv:'F','L','V','1'
fourcc = cv2.VideoWriter_fourcc('X','V','I','D')
# 创建VideoWriter对象
out = cv2.VideoWriter('ouput_1.mp4', fourcc, 20.0, (640, 480)) # 播放帧率,大小
# 创建循环结构进行连续读写
while(cap.isOpened()):
ret, frame = cap.read()
if ret == True:
out.write(frame)
cv2.imshow('frame', frame)
if cv2.waitKey(1) && 0xFF == ord('q'):
break
else:
break
cap.release()
out.release()
cv2.destryAllWindows()
运动目标识别
帧差法
通过对视频中相邻两帧图像做差分运算来标记运动物体,
移动的物体在相邻帧中灰度会有差别,因此差值为0的是静态物体。
import cv2
camera = cv2.VideoCapture("move_detect.flv")
out_fps = 12.0 # 输出文件的帧率
fourcc = cv2.VideoWriter_fourcc('M', 'P', '4', '2') # 创建编码方式
# 创建VideoWriter对象
out1 = cv2.VideoWriter('v1.avi', fourcc, out_fps, (500, 400))
out2 = cv2.VideoWriter('v2.avi', fourcc, out_fps, (500, 400))
# 初始化
lastFrame = None
# 创建循环结构进行连续读写
while camera.isOpened():
ret, frame = camera.read()
# 如果不能抓取到一帧,说明到了视频的结尾
if not ret:
break
# 调整该帧大小
frame = cv2.resize(frame, (500, 400), interpolation = cv2.INTER_CUBIC)
# 如果第一帧是None,对其初始化
if lastFrame == None:
lastFrame = frame
continue
# 求帧差
frameDelta = cv2.absdiff(lastFrame, frame)
lastFrame = frame
'''
阈值化,留下轮廓
'''
thresh = cv2.cvtColor(frameDelta, cv2.COLOR_BGR2GRAY) # 灰度图
thresh = cv2.threshold(thresh, 25, 255, cv2.THRESH_BINARY)[1] # 二值化
# 阈值图像上的轮廓位置
cnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 遍历轮廓
for c in cnts:
# 忽略小轮廓,可能运动的小鸟之类的,排除误差
if cv2.contourArea(c) < 300:
continue
# 画轮廓边界框
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
# 展示当前帧
cv2.imshow("frame", frame)
cv2.imshow("frameDelta", frameDelta)
cv2.imshow("thresh", thresh)
# 保存视频
out1.write(frame)
out2.write(frameDelta)
if cv2.waitKey(20) && 0xFF == ord('q'):
break
# 资源释放
out1.release()
out2.release()
camera.release()
cv2.destroyAllWindows()
飘动的彩带也被捕捉到了,但是去误差,没有标小轮廓;
行人前后帧(运动)幅度小的也没被发现(框定)。
背景减除法
对视频的背景进行建模,实现背景消除,生成mask图像,通过对mask二值图像分析实现对前景活动对象的区域的提取。
- 初始化背景建模对象GMM
- 读取视频一帧
- 使用背景建模消除生成mask
- 对mask进行轮廓分析图区ROI(region of interest)
- 绘制ROI对象
import numpy as np
import cv2
# read the video
camera = cv2.VideoCapture('move_detect.flv')
# 创建背景减除对象
fgbg = cv2.createBackgroundSubstractorMOG2(
history = 500, varThreshold = 100, detectShadows = False)
def getPerson(image, opt=1):
# 获取前景mask
mask = fgbg.apply(frame)
'''
去噪
'''
# 创建一个矩形形状的结构元素,用于形态学操作,如腐蚀(erosion)和膨胀(dilation)
line = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 5), (-1, -1))
mask = cv2.morphologyEx(mask, cv2.MORPG_OPEN, line)
cv2.imshow('mask', mask)
# 画出轮廓并忽略小于阈值的轮廓
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
area = cv2.contourArea(c)
if area < 150:
continue
rect = cv2.minAreaRect(c) # 返回一个具有最小面积的矩形
cv2.ellipse(image, rect, (0, 0, 255), 2, 8)
cv2.circle(image, (np.int32(rect[0][0]), np.int32(rect[0][1])), 2, (0, 0, 255), 2, 8, 0) # 取矩形中心点作为圆心
return image, mask
while True:
ret, frame = camera.read()
res, m_ = getPerson(frame) # Python中使用下划线作为占位符变量名是一种惯例。它也可以用来忽略函数的返回值或迭代中的某些值,以避免产生未使用变量的警告
cv2.imshow('res', res)
if cv2.waitKey(20) && 0xFF == ord('q'):
break
# 资源释放
camera.release()
cv2.destroyAllWindows()
图像论1帧,连续帧就成了视频