背景減除法(Background subtraction)常用於通過靜態攝像頭生成一個前景掩碼,即場景中移動物體的二進制圖像。
代碼示例
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/video.hpp"
#include <iostream>
#include <sstream>
using namespace std;
using namespace cv;
Mat frame; // 當前幀
Mat fgMaskMOG2; // 前景模板,通過MOG2方法生成
Ptr<BackgroundSubtractor> pMOG2; // MOG2 背景消除
char keyboard; // 按鍵響應
const char* filename;
void processVideo(const char* videoFilename);
void processImages(const char* firstFrameFilename);
int main()
{
pMOG2 = createBackgroundSubtractorMOG2(); // MOG2方法,背景消除
char video_or_image;
string s;
cout << "Pless choose Video or Image: ( V / I )\t";
cin >> video_or_image ;
if (video_or_image == 'V' || video_or_image == 'v') // 視頻
{
cout << "\n\nPlease input the address of the video:\t";
cin >> s;
filename = s.c_str();
namedWindow("Frame");
namedWindow("FG Mask MOG2");
processVideo(filename);
}
else if (video_or_image == 'I' || video_or_image == 'i') // 圖像
{
cout << "\n\nPlease input the address of the images:\t";
cin >> s;
filename = s.c_str();
namedWindow("Frame");
namedWindow("FG Mask MOG2");
processImages(filename);
}
else
{
cerr << "Wrong Input !" << endl;
return EXIT_FAILURE;
}
destroyAllWindows();
return EXIT_SUCCESS;
}
void processVideo(const char* videoFilename)
{
VideoCapture capture(videoFilename); // 捕獲視頻
if (!capture.isOpened()) { exit(EXIT_FAILURE); }
keyboard = 0;
while (keyboard != 'q'&&keyboard != 27)
{
if (!capture.read(frame)) { exit(EXIT_FAILURE); } // 讀取當前幀
pMOG2->apply(frame, fgMaskMOG2); // 獲取前景掩模
stringstream ss;
ss << capture.get(CAP_PROP_POS_FRAMES); // 獲取當前幀數
string frameNumberString = ss.str();
rectangle(frame, cv::Point(10, 2), cv::Point(100, 20), cv::Scalar(255, 255, 255), -1);
putText(frame, frameNumberString.c_str(), cv::Point(15, 15),
FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
imshow("Frame", frame);
imshow("FG Mask MOG2", fgMaskMOG2);
keyboard = (char)waitKey(30);
}
capture.release();
}
void processImages(const char* fistFrameFilename)
{
frame = imread(fistFrameFilename);
if (frame.empty()) { exit(EXIT_FAILURE); }
string fn(fistFrameFilename);
keyboard = 0;
while (keyboard != 'q' && keyboard != 27)
{
pMOG2->apply(frame, fgMaskMOG2); // 獲取前景掩模
size_t index = fn.find_last_of("/");
if (index == string::npos) // 如果'/'不存在則搜尋'\\'
index = fn.find_last_of("\\");
size_t index2 = fn.find_last_of(".");
string prefix = fn.substr(0, index + 1); // 圖像路徑前部分,前爲起始位置,後爲長度
string suffix = fn.substr(index2); // 圖像路徑後部分,圖像格式
string frameNumberString = fn.substr(index + 1, index2 - index - 1);
istringstream iss(frameNumberString);
int frameNumber = 0;
iss >> frameNumber;
rectangle(frame, cv::Point(10, 2), cv::Point(100, 20),
cv::Scalar(255, 255, 255), -1);
putText(frame, frameNumberString.c_str(), cv::Point(15, 15),
FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
imshow("Frame", frame);
imshow("FG Mask MOG 2", fgMaskMOG2);
keyboard = (char)waitKey(30);
ostringstream oss;
oss << (frameNumber + 1);
string nextFrameNumberString = oss.str();
string nextFrameFilename = prefix + nextFrameNumberString + suffix;
frame = imread(nextFrameFilename);
if (frame.empty())
exit(EXIT_FAILURE);
fn.assign(nextFrameFilename); // 更新圖片路徑
}
}
運行結果