Home        Store        Learn        Blog

OpenCV Python with Gstreamer Backend

Hi everyone,

I’ve been playing around with getting gstreamer functionality in opencv and thought I’d prefer to use gstreamer as an opencv VideoCapture/VideoWriter backend rather than using the python gstreamer library and having to create the frames manually (which is the approach taken in the ardusub docs).

By default the opencv-python library doesn’t come with the gstreamer backend integrated, so it needs to be built from source. Thankfully the opencv-python GitHub repo does most of the heavy lifting, and also provides a simple way to specify modifications while keeping the defaults for everything else.

Gstreamer Installation

To start with, gstreamer will need to be installed. There are instructions on the gstreamer website, although on Mac you may want to use homebrew instead (e.g. brew install gstreamer gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav).

OpenCV Compilation

If you’ve already got opencv-python installed you’ll want to either uninstall that (pip uninstall opencv-python), or create a virtual environment for this version. Next you’ll need a terminal or command prompt navigated to where you want to put the opencv source code, and proceed as below

# <navigate to where you want the opencv-python repo to be stored>
git clone --recursive https://github.com/skvark/opencv-python.git
cd opencv-python
pip install --upgrade pip wheel
# this is the build step - the repo estimates it can take from 5 
#   mins to > 2 hrs depending on your computer hardware
pip wheel . --verbose
pip install opencv_python*.whl
# note, wheel may be generated in dist/ directory, so may have to cd first

Probably took a while to load, but that’s it!


Now that it’s installed, you can use cv2.VideoCapture and cv2.VideoWriter by passing in a gstreamer command string and specifying the gstreamer backend (e.g. cv2.VideoCapture('videotestsrc ! appsink', cv2.CAP_GSTREAMER)). Note that VideoCapture strings must end with the appsink element, and VideoWriter strings must start with the appsrc element in order to be able to appropriately handle frames.

Personally I prefer to use the wrapper functionality from my library pythonic-cv, which automatically uses threading for speed, context managers for cleanup, and allows iteration over the video stream. It also makes processing convenient. Here’s an example class for a BlueROV camera:

import cv2
from pcv.vidIO import LockedCamera

class BlueROVCamera(LockedCamera):
    ''' A camera class handling h264-encoded UDP stream. '''
    command = ('udpsrc port={} ! '
               'application/x-rtp, payload=96 ! '
               'rtpjitterbuffer ! rtph264depay ! '
               'h264parse ! avdec_h264 ! '
    def __init__(self, port=5600, **kwargs):
        super().__init__(self.command.format(port), cv2.CAP_GSTREAMER, **kwargs)

if __name__ == '__main__':
    # plain stream to measure framerate
    with BlueROVCamera() as cam:
        print(f'fps of pure stream = {cam.measure_framerate(5):.3f}')

    # do some processing (display all colour channels and conversions)
    from pcv.process import channel_options

    print("press 'q' to close stream")
    with BlueROVCamera(process=lambda img: channel_options(img)) as cam:
        print(f'fps of processed stream = {cam.measure_framerate(5):.3f}')

EDIT: added frame-rate measurement example

1 Like