2  * openvc_trail_effect - experiments about video trail effects
 
   4  * Copyright (C) 2015  Antonio Ospite <ao2@ao2.it>
 
   6  * This program is free software: you can redistribute it and/or modify
 
   7  * it under the terms of the GNU General Public License as published by
 
   8  * the Free Software Foundation, either version 2 of the License, or
 
   9  * (at your option) any later version.
 
  11  * This program is distributed in the hope that it will be useful,
 
  12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  14  * GNU General Public License for more details.
 
  16  * You should have received a copy of the GNU General Public License
 
  17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
  20 #include <opencv2/opencv.hpp>
 
  24 #include "Segmentation.hpp"
 
  27 static void usage(const char *name)
 
  29         std::cout << "usage: " << name << " [OPTIONS]" << std::endl;
 
  30         std::cout << "OPTIONS:" << std::endl;
 
  31         std::cout << "\t-i <file>\tthe input file (if missing, a webcam will be tried)" << std::endl;
 
  32         std::cout << "\t-o <file>\tthe optional output file" << std::endl;
 
  33         std::cout << "\t-l <number>\tthe trail length in frames" << std::endl;
 
  34         std::cout << "\t\t\tthe default is 25" << std::endl;
 
  35         std::cout << "\t\t\tNOTES:" << std::endl;
 
  36         std::cout << "\t\t\t  * a negative value means an 'infinite' trail" << std::endl;
 
  37         std::cout << "\t-s <method>\tthe image segmentation method" << std::endl;
 
  38         std::cout << "\t\t\tvalid values are:" << std::endl;
 
  39         std::cout << "\t\t\t none, threshold, background" << std::endl;
 
  40         std::cout << "\t\t\tthe default is 'background'" << std::endl;
 
  41         std::cout << "\t\t\tNOTES:" << std::endl;
 
  42         std::cout << "\t\t\t  * 'none' is only useful with '-d average'" << std::endl;
 
  43         std::cout << "\t-b <number>\tthe number of initial frames for background learning," << std::endl;
 
  44         std::cout << "\t\t\tthe default is 50" << std::endl;
 
  45         std::cout << "\t\t\tNOTES:" << std::endl;
 
  46         std::cout << "\t\t\t  * only useful with '-s background'" << std::endl;
 
  47         std::cout << "\t-t <number>\tthe level for the threshold segmentation method," << std::endl;
 
  48         std::cout << "\t\t\tthe default is 5" << std::endl;
 
  49         std::cout << "\t\t\tNOTES:" << std::endl;
 
  50         std::cout << "\t\t\t  * only useful with '-s threshold'" << std::endl;
 
  51         std::cout << "\t-d <method>\tthe trail drawing method" << std::endl;
 
  52         std::cout << "\t\t\tvalid values are:" << std::endl;
 
  53         std::cout << "\t\t\t  copy, accumulate, fadecopy, fadeaccumulate, average" << std::endl;
 
  54         std::cout << "\t\t\tthe default is 'copy'" << std::endl;
 
  55         std::cout << "\t\t\tNOTES:" << std::endl;
 
  56         std::cout << "\t\t\t  * 'copy' is useless with '-s none'" << std::endl;
 
  57         std::cout << "\t\t\t  * the difference between 'fadecopy' and" << std::endl;
 
  58         std::cout << "\t\t\t    'fadeaccumulate is cleared when using '-B'" << std::endl;
 
  59         std::cout << "\t-r\t\treverse the trail drawing sequence" << std::endl;
 
  60         std::cout << "\t-B\t\tshow the background behind the trail" << std::endl;
 
  61         std::cout << "\t\t\tNOTES:" << std::endl;
 
  62         std::cout << "\t\t\t  * only used with '-s background'" << std::endl;
 
  63         std::cout << "\t-F\t\tredraw the current frame on top of the trail" << std::endl;
 
  64         std::cout << "\t\t\tNOTES:" << std::endl;
 
  65         std::cout << "\t\t\t  * noticeable with '-s average'" << std::endl;
 
  66         std::cout << "\t\t\t  * noticeable with reverse faded trails" << std::endl;
 
  69 int main(int argc, char *argv[])
 
  74         std::string input_file;
 
  75         std::string output_file;
 
  76         int trail_lenght = 25;
 
  77         std::string segmentation_method("background");
 
  78         int background_learn_frames = 50;
 
  79         int threshold_level = 5;
 
  80         std::string drawing_method("copy");
 
  81         bool reverse_trail = false;
 
  82         bool show_background = false;
 
  83         bool redraw_current_frame = false;
 
  85         while ((opt = getopt(argc, argv, "i:o:l:s:b:t:d:rBFh")) != -1) {
 
  88                         input_file = std::string(optarg);
 
  91                         output_file = std::string(optarg);
 
  94                         trail_lenght = atoi(optarg);
 
  97                         segmentation_method = std::string(optarg);
 
 100                         background_learn_frames = atoi(optarg);
 
 103                         threshold_level = atoi(optarg);
 
 106                         drawing_method = std::string(optarg);
 
 109                         reverse_trail = true;
 
 112                         show_background = true;
 
 115                         redraw_current_frame = true;
 
 126         cv::VideoCapture inputVideo;
 
 127         cv::VideoWriter outputVideo;
 
 131         if (!input_file.empty()) {
 
 132                 inputVideo.open(input_file);
 
 135                 // XXX Hardcode the V4L2 backend on linux for now because the
 
 136                 // GStreamer one lacks some functionality, see:
 
 137                 // https://github.com/opencv/opencv/issues/18562
 
 138                 inputVideo.open(0, cv::CAP_V4L2);
 
 144         if (!inputVideo.isOpened()) {
 
 145                 std::cerr  << "Could not open the input video." << std::endl;
 
 150         frame_size = cv::Size((int) inputVideo.get(cv::CAP_PROP_FRAME_WIDTH),
 
 151                               (int) inputVideo.get(cv::CAP_PROP_FRAME_HEIGHT));
 
 153         if (!output_file.empty()) {
 
 154                 int fps = inputVideo.get(cv::CAP_PROP_FPS);
 
 158                 outputVideo.open(output_file, cv::VideoWriter::fourcc('M','J','P','G'), fps, frame_size, true);
 
 159                 if (!outputVideo.isOpened()) {
 
 160                         std::cerr  << "Could not open the output video for write." << std::endl;
 
 168                 trail = new ReverseTrail(trail_lenght, frame_size);
 
 170                 trail = new ForwardTrail(trail_lenght, frame_size);
 
 172         trail->setRedrawCurrentFrame(redraw_current_frame);
 
 174         if (trail->setDrawingMethod(drawing_method) < 0) {
 
 175                 std::cerr  << "Invalid drawing method." << std::endl;
 
 177                 goto out_delete_trail;
 
 180         Segmentation *segmentation;
 
 181         if (segmentation_method == "background") {
 
 182                 segmentation = new MOG2Segmentation(inputVideo, background_learn_frames);
 
 183                 if (show_background) {
 
 184                         cv::Mat background(frame_size, inputVideo.get(cv::CAP_PROP_FORMAT));
 
 186                         ((MOG2Segmentation *)segmentation)->getBackgroundImage(background);
 
 187                         trail->setBackground(background);
 
 189         } else if (segmentation_method == "threshold") {
 
 190                 segmentation = new ThresholdSegmentation(threshold_level);
 
 191         } else if (segmentation_method == "none") {
 
 192                 segmentation = new DummySegmentation();
 
 194                 std::cerr  << "Invalid segmentation method." << std::endl;
 
 196                 goto out_delete_trail;
 
 199         cv::namedWindow("Frame", cv::WINDOW_NORMAL);
 
 202                 inputVideo >> input_frame;
 
 204                 Frame *foreground = new Frame(input_frame,
 
 205                                               segmentation->getForegroundMask(input_frame));
 
 206                 trail->update(foreground);
 
 208                 cv::Mat canvas = cv::Mat::zeros(input_frame.size(), input_frame.type());
 
 211                 cv::imshow("Frame", canvas);
 
 212                 if (cv::waitKeyEx(30) >= 0)
 
 215                 if (outputVideo.isOpened())
 
 216                         outputVideo << canvas;
 
 219         cv::destroyWindow("Frame");