diff --git a/samples/cpp/bgfg_segm.cpp b/samples/cpp/bgfg_segm.cpp index e28bf2d86c..71473d124a 100644 --- a/samples/cpp/bgfg_segm.cpp +++ b/samples/cpp/bgfg_segm.cpp @@ -1,111 +1,117 @@ #include "opencv2/core.hpp" -#include #include "opencv2/imgproc.hpp" -#include "opencv2/video/background_segm.hpp" +#include "opencv2/video.hpp" #include "opencv2/videoio.hpp" #include "opencv2/highgui.hpp" -#include +#include using namespace std; using namespace cv; -static void help() -{ - printf("\nDo background segmentation, especially demonstrating the use of cvUpdateBGStatModel().\n" -"Learns the background at the start and then segments.\n" -"Learning is togged by the space key. Will read from file or camera\n" -"Usage: \n" -" ./bgfg_segm [--camera]=, [--file_name]= \n\n"); -} - -const char* keys = -{ - "{c camera | | use camera or not}" - "{m method |mog2 | method (knn or mog2) }" - "{s smooth | | smooth the mask }" - "{fn file_name|../data/tree.avi | movie file }" -}; - -//this is a sample for foreground detection functions int main(int argc, const char** argv) { - help(); - + const String keys = "{c camera||use video stream from camera (default is NO)}" + "{fn file_name|../data/tree.avi|video file}" + "{m method|mog2|method: background subtraction algorithm ('knn', 'mog2')}" + "{h help||show help message}"; CommandLineParser parser(argc, argv, keys); + parser.about("This sample demonstrates background segmentation."); + if (parser.has("help")) + { + parser.printMessage(); + return 0; + } bool useCamera = parser.has("camera"); - bool smoothMask = parser.has("smooth"); - string file = parser.get("file_name"); - string method = parser.get("method"); - VideoCapture cap; - bool update_bg_model = true; + String file = parser.get("file_name"); + String method = parser.get("method"); + if (!parser.check()) + { + parser.printErrors(); + return 1; + } - if( useCamera ) + VideoCapture cap; + if (useCamera) cap.open(0); else cap.open(file.c_str()); - - parser.printMessage(); - - if( !cap.isOpened() ) + if (!cap.isOpened()) { - printf("can not open camera or video file\n"); - return -1; + cout << "Can not open video stream: '" << (useCamera ? "" : file) << "'" << endl; + return 2; } - namedWindow("image", WINDOW_NORMAL); - namedWindow("foreground mask", WINDOW_NORMAL); - namedWindow("foreground image", WINDOW_NORMAL); - namedWindow("mean background image", WINDOW_NORMAL); - - Ptr bg_model = method == "knn" ? - createBackgroundSubtractorKNN().dynamicCast() : - createBackgroundSubtractorMOG2().dynamicCast(); - - Mat img0, img, fgmask, fgimg; - - for(;;) + Ptr model; + if (method == "knn") + model = createBackgroundSubtractorKNN(); + else if (method == "mog2") + model = createBackgroundSubtractorMOG2(); + if (!model) { - cap >> img0; + cout << "Can not create background model using provided method: '" << method << "'" << endl; + return 3; + } - if( img0.empty() ) + cout << "Press to toggle background model update" << endl; + cout << "Press 's' to toggle foreground mask smoothing" << endl; + cout << "Press ESC or 'q' to exit" << endl; + bool doUpdateModel = true; + bool doSmoothMask = false; + + Mat inputFrame, frame, foregroundMask, foreground, background; + for (;;) + { + // prepare input frame + cap >> inputFrame; + if (inputFrame.empty()) + { + cout << "Finished reading: empty frame" << endl; break; - - resize(img0, img, Size(640, 640*img0.rows/img0.cols), 0, 0, INTER_LINEAR_EXACT); - - if( fgimg.empty() ) - fgimg.create(img.size(), img.type()); - - //update the model - bg_model->apply(img, fgmask, update_bg_model ? -1 : 0); - if( smoothMask ) - { - GaussianBlur(fgmask, fgmask, Size(11, 11), 3.5, 3.5); - threshold(fgmask, fgmask, 10, 255, THRESH_BINARY); } + const Size scaledSize(640, 640 * inputFrame.rows / inputFrame.cols); + resize(inputFrame, frame, scaledSize, 0, 0, INTER_LINEAR); - fgimg = Scalar::all(0); - img.copyTo(fgimg, fgmask); + // pass the frame to background model + model->apply(frame, foregroundMask, doUpdateModel ? -1 : 0); - Mat bgimg; - bg_model->getBackgroundImage(bgimg); + // show processed frame + imshow("image", frame); - imshow("image", img); - imshow("foreground mask", fgmask); - imshow("foreground image", fgimg); - if(!bgimg.empty()) - imshow("mean background image", bgimg ); - - char k = (char)waitKey(30); - if( k == 27 ) break; - if( k == ' ' ) + // show foreground image and mask (with optional smoothing) + if (doSmoothMask) { - update_bg_model = !update_bg_model; - if(update_bg_model) - printf("Background update is on\n"); - else - printf("Background update is off\n"); + GaussianBlur(foregroundMask, foregroundMask, Size(11, 11), 3.5, 3.5); + threshold(foregroundMask, foregroundMask, 10, 255, THRESH_BINARY); + } + if (foreground.empty()) + foreground.create(scaledSize, frame.type()); + foreground = Scalar::all(0); + frame.copyTo(foreground, foregroundMask); + imshow("foreground mask", foregroundMask); + imshow("foreground image", foreground); + + // show background image + model->getBackgroundImage(background); + if (!background.empty()) + imshow("mean background image", background ); + + // interact with user + const char key = (char)waitKey(30); + if (key == 27 || key == 'q') // ESC + { + cout << "Exit requested" << endl; + break; + } + else if (key == ' ') + { + doUpdateModel = !doUpdateModel; + cout << "Toggle background update: " << (doUpdateModel ? "ON" : "OFF") << endl; + } + else if (key == 's') + { + doSmoothMask = !doSmoothMask; + cout << "Toggle foreground mask smoothing: " << (doSmoothMask ? "ON" : "OFF") << endl; } } - return 0; }