1 How to Use Background Subtraction Methods {#tutorial_background_subtraction} 2 ========================================= 3 4 - Background subtraction (BS) is a common and widely used technique for generating a foreground 5 mask (namely, a binary image containing the pixels belonging to moving objects in the scene) by 6 using static cameras. 7 - As the name suggests, BS calculates the foreground mask performing a subtraction between the 8 current frame and a background model, containing the static part of the scene or, more in 9 general, everything that can be considered as background given the characteristics of the 10 observed scene. 11 12 ![](images/Background_Subtraction_Tutorial_Scheme.png) 13 14 - Background modeling consists of two main steps: 15 16 -# Background Initialization; 17 -# Background Update. 18 19 In the first step, an initial model of the background is computed, while in the second step that 20 model is updated in order to adapt to possible changes in the scene. 21 22 - In this tutorial we will learn how to perform BS by using OpenCV. As input, we will use data 23 coming from the publicly available data set [Background Models Challenge 24 (BMC)](http://bmc.univ-bpclermont.fr/) . 25 26 Goals 27 ----- 28 29 In this tutorial you will learn how to: 30 31 -# Read data from videos by using @ref cv::VideoCapture or image sequences by using @ref 32 cv::imread ; 33 -# Create and update the background model by using @ref cv::BackgroundSubtractor class; 34 -# Get and show the foreground mask by using @ref cv::imshow ; 35 -# Save the output by using @ref cv::imwrite to quantitatively evaluate the results. 36 37 Code 38 ---- 39 40 In the following you can find the source code. We will let the user chose to process either a video 41 file or a sequence of images. 42 43 Two different methods are used to generate two foreground masks: 44 -# cv::bgsegm::BackgroundSubtractorMOG 45 -# @ref cv::BackgroundSubtractorMOG2 46 47 The results as well as the input data are shown on the screen. 48 The source file can be downloaded [here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/video/bg_sub.cpp). 49 50 @include samples/cpp/tutorial_code/video/bg_sub.cpp 51 52 Explanation 53 ----------- 54 55 We discuss the main parts of the above code: 56 57 -# First, three Mat objects are allocated to store the current frame and two foreground masks, 58 obtained by using two different BS algorithms. 59 @code{.cpp} 60 Mat frame; //current frame 61 Mat fgMaskMOG; //fg mask generated by MOG method 62 Mat fgMaskMOG2; //fg mask fg mask generated by MOG2 method 63 @endcode 64 -# Two @ref cv::BackgroundSubtractor objects will be used to generate the foreground masks. In this 65 example, default parameters are used, but it is also possible to declare specific parameters in 66 the create function. 67 @code{.cpp} 68 Ptr<BackgroundSubtractor> pMOG; //MOG Background subtractor 69 Ptr<BackgroundSubtractor> pMOG2; //MOG2 Background subtractor 70 ... 71 //create Background Subtractor objects 72 pMOG = createBackgroundSubtractorMOG(); //MOG approach 73 pMOG2 = createBackgroundSubtractorMOG2(); //MOG2 approach 74 @endcode 75 -# The command line arguments are analysed. The user can chose between two options: 76 - video files (by choosing the option -vid); 77 - image sequences (by choosing the option -img). 78 @code{.cpp} 79 if(strcmp(argv[1], "-vid") == 0) { 80 //input data coming from a video 81 processVideo(argv[2]); 82 } 83 else if(strcmp(argv[1], "-img") == 0) { 84 //input data coming from a sequence of images 85 processImages(argv[2]); 86 } 87 @endcode 88 -# Suppose you want to process a video file. The video is read until the end is reached or the user 89 presses the button 'q' or the button 'ESC'. 90 @code{.cpp} 91 while( (char)keyboard != 'q' && (char)keyboard != 27 ){ 92 //read the current frame 93 if(!capture.read(frame)) { 94 cerr << "Unable to read next frame." << endl; 95 cerr << "Exiting..." << endl; 96 exit(EXIT_FAILURE); 97 } 98 @endcode 99 -# Every frame is used both for calculating the foreground mask and for updating the background. If 100 you want to change the learning rate used for updating the background model, it is possible to 101 set a specific learning rate by passing a third parameter to the 'apply' method. 102 @code{.cpp} 103 //update the background model 104 pMOG->apply(frame, fgMaskMOG); 105 pMOG2->apply(frame, fgMaskMOG2); 106 @endcode 107 -# The current frame number can be extracted from the @ref cv::VideoCapture object and stamped in 108 the top left corner of the current frame. A white rectangle is used to highlight the black 109 colored frame number. 110 @code{.cpp} 111 //get the frame number and write it on the current frame 112 stringstream ss; 113 rectangle(frame, cv::Point(10, 2), cv::Point(100,20), 114 cv::Scalar(255,255,255), -1); 115 ss << capture.get(CAP_PROP_POS_FRAMES); 116 string frameNumberString = ss.str(); 117 putText(frame, frameNumberString.c_str(), cv::Point(15, 15), 118 FONT_HERSHEY_SIMPLEX, 0.5 , cv::Scalar(0,0,0)); 119 @endcode 120 -# We are ready to show the current input frame and the results. 121 @code{.cpp} 122 //show the current frame and the fg masks 123 imshow("Frame", frame); 124 imshow("FG Mask MOG", fgMaskMOG); 125 imshow("FG Mask MOG 2", fgMaskMOG2); 126 @endcode 127 -# The same operations listed above can be performed using a sequence of images as input. The 128 processImage function is called and, instead of using a @ref cv::VideoCapture object, the images 129 are read by using @ref cv::imread , after individuating the correct path for the next frame to 130 read. 131 @code{.cpp} 132 //read the first file of the sequence 133 frame = imread(fistFrameFilename); 134 if(!frame.data){ 135 //error in opening the first image 136 cerr << "Unable to open first image frame: " << fistFrameFilename << endl; 137 exit(EXIT_FAILURE); 138 } 139 ... 140 //search for the next image in the sequence 141 ostringstream oss; 142 oss << (frameNumber + 1); 143 string nextFrameNumberString = oss.str(); 144 string nextFrameFilename = prefix + nextFrameNumberString + suffix; 145 //read the next frame 146 frame = imread(nextFrameFilename); 147 if(!frame.data){ 148 //error in opening the next image in the sequence 149 cerr << "Unable to open image frame: " << nextFrameFilename << endl; 150 exit(EXIT_FAILURE); 151 } 152 //update the path of the current frame 153 fn.assign(nextFrameFilename); 154 @endcode 155 Note that this example works only on image sequences in which the filename format is \<n\>.png, 156 where n is the frame number (e.g., 7.png). 157 158 Results 159 ------- 160 161 - Given the following input parameters: 162 @code{.cpp} 163 -vid Video_001.avi 164 @endcode 165 The output of the program will look as the following: 166 167 ![](images/Background_Subtraction_Tutorial_Result_1.png) 168 169 - The video file Video_001.avi is part of the [Background Models Challenge 170 (BMC)](http://bmc.univ-bpclermont.fr/) data set and it can be downloaded from the following link 171 [Video_001](http://bmc.univ-bpclermont.fr/sites/default/files/videos/evaluation/Video_001.zip) 172 (about 32 MB). 173 - If you want to process a sequence of images, then the '-img' option has to be chosen: 174 @code{.cpp} 175 -img 111_png/input/1.png 176 @endcode 177 The output of the program will look as the following: 178 179 ![](images/Background_Subtraction_Tutorial_Result_2.png) 180 181 - The sequence of images used in this example is part of the [Background Models Challenge 182 (BMC)](http://bmc.univ-bpclermont.fr/) dataset and it can be downloaded from the following link 183 [sequence 111](http://bmc.univ-bpclermont.fr/sites/default/files/videos/learning/111_png.zip) 184 (about 708 MB). Please, note that this example works only on sequences in which the filename 185 format is \<n\>.png, where n is the frame number (e.g., 7.png). 186 187 Evaluation 188 ---------- 189 190 To quantitatively evaluate the results obtained, we need to: 191 192 - Save the output images; 193 - Have the ground truth images for the chosen sequence. 194 195 In order to save the output images, we can use @ref cv::imwrite . Adding the following code allows 196 for saving the foreground masks. 197 @code{.cpp} 198 string imageToSave = "output_MOG_" + frameNumberString + ".png"; 199 bool saved = imwrite(imageToSave, fgMaskMOG); 200 if(!saved) { 201 cerr << "Unable to save " << imageToSave << endl; 202 } 203 @endcode 204 Once we have collected the result images, we can compare them with the ground truth data. There 205 exist several publicly available sequences for background subtraction that come with ground truth 206 data. If you decide to use the [Background Models Challenge (BMC)](http://bmc.univ-bpclermont.fr/), 207 then the result images can be used as input for the [BMC 208 Wizard](http://bmc.univ-bpclermont.fr/?q=node/7). The wizard can compute different measures about 209 the accuracy of the results. 210 211 References 212 ---------- 213 214 - [Background Models Challenge (BMC) website](http://bmc.univ-bpclermont.fr/) 215 - A Benchmark Dataset for Foreground/Background Extraction @cite vacavant2013benchmark 216