VPI - Vision Programming Interface

1.2 Release

Background Subtractor

Overview

This application fetches frames from input video source, runs the algorithms on current images, and then calculate foreground mask. The output foreground mask will be saved to a video file.

Instructions

The command line parameters are:

<backend> <input video>

where

  • backend: Defines the backend that will perform the processing. Only cpu and cuda are currently supported.
  • input video: Input video file name, it accepts .mp4, .avi and possibly others, depending on OpenCV's support.

Here's one example:

  • C++
    ./vpi_sample_14_background_subtractor cpu ../assets/pedestrians.mp4
  • Python
    python main.py cpu ../assets/pedestrians.mp4

The application will process pedestrians.mp4 and create fgmask_cpu.mp4 and bgimage_cpu.mp4.

Note
If using OpenCV-2.4 or older (i.e. on Ubuntu 16.04), output files are fgmask_cpu.avi and bgimage_cpu.mp4.

Results

Input videoForeground videoBackground video

Source Code

For convenience, here's the code that is also installed in the samples directory.

Language:
27 import cv2
28 import sys
29 import vpi
30 import numpy as np
31 from argparse import ArgumentParser
32 
33 # ----------------------------
34 # Parse command line arguments
35 
36 parser = ArgumentParser()
37 parser.add_argument('backend', choices=['cpu','cuda'],
38  help='Backend to be used for processing')
39 
40 parser.add_argument('input',
41  help='Input video to be denoised')
42 
43 args = parser.parse_args();
44 
45 if args.backend == 'cuda':
46  backend = vpi.Backend.CUDA
47 else:
48  assert args.backend == 'cpu'
49  backend = vpi.Backend.CPU
50 
51 # -----------------------------
52 # Open input and output videos
53 
54 inVideo = cv2.VideoCapture(args.input)
55 
56 if int(cv2.__version__.split('.')[0]) >= 3:
57  extOutputVideo = '.mp4'
58  fourcc = cv2.VideoWriter_fourcc(*'avc1')
59  inSize = (int(inVideo.get(cv2.CAP_PROP_FRAME_WIDTH)), int(inVideo.get(cv2.CAP_PROP_FRAME_HEIGHT)))
60  fps = inVideo.get(cv2.CAP_PROP_FPS)
61 else:
62  # MP4 support with OpenCV-2.4 has issues, we'll use
63  # avi/mpeg instead.
64  extOutputVideo = '.avi'
65  fourcc = cv2.cv.CV_FOURCC('M','P','E','G')
66  inSize = (int(inVideo.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)), int(inVideo.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)))
67  fps = inVideo.get(cv2.cv.CV_CAP_PROP_FPS)
68 
69 outVideoFGMask = cv2.VideoWriter('fgmask_python'+str(sys.version_info[0])+'_'+args.backend+extOutputVideo,
70  fourcc, fps, inSize)
71 
72 outVideoBGImage = cv2.VideoWriter('bgimage_python'+str(sys.version_info[0])+'_'+args.backend+extOutputVideo,
73  fourcc, fps, inSize)
74 
75 #--------------------------------------------------------------
76 # Create the Background Subtractor object using the backend specified by the user
77 with backend:
78  bgsub = vpi.BackgroundSubtractor(inSize, vpi.Format.BGR8)
79 
80 #--------------------------------------------------------------
81 # Main processing loop
82 idxFrame = 0
83 while True:
84  print("Processing frame {}".format(idxFrame))
85  idxFrame+=1
86 
87  # Read one input frame
88  ret, cvFrame = inVideo.read()
89  if not ret:
90  break
91 
92  # Get the foreground mask and background image estimates
93  fgmask, bgimage = bgsub(vpi.asimage(cvFrame, vpi.Format.BGR8), learnrate=0.01)
94 
95  # Mask needs to be converted to BGR8 for output
96  fgmask = fgmask.convert(vpi.Format.BGR8, backend=vpi.Backend.CUDA);
97 
98  # Write images to output videos
99  with fgmask.rlock(), bgimage.rlock():
100  outVideoFGMask.write(fgmask.cpu())
101  outVideoBGImage.write(bgimage.cpu())
102 
103 # vim: ts=8:sw=4:sts=4:et:ai
29 #include <opencv2/core/version.hpp>
30 #if CV_MAJOR_VERSION >= 3
31 # include <opencv2/imgcodecs.hpp>
32 # include <opencv2/videoio.hpp>
33 #else
34 # include <opencv2/highgui/highgui.hpp>
35 #endif
36 
37 #include <opencv2/imgproc/imgproc.hpp>
38 #include <vpi/OpenCVInterop.hpp>
39 
40 #include <vpi/Array.h>
41 #include <vpi/Image.h>
42 #include <vpi/ImageFormat.h>
43 #include <vpi/Pyramid.h>
44 #include <vpi/Status.h>
45 #include <vpi/Stream.h>
48 
49 #include <iostream>
50 #include <sstream>
51 
52 #define CHECK_STATUS(STMT) \
53  do \
54  { \
55  VPIStatus status = (STMT); \
56  if (status != VPI_SUCCESS) \
57  { \
58  char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH]; \
59  vpiGetLastStatusMessage(buffer, sizeof(buffer)); \
60  std::ostringstream ss; \
61  ss << vpiStatusGetName(status) << ": " << buffer; \
62  throw std::runtime_error(ss.str()); \
63  } \
64  } while (0);
65 
66 int main(int argc, char *argv[])
67 {
68  // OpenCV image that will be wrapped by a VPIImage.
69  // Define it here so that it's destroyed *after* wrapper is destroyed
70  cv::Mat cvCurFrame;
71 
72  // VPI objects that will be used
73  VPIStream stream = NULL;
74  VPIImage imgCurFrame = NULL;
75  VPIImage bgimage = NULL;
76  VPIImage fgmask = NULL;
77  VPIPayload payload = NULL;
78 
79  int retval = 0;
80 
81  try
82  {
83  if (argc != 3)
84  {
85  throw std::runtime_error(std::string("Usage: ") + argv[0] + " <cpu|cuda> <input_video>");
86  }
87 
88  // Parse input parameters
89  std::string strBackend = argv[1];
90  std::string strInputVideo = argv[2];
91 
92  VPIBackend backend;
93  if (strBackend == "cpu")
94  {
95  backend = VPI_BACKEND_CPU;
96  }
97  else if (strBackend == "cuda")
98  {
99  backend = VPI_BACKEND_CUDA;
100  }
101  else
102  {
103  throw std::runtime_error("Backend '" + strBackend + "' not recognized.");
104  }
105 
106  // Load the input video
107  cv::VideoCapture invid;
108  if (!invid.open(strInputVideo))
109  {
110  throw std::runtime_error("Can't open '" + strInputVideo + "'");
111  }
112 
113 #if CV_MAJOR_VERSION >= 3
114  int32_t width = invid.get(cv::CAP_PROP_FRAME_WIDTH);
115  int32_t height = invid.get(cv::CAP_PROP_FRAME_HEIGHT);
116 
117  int fourcc = cv::VideoWriter::fourcc('a', 'v', 'c', '1');
118  double fps = invid.get(cv::CAP_PROP_FPS);
119  std::string extOutputVideo = ".mp4";
120 #else
121  int32_t width = invid.get(CV_CAP_PROP_FRAME_WIDTH);
122  int32_t height = invid.get(CV_CAP_PROP_FRAME_HEIGHT);
123 
124  // MP4 support with OpenCV-2.4 has issues, we'll use
125  // avi/mpeg instead.
126  int fourcc = CV_FOURCC('M', 'P', 'E', 'G');
127  double fps = invid.get(CV_CAP_PROP_FPS);
128  std::string extOutputVideo = ".avi";
129 #endif
130 
131  // Create the stream where processing will happen. We'll use user-provided backend.
132  CHECK_STATUS(vpiStreamCreate(backend, &stream));
133 
134  // Create background subtractor payload to be executed on the given backend
135  // OpenCV delivers us BGR8 images, so the algorithm is configured to accept that.
136  CHECK_STATUS(vpiCreateBackgroundSubtractor(backend, width, height, VPI_IMAGE_FORMAT_BGR8, &payload));
137 
138  // Create foreground image
139  CHECK_STATUS(vpiImageCreate(width, height, VPI_IMAGE_FORMAT_U8, 0, &fgmask));
140 
141  // Create background image
142  CHECK_STATUS(vpiImageCreate(width, height, VPI_IMAGE_FORMAT_BGR8, 0, &bgimage));
143 
144  cv::VideoWriter outVideo("fgmask_" + strBackend + extOutputVideo, fourcc, fps, cv::Size(width, height), false);
145  if (!outVideo.isOpened())
146  {
147  throw std::runtime_error("Can't create output video");
148  }
149 
150  cv::VideoWriter bgimageVideo("bgimage_" + strBackend + extOutputVideo, fourcc, fps, cv::Size(width, height));
151  if (!outVideo.isOpened())
152  {
153  throw std::runtime_error("Can't create output video");
154  }
155 
156  // Fetch a new frame until video ends
157  int idxFrame = 1;
158 
159  while (invid.read(cvCurFrame))
160  {
161  printf("Processing frame %d\n", idxFrame++);
162  // Wrap frame into a VPIImage
163  if (imgCurFrame == NULL)
164  {
165  CHECK_STATUS(vpiImageCreateOpenCVMatWrapper(cvCurFrame, 0, &imgCurFrame));
166  }
167  else
168  {
169  CHECK_STATUS(vpiImageSetWrappedOpenCVMat(imgCurFrame, cvCurFrame));
170  }
171 
173  CHECK_STATUS(vpiInitBackgroundSubtractorParams(&params));
174  params.learningRate = 0.01;
175 
176  CHECK_STATUS(
177  vpiSubmitBackgroundSubtractor(stream, backend, payload, imgCurFrame, fgmask, bgimage, &params));
178 
179  // Wait for processing to finish.
180  CHECK_STATUS(vpiStreamSync(stream));
181 
182  {
183  // Now add it to the output video stream
184  VPIImageData imgdata;
185  CHECK_STATUS(vpiImageLock(fgmask, VPI_LOCK_READ, &imgdata));
186 
187  cv::Mat outFrame;
188  CHECK_STATUS(vpiImageDataExportOpenCVMat(imgdata, &outFrame));
189 
190  outVideo << outFrame;
191 
192  CHECK_STATUS(vpiImageUnlock(fgmask));
193  }
194 
195  {
196  VPIImageData bgdata;
197  CHECK_STATUS(vpiImageLock(bgimage, VPI_LOCK_READ, &bgdata));
198 
199  cv::Mat outFrame;
200  CHECK_STATUS(vpiImageDataExportOpenCVMat(bgdata, &outFrame));
201 
202  bgimageVideo << outFrame;
203 
204  CHECK_STATUS(vpiImageUnlock(bgimage));
205  }
206  }
207  }
208  catch (std::exception &e)
209  {
210  std::cerr << e.what() << std::endl;
211  retval = 1;
212  }
213 
214  // Destroy all resources used
215  vpiStreamDestroy(stream);
216  vpiPayloadDestroy(payload);
217 
218  vpiImageDestroy(imgCurFrame);
219  vpiImageDestroy(fgmask);
220  vpiImageDestroy(bgimage);
221 
222  return retval;
223 }
224 
225 // vim: ts=8:sw=4:sts=4:et:ai
Functions and structures for dealing with VPI arrays.
Declares functions that implement background subtractor(GMM) algorithms.
Declares functions that handle image format conversion.
Defines types and functions to handle image formats.
Functions and structures for dealing with VPI images.
Functions for handling OpenCV interoperability with VPI.
Functions and structures for dealing with VPI pyramids.
Declaration of VPI status codes handling functions.
Declares functions dealing with VPI streams.
float learningRate
Learning rate that indicates how fast the background model is learnt.
VPIStatus vpiCreateBackgroundSubtractor(uint32_t backends, int32_t imageWidth, int32_t imageHeight, VPIImageFormat inputFormat, VPIPayload *payload)
Creates payload for vpiSubmitBackgroundSubtractor.
VPIStatus vpiInitBackgroundSubtractorParams(VPIBackgroundSubtractorParams *params)
Initializes VPIBackgroundSubtractorParams with default values.
VPIStatus vpiSubmitBackgroundSubtractor(VPIStream stream, uint32_t backend, VPIPayload payload, VPIImage inFrame, VPIImage outFGMask, VPIImage outBGImage, const VPIBackgroundSubtractorParams *params)
Submits a background subtractor operation to the stream associated with the given payload.
Structure that defines the parameters for vpiCreateBackgroundSubtractor.
@ VPI_IMAGE_FORMAT_BGR8
Single plane with interleaved BGR 8-bit channel.
Definition: ImageFormat.h:278
@ VPI_IMAGE_FORMAT_U8
Single plane with one 8-bit unsigned integer channel.
Definition: ImageFormat.h:104
VPIStatus vpiImageLock(VPIImage img, VPILockMode mode, VPIImageData *hostData)
Acquires the lock on an image object and returns a pointer to the image planes.
void vpiImageDestroy(VPIImage img)
Destroy an image instance.
struct VPIImageImpl * VPIImage
A handle to an image.
Definition: Types.h:215
VPIStatus vpiImageCreate(int32_t width, int32_t height, VPIImageFormat fmt, uint32_t flags, VPIImage *img)
Create an empty image instance with the specified flags.
VPIStatus vpiImageUnlock(VPIImage img)
Releases the lock on an image object.
Stores information about image characteristics and content.
Definition: Image.h:159
VPIStatus vpiImageDataExportOpenCVMat(const VPIImageData &imgData, cv::Mat *mat)
Fills an existing cv::Mat with data from VPIImageData coming from a locked VPIImage.
VPIStatus vpiImageSetWrappedOpenCVMat(VPIImage img, const cv::Mat &mat)
Redefines the wrapped cv::Mat of an existing VPIImage wrapper.
VPIStatus vpiImageCreateOpenCVMatWrapper(const cv::Mat &mat, VPIImageFormat fmt, uint32_t flags, VPIImage *img)
Wraps a cv::Mat in an VPIImage with the given image format.
struct VPIPayloadImpl * VPIPayload
A handle to an algorithm payload.
Definition: Types.h:227
void vpiPayloadDestroy(VPIPayload payload)
Deallocates the payload object and all associated resources.
struct VPIStreamImpl * VPIStream
A handle to a stream.
Definition: Types.h:209
VPIStatus vpiStreamSync(VPIStream stream)
Blocks the calling thread until all submitted commands in this stream queue are done (queue is empty)...
VPIBackend
VPI Backend types.
Definition: Types.h:91
void vpiStreamDestroy(VPIStream stream)
Destroy a stream instance and deallocate all HW resources.
VPIStatus vpiStreamCreate(uint32_t flags, VPIStream *stream)
Create a stream instance.
@ VPI_BACKEND_CUDA
CUDA backend.
Definition: Types.h:93
@ VPI_BACKEND_CPU
CPU backend.
Definition: Types.h:92
@ VPI_LOCK_READ
Lock memory only for reading.
Definition: Types.h:383