opencv-079-视频分析(背景和前景的提取)

知识点

视频场景分析中最常用的技术之一就是通过背景消除来提取前景移动对象,得到前景的对象mask图像,最常用的背景消除技术就是通过帧差相减,用前面一帧作为背景图像,与当前帧进行相减,不过这种方法对光照与噪声影响非常敏感,所有好的办法是通过对前面一系列帧提取背景模型进行相减,OpenCV中实现的背景模型提取算法有两种,一种是基于高斯混合模型GMM实现的背景提取,另外一种是基于最近邻KNN实现的。

API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Ptr<BackgroundSubtractorMOG2> cv::createBackgroundSubtractorMOG2(
int history = 500,
double varThreshold = 16,
bool detectShadows = true
)

参数解释如下:
history表示过往帧数,500帧,选择history = 1就变成两帧差
varThreshold表示像素与模型之间的马氏距离,值越大,只有那些最新的像素会被归到前景,值越小前景对光照越敏感。
detectShadows 是否保留阴影检测,请选择False这样速度快点

创建
Ptr<BackgroundSubtractor> pBackSub = createBackgroundSubtractorMOG2();
Ptr<BackgroundSubtractor> pBackSub = createBackgroundSubtractorKNN();

代码(c++,python)

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
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

/*
* 视频分析(背景和前景的提取)
*/
int main() {
VideoCapture capture("../images/color_object.mp4");
if (!capture.isOpened()) {
printf("could not open camera...\n");
return -1;
}
namedWindow("input", WINDOW_NORMAL);
namedWindow("mask", WINDOW_NORMAL);
namedWindow("background image", WINDOW_NORMAL);

Mat frame, mask, back_img;
Ptr<BackgroundSubtractor> pMOG2 = createBackgroundSubtractorMOG2(500, 1000, false);
while (true) {
bool ret = capture.read(frame);
if (!ret) break;
pMOG2->apply(frame, mask);
pMOG2->getBackgroundImage(back_img);
imshow("input", frame);
imshow("mask", mask);
imshow("background image", back_img);
char c = waitKey(50);
if (c == 27) {
break;
}
}
waitKey(0);
return 0;

waitKey(0);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import cv2 as cv

cap = cv.VideoCapture('D:/images/video/color_object.mp4')
fgbg = cv.createBackgroundSubtractorMOG2(history=500, varThreshold=1000, detectShadows=False)
while True:
ret, frame = cap.read()
fgmask = fgbg.apply(frame)
background = fgbg.getBackgroundImage()
cv.imshow('input', frame)
cv.imshow('mask',fgmask)
cv.imshow('background', background)
k = cv.waitKey(10)&0xff
if k == 27:
break
cap.release()
cv.destroyAllWindows()

结果

代码地址

github