mirror of
https://github.com/opencv/opencv.git
synced 2025-01-18 14:13:15 +08:00
Update background subtraction tutorial with Java and Python codes.
This commit is contained in:
parent
defeda2f70
commit
4bea70a64a
@ -19,190 +19,149 @@ How to Use Background Subtraction Methods {#tutorial_background_subtraction}
|
||||
In the first step, an initial model of the background is computed, while in the second step that
|
||||
model is updated in order to adapt to possible changes in the scene.
|
||||
|
||||
- In this tutorial we will learn how to perform BS by using OpenCV. As input, we will use data
|
||||
coming from the publicly available data set [Background Models Challenge
|
||||
(BMC)](http://bmc.univ-bpclermont.fr/) .
|
||||
- In this tutorial we will learn how to perform BS by using OpenCV.
|
||||
|
||||
Goals
|
||||
-----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
-# Read data from videos by using @ref cv::VideoCapture or image sequences by using @ref
|
||||
cv::imread ;
|
||||
-# Read data from videos or image sequences by using @ref cv::VideoCapture ;
|
||||
-# Create and update the background model by using @ref cv::BackgroundSubtractor class;
|
||||
-# Get and show the foreground mask by using @ref cv::imshow ;
|
||||
-# Save the output by using @ref cv::imwrite to quantitatively evaluate the results.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
In the following you can find the source code. We will let the user chose to process either a video
|
||||
In the following you can find the source code. We will let the user choose to process either a video
|
||||
file or a sequence of images.
|
||||
|
||||
We will use @ref cv::BackgroundSubtractorMOG2 in this sample, to generate the foreground mask.
|
||||
|
||||
The results as well as the input data are shown on the screen.
|
||||
The source file can be downloaded [here ](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/video/bg_sub.cpp).
|
||||
|
||||
@include samples/cpp/tutorial_code/video/bg_sub.cpp
|
||||
@add_toggle_cpp
|
||||
- **Downloadable code**: Click
|
||||
[here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/video/bg_sub.cpp)
|
||||
|
||||
- **Code at glance:**
|
||||
@include samples/cpp/tutorial_code/video/bg_sub.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
- **Downloadable code**: Click
|
||||
[here](https://github.com/opencv/opencv/tree/3.4/samples/java/tutorial_code/video/background_subtraction/BackgroundSubtractionDemo.java)
|
||||
|
||||
- **Code at glance:**
|
||||
@include samples/java/tutorial_code/video/background_subtraction/BackgroundSubtractionDemo.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
- **Downloadable code**: Click
|
||||
[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/video/background_subtraction/bg_sub.py)
|
||||
|
||||
- **Code at glance:**
|
||||
@include samples/python/tutorial_code/video/background_subtraction/bg_sub.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
We discuss the main parts of the above code:
|
||||
We discuss the main parts of the code above:
|
||||
|
||||
-# First, two Mat objects are allocated to store the current frame and two foreground masks,
|
||||
obtained by using two different BS algorithms.
|
||||
@code{.cpp}
|
||||
Mat frame; //current frame
|
||||
Mat fgMaskMOG2; //fg mask fg mask generated by MOG2 method
|
||||
@endcode
|
||||
-# A @ref cv::BackgroundSubtractor object will be used to generate the foreground mask. In this
|
||||
- A @ref cv::BackgroundSubtractor object will be used to generate the foreground mask. In this
|
||||
example, default parameters are used, but it is also possible to declare specific parameters in
|
||||
the create function.
|
||||
@code{.cpp}
|
||||
Ptr<BackgroundSubtractor> pMOG2; //MOG2 Background subtractor
|
||||
...
|
||||
//create Background Subtractor object
|
||||
pMOG2 = createBackgroundSubtractorMOG2(); //MOG2 approach
|
||||
@endcode
|
||||
-# The command line arguments are analysed. The user can chose between two options:
|
||||
- video files (by choosing the option -vid);
|
||||
- image sequences (by choosing the option -img).
|
||||
@code{.cpp}
|
||||
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]);
|
||||
}
|
||||
@endcode
|
||||
-# Suppose you want to process a video file. The video is read until the end is reached or the user
|
||||
presses the button 'q' or the button 'ESC'.
|
||||
@code{.cpp}
|
||||
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);
|
||||
}
|
||||
@endcode
|
||||
-# Every frame is used both for calculating the foreground mask and for updating the background. If
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/video/bg_sub.cpp create
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/video/background_subtraction/BackgroundSubtractionDemo.java create
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/video/background_subtraction/bg_sub.py create
|
||||
@end_toggle
|
||||
|
||||
- A @ref cv::VideoCapture object is used to read the input video or input images sequence.
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/video/bg_sub.cpp capture
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/video/background_subtraction/BackgroundSubtractionDemo.java capture
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/video/background_subtraction/bg_sub.py capture
|
||||
@end_toggle
|
||||
|
||||
- Every frame is used both for calculating the foreground mask and for updating the background. If
|
||||
you want to change the learning rate used for updating the background model, it is possible to
|
||||
set a specific learning rate by passing a third parameter to the 'apply' method.
|
||||
@code{.cpp}
|
||||
//update the background model
|
||||
pMOG2->apply(frame, fgMaskMOG2);
|
||||
@endcode
|
||||
-# The current frame number can be extracted from the @ref cv::VideoCapture object and stamped in
|
||||
set a specific learning rate by passing a parameter to the `apply` method.
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/video/bg_sub.cpp apply
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/video/background_subtraction/BackgroundSubtractionDemo.java apply
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/video/background_subtraction/bg_sub.py apply
|
||||
@end_toggle
|
||||
|
||||
- The current frame number can be extracted from the @ref cv::VideoCapture object and stamped in
|
||||
the top left corner of the current frame. A white rectangle is used to highlight the black
|
||||
colored frame number.
|
||||
@code{.cpp}
|
||||
//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));
|
||||
@endcode
|
||||
-# We are ready to show the current input frame and the results.
|
||||
@code{.cpp}
|
||||
//show the current frame and the fg masks
|
||||
imshow("Frame", frame);
|
||||
imshow("FG Mask MOG 2", fgMaskMOG2);
|
||||
@endcode
|
||||
-# The same operations listed above can be performed using a sequence of images as input. The
|
||||
processImage function is called and, instead of using a @ref cv::VideoCapture object, the images
|
||||
are read by using @ref cv::imread , after individuating the correct path for the next frame to
|
||||
read.
|
||||
@code{.cpp}
|
||||
//read the first file of the sequence
|
||||
frame = 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 sequence
|
||||
ostringstream oss;
|
||||
oss << (frameNumber + 1);
|
||||
string nextFrameNumberString = oss.str();
|
||||
string nextFrameFilename = prefix + nextFrameNumberString + suffix;
|
||||
//read the next frame
|
||||
frame = 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 frame
|
||||
fn.assign(nextFrameFilename);
|
||||
@endcode
|
||||
Note that this example works only on image sequences in which the filename format is \<n\>.png,
|
||||
where n is the frame number (e.g., 7.png).
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/video/bg_sub.cpp display_frame_number
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/video/background_subtraction/BackgroundSubtractionDemo.java display_frame_number
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/video/background_subtraction/bg_sub.py display_frame_number
|
||||
@end_toggle
|
||||
|
||||
- We are ready to show the current input frame and the results.
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/video/bg_sub.cpp show
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/video/background_subtraction/BackgroundSubtractionDemo.java show
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/video/background_subtraction/bg_sub.py show
|
||||
@end_toggle
|
||||
|
||||
Results
|
||||
-------
|
||||
|
||||
- Given the following input parameters:
|
||||
@code{.cpp}
|
||||
-vid Video_001.avi
|
||||
@endcode
|
||||
The output of the program will look as the following:
|
||||
- With the `vtest.avi` video, for the following frame:
|
||||
|
||||
![](images/Background_Subtraction_Tutorial_Result_1.png)
|
||||
![](images/Background_Subtraction_Tutorial_frame.jpg)
|
||||
|
||||
- The video file Video_001.avi is part of the [Background Models Challenge
|
||||
(BMC)](http://bmc.univ-bpclermont.fr/) data set and it can be downloaded from the following link
|
||||
[Video_001](http://bmc.univ-bpclermont.fr/sites/default/files/videos/evaluation/Video_001.zip)
|
||||
(about 32 MB).
|
||||
- If you want to process a sequence of images, then the '-img' option has to be chosen:
|
||||
@code{.cpp}
|
||||
-img 111_png/input/1.png
|
||||
@endcode
|
||||
The output of the program will look as the following:
|
||||
The output of the program will look as the following for MOG2 method (gray areas are detected shadows):
|
||||
|
||||
![](images/Background_Subtraction_Tutorial_Result_2.png)
|
||||
![](images/Background_Subtraction_Tutorial_result_MOG2.jpg)
|
||||
|
||||
- The sequence of images used in this example is part of the [Background Models Challenge
|
||||
(BMC)](http://bmc.univ-bpclermont.fr/) dataset and it can be downloaded from the following link
|
||||
[sequence 111](http://bmc.univ-bpclermont.fr/sites/default/files/videos/learning/111_png.zip)
|
||||
(about 708 MB). Please, note that this example works only on sequences in which the filename
|
||||
format is \<n\>.png, where n is the frame number (e.g., 7.png).
|
||||
The output of the program will look as the following for the KNN method (gray areas are detected shadows):
|
||||
|
||||
Evaluation
|
||||
----------
|
||||
|
||||
To quantitatively evaluate the results obtained, we need to:
|
||||
|
||||
- Save the output images;
|
||||
- Have the ground truth images for the chosen sequence.
|
||||
|
||||
In order to save the output images, we can use @ref cv::imwrite . Adding the following code allows
|
||||
for saving the foreground masks.
|
||||
@code{.cpp}
|
||||
string imageToSave = "output_MOG_" + frameNumberString + ".png";
|
||||
bool saved = imwrite(imageToSave, fgMaskMOG);
|
||||
if(!saved) {
|
||||
cerr << "Unable to save " << imageToSave << endl;
|
||||
}
|
||||
@endcode
|
||||
Once we have collected the result images, we can compare them with the ground truth data. There
|
||||
exist several publicly available sequences for background subtraction that come with ground truth
|
||||
data. If you decide to use the [Background Models Challenge (BMC)](http://bmc.univ-bpclermont.fr/),
|
||||
then the result images can be used as input for the [BMC
|
||||
Wizard](http://bmc.univ-bpclermont.fr/?q=node/7). The wizard can compute different measures about
|
||||
the accuracy of the results.
|
||||
![](images/Background_Subtraction_Tutorial_result_KNN.jpg)
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
- [Background Models Challenge (BMC) website](http://bmc.univ-bpclermont.fr/)
|
||||
- [Background Models Challenge (BMC) website](https://web.archive.org/web/20140418093037/http://bmc.univ-bpclermont.fr/)
|
||||
- A Benchmark Dataset for Foreground/Background Extraction @cite vacavant2013benchmark
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 84 KiB |
Binary file not shown.
Before Width: | Height: | Size: 94 KiB |
Binary file not shown.
After Width: | Height: | Size: 91 KiB |
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
@ -6,6 +6,8 @@ tracking and foreground extractions.
|
||||
|
||||
- @subpage tutorial_background_subtraction
|
||||
|
||||
*Languages:* C++, Java, Python
|
||||
|
||||
*Compatibility:* \> OpenCV 2.4.6
|
||||
|
||||
*Author:* Domenico Daniele Bloisi
|
||||
|
@ -4,180 +4,84 @@
|
||||
* @author Domenico D. Bloisi
|
||||
*/
|
||||
|
||||
//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>
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/videoio.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/video.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
// Global variables
|
||||
Mat frame; //current frame
|
||||
Mat fgMaskMOG2; //fg mask fg mask generated by MOG2 method
|
||||
Ptr<BackgroundSubtractor> pMOG2; //MOG2 Background subtractor
|
||||
char keyboard; //input from keyboard
|
||||
const char* params
|
||||
= "{ help h | | Print usage }"
|
||||
"{ input | ../data/vtest.avi | Path to a video or a sequence of image }"
|
||||
"{ algo | MOG2 | Background subtraction method (KNN, MOG2) }";
|
||||
|
||||
/** Function Headers */
|
||||
void 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function main
|
||||
*/
|
||||
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;
|
||||
CommandLineParser parser(argc, argv, params);
|
||||
parser.about( "This program shows how to use background subtraction methods provided by "
|
||||
" OpenCV. You can process both videos and images.\n" );
|
||||
if (parser.has("help"))
|
||||
{
|
||||
//print help information
|
||||
parser.printMessage();
|
||||
}
|
||||
|
||||
//create GUI windows
|
||||
namedWindow("Frame");
|
||||
namedWindow("FG Mask MOG 2");
|
||||
|
||||
//! [create]
|
||||
//create Background Subtractor objects
|
||||
pMOG2 = createBackgroundSubtractorMOG2(); //MOG2 approach
|
||||
Ptr<BackgroundSubtractor> pBackSub;
|
||||
if (parser.get<String>("algo") == "MOG2")
|
||||
pBackSub = createBackgroundSubtractorMOG2();
|
||||
else
|
||||
pBackSub = createBackgroundSubtractorKNN();
|
||||
//! [create]
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function processVideo
|
||||
*/
|
||||
void processVideo(char* videoFilename) {
|
||||
//create the capture object
|
||||
VideoCapture capture(videoFilename);
|
||||
if(!capture.isOpened()){
|
||||
//! [capture]
|
||||
VideoCapture capture(parser.get<String>("input"));
|
||||
if (!capture.isOpened()){
|
||||
//error in opening the video input
|
||||
cerr << "Unable to open video file: " << videoFilename << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
cerr << "Unable to open: " << parser.get<String>("input") << endl;
|
||||
return 0;
|
||||
}
|
||||
//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);
|
||||
}
|
||||
//! [capture]
|
||||
|
||||
Mat frame, fgMask;
|
||||
while (true) {
|
||||
capture >> frame;
|
||||
if (frame.empty())
|
||||
break;
|
||||
|
||||
//! [apply]
|
||||
//update the background model
|
||||
pMOG2->apply(frame, fgMaskMOG2);
|
||||
pBackSub->apply(frame, fgMask);
|
||||
//! [apply]
|
||||
|
||||
//! [display_frame_number]
|
||||
//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);
|
||||
stringstream ss;
|
||||
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();
|
||||
}
|
||||
//! [display_frame_number]
|
||||
|
||||
/**
|
||||
* @function processImages
|
||||
*/
|
||||
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]
|
||||
//show the current frame and the fg masks
|
||||
imshow("Frame", frame);
|
||||
imshow("FG Mask MOG 2", fgMaskMOG2);
|
||||
imshow("FG Mask", fgMask);
|
||||
//! [show]
|
||||
|
||||
//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);
|
||||
int keyboard = waitKey(30);
|
||||
if (keyboard == 'q' || keyboard == 27)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,79 @@
|
||||
import org.opencv.core.Core;
|
||||
import org.opencv.core.Mat;
|
||||
import org.opencv.core.Point;
|
||||
import org.opencv.core.Scalar;
|
||||
import org.opencv.highgui.HighGui;
|
||||
import org.opencv.imgproc.Imgproc;
|
||||
import org.opencv.video.BackgroundSubtractor;
|
||||
import org.opencv.video.Video;
|
||||
import org.opencv.videoio.VideoCapture;
|
||||
import org.opencv.videoio.Videoio;
|
||||
|
||||
class BackgroundSubtraction {
|
||||
public void run(String[] args) {
|
||||
String input = args.length > 0 ? args[0] : "../data/vtest.avi";
|
||||
boolean useMOG2 = args.length > 1 ? args[1] == "MOG2" : true;
|
||||
|
||||
//! [create]
|
||||
BackgroundSubtractor backSub;
|
||||
if (useMOG2) {
|
||||
backSub = Video.createBackgroundSubtractorMOG2();
|
||||
} else {
|
||||
backSub = Video.createBackgroundSubtractorKNN();
|
||||
}
|
||||
//! [create]
|
||||
|
||||
//! [capture]
|
||||
VideoCapture capture = new VideoCapture(input);
|
||||
if (!capture.isOpened()) {
|
||||
System.err.println("Unable to open: " + input);
|
||||
System.exit(0);
|
||||
}
|
||||
//! [capture]
|
||||
|
||||
Mat frame = new Mat(), fgMask = new Mat();
|
||||
while (true) {
|
||||
capture.read(frame);
|
||||
if (frame.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
//! [apply]
|
||||
// update the background model
|
||||
backSub.apply(frame, fgMask);
|
||||
//! [apply]
|
||||
|
||||
//! [display_frame_number]
|
||||
// get the frame number and write it on the current frame
|
||||
Imgproc.rectangle(frame, new Point(10, 2), new Point(100, 20), new Scalar(255, 255, 255), -1);
|
||||
String frameNumberString = String.format("%d", (int)capture.get(Videoio.CAP_PROP_POS_FRAMES));
|
||||
Imgproc.putText(frame, frameNumberString, new Point(15, 15), Core.FONT_HERSHEY_SIMPLEX, 0.5,
|
||||
new Scalar(0, 0, 0));
|
||||
//! [display_frame_number]
|
||||
|
||||
//! [show]
|
||||
// show the current frame and the fg masks
|
||||
HighGui.imshow("Frame", frame);
|
||||
HighGui.imshow("FG Mask", fgMask);
|
||||
//! [show]
|
||||
|
||||
// get the input from the keyboard
|
||||
int keyboard = HighGui.waitKey(30);
|
||||
if (keyboard == 'q' || keyboard == 27) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
HighGui.waitKey();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
public class BackgroundSubtractionDemo {
|
||||
public static void main(String[] args) {
|
||||
// Load the native OpenCV library
|
||||
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
|
||||
new BackgroundSubtraction().run(args);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
from __future__ import print_function
|
||||
import cv2 as cv
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='This program shows how to use background subtraction methods provided by \
|
||||
OpenCV. You can process both videos and images.')
|
||||
parser.add_argument('--input', type=str, help='Path to a video or a sequence of image.', default='../data/vtest.avi')
|
||||
parser.add_argument('--algo', type=str, help='Background subtraction method (KNN, MOG2).', default='MOG2')
|
||||
args = parser.parse_args()
|
||||
|
||||
## [create]
|
||||
#create Background Subtractor objects
|
||||
if args.algo == 'MOG2':
|
||||
backSub = cv.createBackgroundSubtractorMOG2()
|
||||
else:
|
||||
backSub = cv.createBackgroundSubtractorKNN()
|
||||
## [create]
|
||||
|
||||
## [capture]
|
||||
capture = cv.VideoCapture(args.input)
|
||||
if not capture.isOpened:
|
||||
print('Unable to open: ' + args.input)
|
||||
exit(0)
|
||||
## [capture]
|
||||
|
||||
while True:
|
||||
ret, frame = capture.read()
|
||||
if frame is None:
|
||||
break
|
||||
|
||||
## [apply]
|
||||
#update the background model
|
||||
fgMask = backSub.apply(frame)
|
||||
## [apply]
|
||||
|
||||
## [display_frame_number]
|
||||
#get the frame number and write it on the current frame
|
||||
cv.rectangle(frame, (10, 2), (100,20), (255,255,255), -1)
|
||||
cv.putText(frame, str(capture.get(cv.CAP_PROP_POS_FRAMES)), (15, 15),
|
||||
cv.FONT_HERSHEY_SIMPLEX, 0.5 , (0,0,0))
|
||||
## [display_frame_number]
|
||||
|
||||
## [show]
|
||||
#show the current frame and the fg masks
|
||||
cv.imshow('Frame', frame)
|
||||
cv.imshow('FG Mask', fgMask)
|
||||
## [show]
|
||||
|
||||
keyboard = cv.waitKey(30)
|
||||
if keyboard == 'q' or keyboard == 27:
|
||||
break
|
Loading…
Reference in New Issue
Block a user