一种最简单的前景(移动区域)提取方怯就是一帧(或之后的几帧)减去另 一帧,然后将“足够不同”的地方标为前景。这个过程会捕捉到移动物体的边缘。简单起见,我们考虑三个单通道图片frameTime1,frameTime2和frameForeground 。图片frameTime1是过去的一张灰度图片,frameTime2是当前的灰度图片。我们用下面的接口来检测前景,将差分的值(绝对值)保存在frameForeground 中。
cv::absdiff(
frameTime1, // First input array
frameTime2, // Second input array
frameForeground // Result array
);
由于像素总是存在噪音和波动,我们应该忽略帧间微小的不同(例如小于20),并标记出(设为 255)大的不同。调用阈值化处理函数达到这一目的。
C++实现代码:
// 帧间差分法
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
using namespace std;
int N = 4; //N帧的帧间差分
int main()
{
using namespace cv;
cv::VideoCapture cap;
if (!cap.open("test.avi"))
{
cerr << "Couldn't open video file" << endl;
return -1;
}
vector<Mat> frames;
for (int i = 1; ; i++)
{
Mat frame, frame_gray;
cap >> frame;
if( !frame.data ) break;
if (i > 10 && i <= 10 + N)
{
cvtColor(frame, frame_gray, CV_RGB2GRAY); // 将彩色图像转换为灰度图像;
frames.push_back(frame_gray);
}
}
int row = frames[0].rows;
int col = frames[0].cols;
vector<Mat> alldiff(N-1, Mat(row, col, CV_8UC1)); // 生成一个Mat容器alldiff用于存储最终的各个帧的差分结果
for (int i = 0; i < N - 1; i++)
{
Mat diff = Mat(row, col, CV_8UC1);
absdiff(frames[i], frames[i+1], diff); //帧间差分
threshold(diff, diff, 20, 255, CV_8UC1); //阈值化处理
alldiff.push_back(~diff);
string n = to_string(i);
string name = "diff_" + n + ".jpg";
imwrite(name, ~diff);
}
waitKey(0);
return 0;
}
原视频:
帧间差分结果:


