![]()
背景减法利用图像序列中的当前帧和事先确定的背景参考模型间的差异比较,来确定运动物体位置,是一种基于统计学原理的运动目标检测的方法。这种方法的性能取决于背景建模技术,Gloyer等人使用单高斯模型的思路,但常常不能准确地描述背景模型。
1999年Stauffer等人提出了经典的混合高斯背景建模法,这种方法不仅对复杂场景的适应强,而且能通过自动计算的模型参数来对背景模型调整,虽然增加了高斯分布的个数,造成计算量增大,但检测速度很快,且检测准确,容易实现。基于混合高斯模型建模的背景减法已是运动检测的主流方法。OpenCv中有三种三种比较容易使用的方法。
1. BackgroundSubtractorMOG
这是一个以混合高斯模型为基础的前景/背景分割算法。它是 P.KadewTraKuPong和 R.Bowden 在 2001 年提出的。它使用 K(K=3 或 5)个高斯分布混合对背景像素进行建模。使用这些颜色(在整个视频中)存在时间的长短作为混合的权重。背景的颜色一般持续的时间最长,而且更加静止。一个像素怎么会有分布呢?在 x,y 平面上一个像素就是一个像素没有分布,但是我们现在讲的背景建模是基于时间序列的,因此每一个像素点所在的位置在整个时间序列中就会有很多值,从而构成一个分布。
在编写代码时,我们需要使用函数cv2.createBackgroundSubtractorMOG()创建一个背景对象。这个函数有些可选参数,比如要进行建模场景的时间长度,高斯混合成分的数量,阈值等。将他们全部设置为默认值。然后在整个视频中 我们是需要使用 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 = cv2.bgsegm.createBackgroundSubtractorMOG()
fgbg2 = cv2.createBackgroundSubtractorMOG2()
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
fgbg3 = cv2.bgsegm.createBackgroundSubtractorGMG(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 = cap.read()
if not ret:
print('not found')
break
frame = cv2.resize(frame, (400, 400), interpolation=cv2.INTER_CUBIC)
# 前景掩码
fgmask1 = fgbg1.apply(frame)
fgmask2 = fgbg2.apply(frame)
fgmask3 = fgbg3.apply(frame)
fgmask4 = cv2.morphologyEx(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
cap.release()
cv2.destroyAllWindows()
BackgroundSubtractorMOGBackgroundSubtractorMOG2BackgroundSubtractorGMG(噪声未保存到)BackgroundSubtractorGMG(经形态学运算)
下面是采用BackgroundSubtractorGMG方法处理选取的两组图片BackgroundSubtractorGMG原图1BackgroundSubtractorGMG修图1BackgroundSubtractorGMG原图2BackgroundSubtractorGMG修图2
5. 检测运动目标
运动目标检测流程图
代码实现如下:
#使用BackgroundSubtractorMOG
import 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 = cv.bgsegm.createBackgroundSubtractorMOG()
# 视频文件输出参数设置
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 = cap.read()
# 如果视频结束,跳出循环
if not ret:
break
frame = cv.resize(frame, (500, 500), interpolation=cv.INTER_CUBIC)
frame_motion = frame.copy()
# 计算前景掩码
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.findContours(draw1.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for c in contours_m:
if cv.contourArea(c) < 300:
continue
(x, y, w, h) = cv.boundingRect(c)
cv.rectangle(frame_motion, (x, y), (x + w, y + h), color_m, 2)
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) # 保存
out.release()
cap.release()
cv.destroyAllWindows()
运动目标检测https://www.zhihu.com/video/1016748414142455808
6. 参考资料
[1]opencv官网教程
版权声明:本文为CSDN博主「daidaiyijiu」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_35803436/article/details/113554640
![]()

暂无评论