背景差法⽬标识别python_运动⽬标检测(4)—背景差分法背景减法利⽤图像序列中的当前帧和事先确定的背景参考模型间的差异⽐较,来确定运动物体位置,是⼀种基于统计学原理的运动⽬标检测的⽅法。这种⽅法的性能取决于背景建模技术,Gloyer等⼈使⽤单⾼斯模型的思路,但常常不能准确地描述背景模型。
1999年Stauffer等⼈提出了经典的混合⾼斯背景建模法,这种⽅法不仅对复杂场景的适应强,⽽且能通过⾃动计算的模型参数来对背景模型调整,虽然增加了⾼斯分布的个数,造成计算量增⼤,但检测速度很快,且检测准确,容易实现。基于混合⾼斯模型建模的背景减法已是运动检测的主流⽅法。OpenCv中有三种三种⽐较容易使⽤的⽅法。
1. BackgroundSubtractorMOG
这是⼀个以混合⾼斯模型为基础的前景/背景分割算法。它是 P.KadewTraKuPong和 R.Bowden 在 2001 年提出的。它使⽤ K(K=3 或5)个⾼斯分布混合对背景像素进⾏建模。使⽤这些颜⾊(在整个视频中)存在时间的长短作为混合的权重。背景的颜⾊⼀般持续的时间最长,⽽且更加静⽌。⼀个像素怎么会有分布呢?在 x,y 平⾯上⼀个像素就是⼀个像素没有分布,但是我们现在讲的背景建模是基于时间序列的,因此每⼀个像素点所在的位置在整个时间序列中就会有很多值,从⽽构成⼀个分布。
在编写代码时,我们需要使⽤函数ateBackgroundSubtractorMOG()创建⼀个背景对象。这个函
数有些可选参数,⽐如要进⾏建模场景的时间长度,⾼斯混合成分的数量,阈值等。将他们全部设置为默认值。然后在整个视频中 我们是需要使⽤backgroundsubtractor.apply() 就可以得到前景的掩模了。
2. BackgroundSubtractorMOG2
这个也是以⾼斯混合模型为基础的背景/前景分割算法。它是以 2004 年和 2006 年 Z.Zivkovic 的两篇⽂章为基础的。这个算法的⼀个特点是它为每⼀个像素选择⼀个合适数⽬的⾼斯分布。(上⼀个⽅法中我们使⽤是 K ⾼斯分布)。这样就会对由于亮度等发⽣变化引起的场景变化产⽣更好的适应。
和前⾯⼀样我们需要创建⼀个背景对象。但在这⾥我们我们可以选择是否检测阴影。如果 detectShadows = True(默认值),它就会检测并将影⼦标记出来,但是这样做会降低处理速度。影⼦会被标记为灰⾊。
3. BackgroundSubtractorGMG
此算法结合了静态背景图像估计和每个像素的贝叶斯分割。这是 2012 年Andrew_B.Godbehere,Akihiro_Matsukawa 和
Ken_Goldberg 在⽂章中提出的。
它使⽤前⾯很少的图像(默认为前 120 帧)进⾏背景建模。使⽤了概率前景估计算法(使⽤贝叶斯估计鉴定前景)。这是⼀种⾃适应的估计,新观察到的对象⽐旧的对象具有更⾼的权重,从⽽对光照变化产⽣适应。⼀些形态学操作如开运算闭运算等被⽤来除去不需要的噪⾳。在前⼏帧图像中你会得到⼀个⿊⾊窗⼝。
对结果进⾏形态学开运算对与去除噪声很有帮助。
4. 三种⽅法的效果
代码实现如下:
import numpy as np
import cv2
import imageio
cap = cv2.VideoCapture("E:/opencv_vs/opencv/sources/samples/data/vtest.avi")
fgbg1 = ateBackgroundSubtractorMOG()
fgbg2 = ateBackgroundSubtractorMOG2()
kernel = StructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
fgbg3 = ateBackgroundSubtractorGMG(60) # initializationFrames=120
# 保存gif参数设置
gif1 = 'E:/video/v1.gif'
gif2 = 'E:/video/v2.gif'
gif3 = 'E:/video/v3.gif'
frames1 = []
frames2 = []
frames3 = []
while True:
ret, frame = ad()
if not ret:
print('not found')
break
frame = size(frame, (400, 400), interpolation=cv2.INTER_CUBIC)
# 前景掩码
fgmask1 = fgbg1.apply(frame)
fgmask2 = fgbg2.apply(frame)
fgmask3 = fgbg3.apply(frame)
fgmask4 = phologyEx(fgmask3, cv2.MORPH_OPEN, kernel, iterations=1) # 形态学开运算cv2.imshow('frame1', fgmask1)
cv2.imshow('frame2', fgmask2)
cv2.imshow('frame3', fgmask3)
cv2.imshow('frame4', fgmask4)
# 加⼊帧
frames1.append(fgmask1)
frames2.append(fgmask2)
frames3.append(fgmask4)
# 保存gif
imageio.mimsave(gif1, frames1, 'GIF', duration=0.1)
imageio.mimsave(gif2, frames2, 'GIF', duration=0.1)
imageio.mimsave(gif3, frames3, 'GIF', duration=0.1)
k = cv2.waitKey(100) & 0xff
if k == 27 or k == ord('q'):
break
cv2.destroyAllWindows()
BackgroundSubtractorMOGBackgroundSubtractorMOG2BackgroundSubtractorGMG(噪声未保存
到)BackgroundSubtractorGMG(经形态学运算)
下⾯是采⽤BackgroundSubtractorGMG⽅法处理选取的两组图⽚BackgroundSubtractorGMG原图1BackgroundSubtractorGMG修图1BackgroundSubtractorGMG原图2BackgroundSubtractorGMG修图2
5. 检测运动⽬标
运动⽬标检测流程图
代码实现如下:
#使⽤BackgroundSubtractorMOG
rectangle函数opencvimport cv2 as cv
import numpy as np
# 设置⽂件
file_test = "E:/opencv_vs/opencv/sources/samples/data/vtest.avi"
cap = cv.VideoCapture(file_test)
# 设置变量
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (2, 2)) # 定义结构元素
color_m = (255, 0, 0)
# 背景差法
fgbg = ateBackgroundSubtractorMOG()
# 视频⽂件输出参数设置
out_fps = 12.0 # 输出⽂件的帧率
fourcc = cv.VideoWriter_fourcc('M', 'P', '4', '2')
out = cv.VideoWriter('E:/video/v9.avi', fourcc, out_fps, (500, 500))
while True:
# 读取⼀帧
ret, frame = ad()
# 如果视频结束,跳出循环
if not ret:
break
frame = cv.resize(frame, (500, 500), interpolation=cv.INTER_CUBIC)
frame_motion = py()
# 计算前景掩码
fgmask = fgbg.apply(frame_motion)
draw1 = cv.threshold(fgmask, 25, 255, cv.THRESH_BINARY)[1] # ⼆值化
draw1 = cv.dilate(draw1, kernel, iterations=1)
# 查检测物体的轮廓,只检测外轮廓,只需4个点来保存轮廓信息
image_m, contours_m, hierarchy_m = cv.py(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) for c in contours_m:
urArea(c) < 300:
continue
(x, y, w, h) = cv.boundingRect(c)
cv.imshow("source", frame_motion)
cv.imshow("apply", fgmask)
cv.imshow("draw", draw1)
k = cv.waitKey(200)
if k == ord('q'):
break
out.write(frame_motion) # 保存
cv.destroyAllWindows()
6. 参考资料
[1]opencv官⽹教程