python 背景建模高斯混合模型

原文:https://blog.csdn.net/zhangyonggang886/article/details/51638655 

BackgroundSubtractorMOG2是以高斯混合模型为基础的背景/前景分割算法。它是以2004年和2006年Z.Zivkovic的两篇文章为基础的。这个算法的一个特点是它为每一个像素选择一个合适数目的高斯分布。(上一个方法中我们使用是K高斯分布)。这样就会对由于亮度等发生变化引起的场景变化产生更好的适应。和前面一样我们需要创建一个背景对象。但在这里我们我们可以选择是否检测阴影。如果detectShadows = True(默认值),它就会检测并将影子标记出来,但是这样做会降低处理速度。影子会被标记为灰色。

  • history:用于训练背景的帧数,默认为500帧,如果不手动设置learningRate,history就被用于计算当前的learningRate,此时history越大,learningRate越小,背景更新越慢;
  • varThreshold:方差阈值,用于判断当前像素是前景还是背景。一般默认16,如果光照变化明显,如阳光下的水面,建议设为25,36,具体去试一下也不是很麻烦,值越大,灵敏度越低;
  • detectShadows:是否检测影子,设为true为检测,false为不检测,检测影子会增加程序时间复杂度,如无特殊要求,建议设为false;

这里我们采用opencv实现视频追踪,对于opencv的安装、配置和使用,网上有很多教程,我们这里就不在说明。如果你对opencv不太了解,请自行查资料学习。话归正题,这里我将会分别从Python和c++实现BackgroundSubtractorMOG2,我使用的是opencv3.1linux版本。 
Python代码:

import numpy as np
import cv2
import time
import datetime

cap = cv2.VideoCapture(0)

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
fgbg = cv2.createBackgroundSubtractorMOG2()
fourcc = cv2.VideoWriter_fourcc(*'XVID')
frame1 = np.zeros((640,480))
out = cv2.VideoWriter(datetime.datetime.now().strftime("%A_%d_%B_%Y_%I_%M_%S%p")+'.avi',fourcc, 5.0, np.shape(frame1))

while(1):
    ret, frame = cap.read()
    fgmask = fgbg.apply(frame)
    (_,cnts, _) = cv2.findContours(fgmask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    maxArea = 0
    for c in cnts:
        Area = cv2.contourArea(c)
        if Area < maxArea :
        #if cv2.contourArea(c) < 500:
            (x, y, w, h) = (0,0,0,0)
            continue
        else:
            if Area < 1000:
                (x, y, w, h) = (0,0,0,0)
                continue
            else:
                maxArea = Area
                m=c
                (x, y, w, h) = cv2.boundingRect(m)
        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
        out.write(frame)
    cv2.imshow('frame',frame)
    k = cv2.waitKey(30)&0xff
    if k==27:
        break
out.release()
cap.release()
cv2.destoryAllWindows()
  • c++版本: 

VideoDetect.h

#pragma once
#include 
#include 

using namespace std;
using namespace cv;
enum VIDEOTYPE
{
    CAMERAVIDEO/*摄像头*/,FILEVIDEO/*视频*/
};

class MOG2Detector
{
public:
    MOG2Detector();
    ~MOG2Detector();
    /*
    VIDEOTYPE 指定摄像头或者文件
    path 文件路径
    WindowName opencv可视化窗口名称
    */
    MOG2Detector(VIDEOTYPE type,char * path = "E:/image/s.avi",char * WindowName = "Video");
    //开始
    void startDecect();

private:
    char * WinName;
    VIDEOTYPE VideoType;
    cv::VideoCapture capture;
    cv::Ptr fgbg;
};
  • VideoDetect.cpp:
#include "stdafx.h"
#include "MOG2Detector.h"


MOG2Detector::MOG2Detector()
{
}
MOG2Detector::~MOG2Detector()
{

}

MOG2Detector::MOG2Detector(VIDEOTYPE type, char * path, char * WindowName)
{
    if (type == CAMERAVIDEO) 
    {
        capture.open(0);
    }
    else if (type == FILEVIDEO)
    {
        capture.open("E:/image/s.avi");
    }
    else 
    {
        cout << "Type is error, you can input CAMERAVIDEO or FILEVIDEO" << endl;
        return;
    }

    if (!capture.isOpened())
    {
        std::cout << "video camera capture open fail! \n" << std::endl;
        exit(1);
    }

    fgbg = cv::createBackgroundSubtractorMOG2();
    WinName = WindowName;
}

void MOG2Detector::startDecect()
{
    cv::Mat frame, fgmask;
    //cnts存储边缘信息
    std::vector<std::vector > cnts;
    cv::namedWindow("video", 1);

    while (1)
    {
        capture.read(frame);
        fgbg->apply(frame, fgmask);
        //检测每一帧边缘
        findContours(fgmask, cnts, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
        float Area;
        Rect rect;
        vector m;
        for (int i = cnts.size() - 1; i >= 0; i--)
        {
            vector c = cnts[i];
            //获取面积
            Area = contourArea(c);
            if (Area < 50)//50这个值根据需求设定,这里指的是目标的大小
            {
                continue;
            }
            else
            {
                m = c;
            }
            rect = boundingRect(m);
            rectangle(frame, rect, Scalar(0, 255, 0), 2);
        }
        resize(frame, frame, Size(480, 320));
        imshow("video", frame);
        char c = waitKey(33);
        if (c == 27)
            break;
    }
    //释放资源
    capture.release();
    cv::destroyWindow("video");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

最近比较忙,等到有时间在完善这些代码,添加注释! 

你可能感兴趣的:(opencv)