本文转载自别人博客
混合高斯模型:在进行前景检测前,先对背景进行训练,对图像中每个背景采用一个混合高斯模型进行模拟,每个背景的混合高斯的个数可以自适应。然后在测试阶段,对新来的像素进行GMM匹配,如果该像素值能够匹配其中一个高斯,则认为是背景,否则认为是前景。由于整个过程GMM模型在不断更新学习中,所以对动态背景有一定的鲁棒性。
混合高斯模型学习方法
1.首先初始化每个高斯模型矩阵参数。
2.取视频中T帧数据图像用来训练高斯混合模型。来了第一个像素之后用它来当做第一个高斯分布。
3.当后面来的像素值时,与前面已有的高斯的均值比较,如果该像素点的值与其模型均值差在3倍的方差内,则属于该分布,并对其进行参数更新。
4.如果下一次来的像素不满足当前高斯分布,用它来创建一个新的高斯分布。
混合高斯模型测试方法
在测试阶段,对新来像素点的值与混合高斯模型中的每一个均值进行比较,如果其差值在2倍的方差之间的话,则认为是背景,否则认为是前景。将前景赋值为255,背景赋值为0。这样就形成了一副前景二值图。
MOG:高斯混合模型分离算法,全称Gaussian Mixture-based Background/Foreground Segmentation Algorithm。它使用一种通过K高斯分布的混合来对每个背景像素进行建模的方法(K = 3〜5)
MOG2: 也是高斯混合模型分离算法,是MOG的改进算法。该算法的一个重要特征是,它为每个像素选择适当数量的高斯分布,它可以更好地适应不同场景的照明变化等。
MOG2接口 cv2.createBackgroundSubtractorMOG2
model = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=100, detectShadows=0)
参数介绍
history:用于训练背景的帧数,默认为500帧,如果不手动设置learningRate,history就被用于计算当前的learningRate,此时history越大,learningRate越小,背景更新越慢;
varThreshold:方差阈值,用于判断当前像素是前景还是背景。一般默认16,如果光照变化明显,如阳光下的水面,建议设为25,36,具体去试一下也不是很麻烦,值越大,灵敏度越低;
detectShadows:是否检测影子,设为true为检测,false为不检测,检测影子会增加程序时间复杂度,如无特殊要求,建议设为false;
fmask = model.apply(img)
img:原图
fmask: 二值图像
寻找图像中的轮廓 cv2.findContours
contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.findContours()函数返回两个值,一个是轮廓本身,还有一个是每条轮廓对应的属性。
参数:
第一个参数是寻找轮廓的图像;
第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
cv2.RETR_EXTERNAL表示只检测外轮廓
cv2.RETR_LIST检测的轮廓不建立等级关系
cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
cv2.RETR_TREE建立一个等级树结构的轮廓。第三个参数method为轮廓的近似办法
cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
cv2.getStructuringElement构造形态学使用的kernel
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
第一个参数表示内核的形状,有三种形状可以选择。
矩形:MORPH_RECT;
交叉形:MORPH_CROSS;
椭圆形:MORPH_ELLIPSE;
第二和第三个参数分别是内核的尺寸以及锚点的位置
形态学的开运算
fgmk = cv2.morphologyEx(fgmk, cv2.MORPH_OPEN, kernel)
完整代码
import cv2
import numpy as np
# 第一步:使用cv2.VideoCapture读取视频
cap = cv2.VideoCapture('test.avi')
# 第二步:cv2.getStructuringElement构造形态学使用的kernel
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
# 第三步:构造高斯混合模型
model = cv2.createBackgroundSubtractorMOG2()
while(True):
# 第四步:读取视频中的图片,并使用高斯模型进行拟合
ret, frame = cap.read()
# 运用高斯模型进行拟合,在两个标准差内设置为0,在两个标准差外设置为255
fgmk = model.apply(frame)
# 第五步:使用形态学的开运算做背景的去除
fgmk = cv2.morphologyEx(fgmk, cv2.MORPH_OPEN, kernel)
# 第六步:cv2.findContours计算fgmk的轮廓
contours = cv2.findContours(fgmk, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
for c in contours:
# 第七步:进行人的轮廓判断,使用周长,符合条件的画出外接矩阵的方格
length = cv2.arcLength(c, True)
if length > 188:
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 第八步:进行图片的展示
cv2.imshow('fgmk', fgmk)
cv2.imshow('frame', frame)
if cv2.waitKey(150) & 0xff == 27:
break
cap.release()
cv2.destroyAllWindows()
for c in contours:
area = abs(cv2.contourArea(c))
if area >= 20:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)