|
1 | 1 | #include "opencv2/core.hpp"
|
2 |
| -#include <opencv2/core/utility.hpp> |
3 | 2 | #include "opencv2/imgproc.hpp"
|
4 |
| -#include "opencv2/video/background_segm.hpp" |
| 3 | +#include "opencv2/video.hpp" |
5 | 4 | #include "opencv2/videoio.hpp"
|
6 | 5 | #include "opencv2/highgui.hpp"
|
7 |
| -#include <stdio.h> |
| 6 | +#include <iostream> |
8 | 7 |
|
9 | 8 | using namespace std;
|
10 | 9 | using namespace cv;
|
11 | 10 |
|
12 |
| -static void help() |
13 |
| -{ |
14 |
| - printf("\nDo background segmentation, especially demonstrating the use of cvUpdateBGStatModel().\n" |
15 |
| -"Learns the background at the start and then segments.\n" |
16 |
| -"Learning is togged by the space key. Will read from file or camera\n" |
17 |
| -"Usage: \n" |
18 |
| -" ./bgfg_segm [--camera]=<use camera, if this key is present>, [--file_name]=<path to movie file> \n\n"); |
19 |
| -} |
20 |
| - |
21 |
| -const char* keys = |
22 |
| -{ |
23 |
| - "{c camera | | use camera or not}" |
24 |
| - "{m method |mog2 | method (knn or mog2) }" |
25 |
| - "{s smooth | | smooth the mask }" |
26 |
| - "{fn file_name|../data/tree.avi | movie file }" |
27 |
| -}; |
28 |
| - |
29 |
| -//this is a sample for foreground detection functions |
30 | 11 | int main(int argc, const char** argv)
|
31 | 12 | {
|
32 |
| - help(); |
33 |
| - |
| 13 | + const String keys = "{c camera||use video stream from camera (default is NO)}" |
| 14 | + "{fn file_name|../data/tree.avi|video file}" |
| 15 | + "{m method|mog2|method: background subtraction algorithm ('knn', 'mog2')}" |
| 16 | + "{h help||show help message}"; |
34 | 17 | CommandLineParser parser(argc, argv, keys);
|
| 18 | + parser.about("This sample demonstrates background segmentation."); |
| 19 | + if (parser.has("help")) |
| 20 | + { |
| 21 | + parser.printMessage(); |
| 22 | + return 0; |
| 23 | + } |
35 | 24 | bool useCamera = parser.has("camera");
|
36 |
| - bool smoothMask = parser.has("smooth"); |
37 |
| - string file = parser.get<string>("file_name"); |
38 |
| - string method = parser.get<string>("method"); |
39 |
| - VideoCapture cap; |
40 |
| - bool update_bg_model = true; |
| 25 | + String file = parser.get<String>("file_name"); |
| 26 | + String method = parser.get<String>("method"); |
| 27 | + if (!parser.check()) |
| 28 | + { |
| 29 | + parser.printErrors(); |
| 30 | + return 1; |
| 31 | + } |
41 | 32 |
|
42 |
| - if( useCamera ) |
| 33 | + VideoCapture cap; |
| 34 | + if (useCamera) |
43 | 35 | cap.open(0);
|
44 | 36 | else
|
45 | 37 | cap.open(file.c_str());
|
46 |
| - |
47 |
| - parser.printMessage(); |
48 |
| - |
49 |
| - if( !cap.isOpened() ) |
| 38 | + if (!cap.isOpened()) |
50 | 39 | {
|
51 |
| - printf("can not open camera or video file\n"); |
52 |
| - return -1; |
| 40 | + cout << "Can not open video stream: '" << (useCamera ? "<camera 0>" : file) << "'" << endl; |
| 41 | + return 2; |
53 | 42 | }
|
54 | 43 |
|
55 |
| - namedWindow("image", WINDOW_NORMAL); |
56 |
| - namedWindow("foreground mask", WINDOW_NORMAL); |
57 |
| - namedWindow("foreground image", WINDOW_NORMAL); |
58 |
| - namedWindow("mean background image", WINDOW_NORMAL); |
59 |
| - |
60 |
| - Ptr<BackgroundSubtractor> bg_model = method == "knn" ? |
61 |
| - createBackgroundSubtractorKNN().dynamicCast<BackgroundSubtractor>() : |
62 |
| - createBackgroundSubtractorMOG2().dynamicCast<BackgroundSubtractor>(); |
| 44 | + Ptr<BackgroundSubtractor> model; |
| 45 | + if (method == "knn") |
| 46 | + model = createBackgroundSubtractorKNN(); |
| 47 | + else if (method == "mog2") |
| 48 | + model = createBackgroundSubtractorMOG2(); |
| 49 | + if (!model) |
| 50 | + { |
| 51 | + cout << "Can not create background model using provided method: '" << method << "'" << endl; |
| 52 | + return 3; |
| 53 | + } |
63 | 54 |
|
64 |
| - Mat img0, img, fgmask, fgimg; |
| 55 | + cout << "Press <space> to toggle background model update" << endl; |
| 56 | + cout << "Press 's' to toggle foreground mask smoothing" << endl; |
| 57 | + cout << "Press ESC or 'q' to exit" << endl; |
| 58 | + bool doUpdateModel = true; |
| 59 | + bool doSmoothMask = false; |
65 | 60 |
|
66 |
| - for(;;) |
| 61 | + Mat inputFrame, frame, foregroundMask, foreground, background; |
| 62 | + for (;;) |
67 | 63 | {
|
68 |
| - cap >> img0; |
69 |
| - |
70 |
| - if( img0.empty() ) |
| 64 | + // prepare input frame |
| 65 | + cap >> inputFrame; |
| 66 | + if (inputFrame.empty()) |
| 67 | + { |
| 68 | + cout << "Finished reading: empty frame" << endl; |
71 | 69 | break;
|
| 70 | + } |
| 71 | + const Size scaledSize(640, 640 * inputFrame.rows / inputFrame.cols); |
| 72 | + resize(inputFrame, frame, scaledSize, 0, 0, INTER_LINEAR); |
72 | 73 |
|
73 |
| - resize(img0, img, Size(640, 640*img0.rows/img0.cols), 0, 0, INTER_LINEAR_EXACT); |
| 74 | + // pass the frame to background model |
| 75 | + model->apply(frame, foregroundMask, doUpdateModel ? -1 : 0); |
74 | 76 |
|
75 |
| - if( fgimg.empty() ) |
76 |
| - fgimg.create(img.size(), img.type()); |
| 77 | + // show processed frame |
| 78 | + imshow("image", frame); |
77 | 79 |
|
78 |
| - //update the model |
79 |
| - bg_model->apply(img, fgmask, update_bg_model ? -1 : 0); |
80 |
| - if( smoothMask ) |
| 80 | + // show foreground image and mask (with optional smoothing) |
| 81 | + if (doSmoothMask) |
81 | 82 | {
|
82 |
| - GaussianBlur(fgmask, fgmask, Size(11, 11), 3.5, 3.5); |
83 |
| - threshold(fgmask, fgmask, 10, 255, THRESH_BINARY); |
| 83 | + GaussianBlur(foregroundMask, foregroundMask, Size(11, 11), 3.5, 3.5); |
| 84 | + threshold(foregroundMask, foregroundMask, 10, 255, THRESH_BINARY); |
84 | 85 | }
|
85 |
| - |
86 |
| - fgimg = Scalar::all(0); |
87 |
| - img.copyTo(fgimg, fgmask); |
88 |
| - |
89 |
| - Mat bgimg; |
90 |
| - bg_model->getBackgroundImage(bgimg); |
91 |
| - |
92 |
| - imshow("image", img); |
93 |
| - imshow("foreground mask", fgmask); |
94 |
| - imshow("foreground image", fgimg); |
95 |
| - if(!bgimg.empty()) |
96 |
| - imshow("mean background image", bgimg ); |
97 |
| - |
98 |
| - char k = (char)waitKey(30); |
99 |
| - if( k == 27 ) break; |
100 |
| - if( k == ' ' ) |
| 86 | + if (foreground.empty()) |
| 87 | + foreground.create(scaledSize, frame.type()); |
| 88 | + foreground = Scalar::all(0); |
| 89 | + frame.copyTo(foreground, foregroundMask); |
| 90 | + imshow("foreground mask", foregroundMask); |
| 91 | + imshow("foreground image", foreground); |
| 92 | + |
| 93 | + // show background image |
| 94 | + model->getBackgroundImage(background); |
| 95 | + if (!background.empty()) |
| 96 | + imshow("mean background image", background ); |
| 97 | + |
| 98 | + // interact with user |
| 99 | + const char key = (char)waitKey(30); |
| 100 | + if (key == 27 || key == 'q') // ESC |
| 101 | + { |
| 102 | + cout << "Exit requested" << endl; |
| 103 | + break; |
| 104 | + } |
| 105 | + else if (key == ' ') |
101 | 106 | {
|
102 |
| - update_bg_model = !update_bg_model; |
103 |
| - if(update_bg_model) |
104 |
| - printf("Background update is on\n"); |
105 |
| - else |
106 |
| - printf("Background update is off\n"); |
| 107 | + doUpdateModel = !doUpdateModel; |
| 108 | + cout << "Toggle background update: " << (doUpdateModel ? "ON" : "OFF") << endl; |
| 109 | + } |
| 110 | + else if (key == 's') |
| 111 | + { |
| 112 | + doSmoothMask = !doSmoothMask; |
| 113 | + cout << "Toggle foreground mask smoothing: " << (doSmoothMask ? "ON" : "OFF") << endl; |
107 | 114 | }
|
108 | 115 | }
|
109 |
| - |
110 | 116 | return 0;
|
111 | 117 | }
|
0 commit comments