Bootstrap

python opencv 背景建模 混合高斯模型

本文转载自别人博客

混合高斯模型:在进行前景检测前,先对背景进行训练,对图像中每个背景采用一个混合高斯模型进行模拟,每个背景的混合高斯的个数可以自适应。然后在测试阶段,对新来的像素进行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)

 

 

 

 

 

 

 

 

 

 

 

 

 

;