一種最簡單的前景(移動區域)提取方怯就是一幀(或之後的幾幀)減去另 一幀,然後將“足夠不同”的地方標爲前景。這個過程會捕捉到移動物體的邊緣。簡單起見,我們考慮三個單通道圖片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;
}
原視頻:
幀間差分結果: