© 2013, Rich Wareham, CC-BY-SA
This notebook demonstrates how to grab an image from a video camera using OpenCV's VideoCapture
object.
Firstly, we'll import all the libraries we'll be using:
# Use the 'pylab' system for plotting. This is IPython-specific.
%pylab inline
Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline]. For more information, type 'help(pylab)'.
# Under 'normal' Python, you'd import the functions directly from matplotlib and numpy
from matplotlib.pyplot import *
import numpy as np
# Use OpenCV
import cv2
# Set default figure size to be a bit bigger
rcParams['figure.figsize'] = (12,12)
Video grabbing in OpenCV is managed by an object of type VideoCapture
. We need to initialise a new object:
capture = cv2.VideoCapture()
The capture
object has a number of useful methods. Refer to the VideoCapture documentation for more information.
dir(capture)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'get', 'grab', 'isOpened', 'open', 'read', 'release', 'retrieve', 'set']
We must firt open the video stream we want. We could pass the name of a video file here but we want to capture from a video device. To do so we pass the numeric index of the camera to capture from. I only have one camera on my computer so that makes things easier. Pass 0
to use the default device:
capture.open(0)
True
Let's double-check that the capture device is open:
capture.isOpened()
True
The OpenCV VideoCapture
object separates grabbing the frame from actually retrieving it. There is a convenience method, read
, which will do both for us. It returns a flag indicating if a frame was grabbed and, if so, the frame itself.
grabbed, frame = capture.read()
print('Frame grabbed: {0}'.format(grabbed))
Frame grabbed: True
The grabbed frame should be a colour image. Let's look at it's shape:
# The 'shape' of the frame is a 3-tuple giving the number of rows, columns and colour components
frame.shape
(480, 640, 3)
We can use OpenCV to convert the colour image to a greyscale:
# NB the image returned from the camera has the colour components ordered: Blue, Green and Red, just to be annoying.
frame_grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
And let's take a look:
imshow(frame_grey, cmap=cm.gray)
<matplotlib.image.AxesImage at 0x33f3f90>
Beautiful!
It so happens that my camera is an HD one and can capture in 1280x720 resolution. We can use the set
method on the VideoCapture
object to set camera properties. This may not work on your camera, it depends on the model. Also the constants specifying caprutre properties appear only to be defined in the cv
package. (As opposed to cv2
.)
import cv
capture.set(cv.CV_CAP_PROP_FRAME_WIDTH, 1280)
capture.set(cv.CV_CAP_PROP_FRAME_HEIGHT, 720)
False
We can now grab the frame just as before:
grabbed, frame = capture.read()
frame_grey = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
imshow(frame_grey, cmap=cm.gray)
print('Frame grabbed: {0}'.format(grabbed))
Frame grabbed: True
Recall that the frame is annoyingly in BGR order and not RGB. We essentially want to re-order the frame
matrix along its third dimension. Fortunately the powerful slicing and indexing syntax of NumPy comes to our rescue. Trying to plot the frame naively results in the wrong colours:
imshow(frame)
<matplotlib.image.AxesImage at 0x5dc38d0>
But we can re-order the third dimension by simply specifying the correct indices:
imshow(frame[:,:,(2,1,0)])
<matplotlib.image.AxesImage at 0x3546b90>