opencv-087-视频分析(基于帧差法实现移动对象分析)

知识点

光流跟踪与背景消除都是基于建模方式的视频分析方法,其实这类方法最原始的一个例子就是对视频移动对象的帧差法跟踪,这个在视频分析与处理中也是一种很常见的手段,有时候会取得意想不到的好效果,帧差法进一步划分有可以分为:

  • 两帧差
  • 三帧差

假设有当前帧frame, 前一帧prev1,更前一帧prev2
两帧差方法直接使用前一帧 减去当前帧 diff = frame – prev1
三帧差方法计算如下:
diff1 = prev2 – prev1
diff2 = frame – prev1
diff = diff1 & diff2
帧差法在求取帧差之前一般会进行高斯模糊,用以减低干扰,通过得到的diff图像进行形态学操作,用以合并与候选区域,提升效率。帧差法的缺点有如下:

  1. 高斯模糊是高耗时计算
  2. 容易受到噪声与光线干扰

代码(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
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

/*
* 视频分析(基于帧差法实现移动对象分析)
*/
int main() {
VideoCapture capture("../images/bike.avi");
if (!capture.isOpened()) {
cout << "could not open video..." << endl;
return -1;
}

// 读取第一帧
Mat preFrame, preGray;
capture.read(preFrame);
cvtColor(preFrame, preGray, COLOR_BGR2GRAY);
GaussianBlur(preGray, preGray, Size(0, 0), 15);

Mat diff;
Mat frame, gray;

// 定义结构元素
Mat k = getStructuringElement(MORPH_RECT, Size(7, 7));

while (true) {
bool ret = capture.read(frame);
if (!ret) break;
cvtColor(frame, gray, COLOR_BGR2GRAY);
GaussianBlur(gray, gray, Size(0, 0), 15);
subtract(gray, preGray, diff);
threshold(diff, diff, 0, 255, THRESH_BINARY | THRESH_OTSU);
morphologyEx(diff, diff, MORPH_OPEN, k);
imshow("input", frame);
imshow("result", diff);

gray.copyTo(preGray);
char c = waitKey(5);
if (c == 27) {
break;
}
}

waitKey(0);
return 0;
}
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
import numpy as np
import cv2 as cv

cap = cv.VideoCapture("D:/images/video/bike.avi")
ret, prevFrame = cap.read()
prevGray = cv.cvtColor(prevFrame, cv.COLOR_BGR2GRAY)
prevGray = cv.GaussianBlur(prevGray, (0, 0), 15)
k = cv.getStructuringElement(cv.MORPH_RECT, (7, 7))
while True:
ret, frame = cap.read()
if ret is False:
break
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
gray = cv.GaussianBlur(gray, (0, 0), 15)
diff = cv.subtract(gray, prevGray)
t, binary = cv.threshold(diff, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
binary = cv.morphologyEx(binary, cv.MORPH_OPEN, k)
cv.imshow('input', frame)
cv.imshow('result', binary)
cv.imwrite("D:/result.png", binary)
c = cv.waitKey(50)&0xff
prevGray = np.copy(gray)
if c == 27:
break
cap.release()
cv.destroyAllWindows()

结果

代码地址

github