背景差分法示例
来源:互联网 发布:三菱fx5u编程手册 编辑:程序博客网 时间:2024/06/07 16:54
背景差分法
背景差分法是一种很常用而且广泛传感的技术,主要用于背景不动的情况下提取前景。它主要的原理是在当前帧和背景做减法,然后使用threshold进行二值化得到前景掩码。下面是背景减法的示意图。
背景差分法主要包含以下两个步骤:
1.背景的建立
2.背景的更新
两个关键点,第一个就是如何选择背景,第二个就是什么时候更新背景,这样可以适应背景变化的情况,更新背景的快慢也很重要,如果更新慢了,快速运动的物体如果没有重叠就认为是两个物体了,如果更新快了,慢速运动的物体会被认为是背景,这样就造成漏检。
这里学习一下在opencv中如何使用背景差分法。
代码
使用了两个方法来产生前景掩码:
1. cv::bgsegm::BackgroundSubtractorMog
2. cv::BackgroundSubtractorMog2
//opencv#include "opencv2/imgcodecs.hpp"#include "opencv2/imgproc.hpp"#include "opencv2/videoio.hpp"#include <opencv2/highgui.hpp>#include <opencv2/video.hpp>//C#include <stdio.h>//C++#include <iostream>#include <sstream>using namespace cv;using namespace std;// Global variablesMat frame; //current frameMat fgMaskMOG2; //fg mask fg mask generated by MOG2 methodPtr<BackgroundSubtractor> pMOG2; //MOG2 Background subtractorchar keyboard; //input from keyboardvoid help();void processVideo(char* videoFilename);void processImages(char* firstFrameFilename);void help(){ cout << "--------------------------------------------------------------------------" << endl << "This program shows how to use background subtraction methods provided by " << endl << " OpenCV. You can process both videos (-vid) and images (-img)." << endl << endl << "Usage:" << endl << "./bg_sub {-vid <video filename>|-img <image filename>}" << endl << "for example: ./bg_sub -vid video.avi" << endl << "or: ./bg_sub -img /data/images/1.png" << endl << "--------------------------------------------------------------------------" << endl << endl;}int main(int argc, char* argv[]){ //print help information help(); //check for the input parameter correctness if(argc != 3) { cerr <<"Incorret input list" << endl; cerr <<"exiting..." << endl; return EXIT_FAILURE; } //create GUI windows namedWindow("Frame"); namedWindow("FG Mask MOG 2"); //create Background Subtractor objects pMOG2 = createBackgroundSubtractorMOG2(); //MOG2 approach if(strcmp(argv[1], "-vid") == 0) { //input data coming from a video processVideo(argv[2]); } else if(strcmp(argv[1], "-img") == 0) { //input data coming from a sequence of images processImages(argv[2]); } else { //error in reading input parameters cerr <<"Please, check the input parameters." << endl; cerr <<"Exiting..." << endl; return EXIT_FAILURE; } //destroy GUI windows destroyAllWindows(); return EXIT_SUCCESS;}void processVideo(char* videoFilename) { //create the capture object VideoCapture capture(videoFilename); if(!capture.isOpened()){ //error in opening the video input cerr << "Unable to open video file: " << videoFilename << endl; exit(EXIT_FAILURE); } //read input data. ESC or 'q' for quitting keyboard = 0; while( keyboard != 'q' && keyboard != 27 ){ //read the current frame if(!capture.read(frame)) { cerr << "Unable to read next frame." << endl; cerr << "Exiting..." << endl; exit(EXIT_FAILURE); } //update the background model pMOG2->apply(frame, fgMaskMOG2); //get the frame number and write it on the current frame stringstream ss; rectangle(frame, cv::Point(10, 2), cv::Point(100,20), cv::Scalar(255,255,255), -1); ss << capture.get(CAP_PROP_POS_FRAMES); string frameNumberString = ss.str(); putText(frame, frameNumberString.c_str(), cv::Point(15, 15), FONT_HERSHEY_SIMPLEX, 0.5 , cv::Scalar(0,0,0)); //show the current frame and the fg masks imshow("Frame", frame); imshow("FG Mask MOG 2", fgMaskMOG2); //get the input from the keyboard keyboard = (char)waitKey( 30 ); } //delete capture object capture.release();}void processImages(char* fistFrameFilename) { //read the first file of the sequence frame = imread(fistFrameFilename); if(frame.empty()){ //error in opening the first image cerr << "Unable to open first image frame: " << fistFrameFilename << endl; exit(EXIT_FAILURE); } //current image filename string fn(fistFrameFilename); //read input data. ESC or 'q' for quitting keyboard = 0; while( keyboard != 'q' && keyboard != 27 ){ //update the background model pMOG2->apply(frame, fgMaskMOG2); //get the frame number and write it on the current frame 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)); //show the current frame and the fg masks imshow("Frame", frame); imshow("FG Mask MOG 2", fgMaskMOG2); //get the input from the keyboard keyboard = (char)waitKey( 30 ); //search for the next image in the sequence ostringstream oss; oss << (frameNumber + 1); string nextFrameNumberString = oss.str(); string nextFrameFilename = prefix + nextFrameNumberString + suffix; //read the next frame frame = imread(nextFrameFilename); if(frame.empty()){ //error in opening the next image in the sequence cerr << "Unable to open image frame: " << nextFrameFilename << endl; exit(EXIT_FAILURE); } //update the path of the current frame fn.assign(nextFrameFilename); }}
关键代码说明
- 创建三个全局变量,frame用于保存当前图像,fgMaskMog用于保存前景掩码,fgMaskMog2是第二种方法产生的前景掩码。
Mat frame; //current frameMat fgMaskMOG; //fg mask generated by MOG methodMat fgMaskMOG2; //fg mask fg mask generated by MOG2 method
- 使用两个方法产生前景掩码,cv::BackgroundSubtractor。在本例中,使用默认的参数,你也可以尝试其它参数。
Ptr<BackgroundSubtractor> pMOG; //MOG Background subtractorPtr<BackgroundSubtractor> pMOG2; //MOG2 Background subtractor...//create Background Subtractor objectspMOG = createBackgroundSubtractorMOG(); //MOG approach
- 传入视频还是单张图像,使用-vid参数传入视频 使用-img参数传入图像
if(strcmp(argv[1], "-vid") == 0) { //input data coming from a video processVideo(argv[2]);}else if(strcmp(argv[1], "-img") == 0) { //input data coming from a sequence of images processImages(argv[2]);}
- 建议使用视频进行测试。如果要停止,输入“q”或者esc。
while( (char)keyboard != 'q' && (char)keyboard != 27 ){ //read the current frame if(!capture.read(frame)) { cerr << "Unable to read next frame." << endl; cerr << "Exiting..." << endl; exit(EXIT_FAILURE); }
- 每一帧图像都用于计算前景掩码和更新背景,可以通过传入参数来修改更新速度。
//update the background modelpMOG->apply(frame, fgMaskMOG);pMOG2->apply(frame, fgMaskMOG2);
- 在在上角显示当前帧号。
//get the frame number and write it on the current framestringstream ss;rectangle(frame, cv::Point(10, 2), cv::Point(100,20), cv::Scalar(255,255,255), -1);ss << capture.get(CAP_PROP_POS_FRAMES);string frameNumberString = ss.str();putText(frame, frameNumberString.c_str(), cv::Point(15, 15), FONT_HERSHEY_SIMPLEX, 0.5 , cv::Scalar(0,0,0));
- 然后显示输入图像和结果
//show the current frame and the fg masksimshow("Frame", frame);imshow("FG Mask MOG", fgMaskMOG);imshow("FG Mask MOG 2", fgMaskMOG2);
- 如果选择图片进行处理,需要输入几张图像。使用cv::imread进行处理。
//read the first file of the sequenceframe = imread(fistFrameFilename);if(!frame.data){ //error in opening the first image cerr << "Unable to open first image frame: " << fistFrameFilename << endl; exit(EXIT_FAILURE);}...//search for the next image in the sequenceostringstream oss;oss << (frameNumber + 1);string nextFrameNumberString = oss.str();string nextFrameFilename = prefix + nextFrameNumberString + suffix;//read the next frameframe = imread(nextFrameFilename);if(!frame.data){ //error in opening the next image in the sequence cerr << "Unable to open image frame: " << nextFrameFilename << endl; exit(EXIT_FAILURE);}//update the path of the current framefn.assign(nextFrameFilename);
结果显示:
结果显示如果人停下了,那么就检测不到了。
保存
保存使用cv::imread就可以了,代码实现很简单
string imageToSave = "output_MOG_" + frameNumberString + ".png";bool saved = imwrite(imageToSave, fgMaskMOG);if(!saved) { cerr << "Unable to save " << imageToSave << endl;}
阅读全文
0 0
- 背景差分法示例
- 静态文本颜色背景改变示例源程序
- 背景差分法
- j2me中使用canvas设置背景颜色示例
- jQuery关于导航条背景切换效果实现示例
- c#Winform程序的toolStripButton自定义背景应用示例源码
- js导航栏单击事件背景变换示例代码
- ROS编程示例---设置乌龟背景随机颜色
- 背景
- 背景
- 背景
- 背景
- 背景
- 背景
- 背景
- 背景
- 背景
- 背景
- Rxjava 初始源码探究
- 深度学习笔记——算法总结
- Android ClassLoader详解
- gitlab 安装
- Boost电路的驱动电路
- 背景差分法示例
- 调通sina33m下的ap6181版本(分色排版)V1.0
- 深度学习——keras
- 微信小程序--搜索电影app(续)
- 安卓引用方法时的错误
- 2017 上半年总结
- android控件拖动,移动、解决父布局重绘时控件回到原点
- Makefile $@ $^ $< 三个常用变量
- OpenCV3 Python语言实现 笔记2