文章目录
项目介绍
在此文章中,我们将使用 python 中的 opencv 库创建一个运动热图,用于检测物体或人的流动方向。
输入:一段包含行人运动的视频文件。
输出:运动热图视频,其中的一帧如下图所示:
使用的 python 及 opencv 库的版本为:
- python:3.7;
- opencv-python:4.2.0.34;
- opencv-contrib-python:4.2.0.34。
实现流程
这个程序是基于一种被称为高斯背景差法的技术,这项技术被广泛应用于用稳定的摄像机检测运动物体。
背景差法创建一个表示帧(图像的静态部分)背景的模板,对于每一帧,它将减去前一帧。
其主要步骤只有两个:
- 背景初始化:在第一步中,通过冻结第一帧来计算背景的模型;
- 更新:在第二步中,下一帧将减去上一帧,如果两帧之间发生变化(移动),则这些帧的差异将反映出该变化,可以通过应用过滤器来进行提取差异信息。
代码实现
1. 导入需要的库
import cv2
import copy
import matplotlib.pyplot as plt
2. 读取原始视频并统计帧数
capture = cv2.VideoCapture('test.avi')
length = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
3. 实例化背景消除器
background_subtractor = cv2.bgsegm.createBackgroundSubtractorMOG()
4. 设置制作的视频的参数
fourcc = cv2.VideoWriter_fourcc(*'XVID')
# width 和 height 可以通过打印下面的 frame.shape 来查看
width = 768
height = 576
video = cv2.VideoWriter('output.avi', fourcc, 30.0, (width, height))
5. 对每一帧进行热图处理
for i in range(0, length-1):
ret, frame = capture.read()
# 检查是不是第一帧
# 初始化背景差法的背景
if i == 0:
first_frame = copy.deepcopy(frame)
height, width = frame.shape[:2]
accum_image = np.zeros((height, width), np.uint8) # 初始化 accum_image 数组
fgmask = background_subtractor.apply(frame) # 消除背景
# 为了消除例如风,小鸟飞行等少量运动,将阈值与maxValue一起应用到掩膜上。
threshold = 2
maxValue = 2
ret, th1 = cv2.threshold(fgmask, threshold, maxValue, cv2.THRESH_BINARY)
accum_image = cv2.add(accum_image, th1) # 将掩膜的结果添加到 accum_image 数组中
color_image_video = cv2.applyColorMap(accum_image, cv2.COLORMAP_HOT) # 颜色映射被应用于掩膜
video.write(cv2.add(frame, color_image_video)) # 将掩膜与当前帧合并后写入视频文件
6. 播放制作的视频文件
cap = cv2.VideoCapture('output.avi')
while 1:
ret, frame = cap.read() #cap.read()函数返回的第1个参数ret(return value缩写)是一个布尔值,表示当前这一帧是否获取正确
cv2.imshow("cap", frame)
if cv2.waitKey(5) & 0xff == ord('q'): # waitKey的参数表示暂停时间,所以这个值越大,视频播放速度越慢
break
cap.release()
cv2.destroyAllWindows()
完整代码
import cv2
import copy
import matplotlib.pyplot as plt
capture = cv2.VideoCapture('test.avi')
background_subtractor = cv2.bgsegm.createBackgroundSubtractorMOG()
length = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
fourcc = cv2.VideoWriter_fourcc(*'XVID')
width = 768
height = 576
video = cv2.VideoWriter('output.avi', fourcc, 30.0, (width, height))
for i in range(0, length-1):
ret, frame = capture.read()
if i == 0:
first_frame = copy.deepcopy(frame)
height, width = frame.shape[:2]
accum_image = np.zeros((height, width), np.uint8)
fgmask = background_subtractor.apply(frame)
threshold = 2
maxValue = 2
ret, th1 = cv2.threshold(fgmask, threshold, maxValue, cv2.THRESH_BINARY)
accum_image = cv2.add(accum_image, th1)
color_image_video = cv2.applyColorMap(accum_image, cv2.COLORMAP_HOT)
video.write(cv2.add(frame, color_image_video))
cap = cv2.VideoCapture('output.avi')
while 1:
ret, frame = cap.read()
cv2.imshow("cap", frame)
if cv2.waitKey(5) & 0xff == ord('q'):
break
cap.release()
cv2.destroyAllWindows()