Capturing Camera Images with OpenCV

© 2013, Rich Wareham, CC-BY-SA

This notebook demonstrates how to grab an image from a video camera using OpenCV's VideoCapture object.

Setup

Firstly, we'll import all the libraries we'll be using:

In [1]:
# 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)'.

In [2]:
# Under 'normal' Python, you'd import the functions directly from matplotlib and numpy
from matplotlib.pyplot import *
import numpy as np
In [3]:
# Use OpenCV
import cv2
In [4]:
# Set default figure size to be a bit bigger
rcParams['figure.figsize'] = (12,12)

Video grabbing

Video grabbing in OpenCV is managed by an object of type VideoCapture. We need to initialise a new object:

In [5]:
capture = cv2.VideoCapture()

The capture object has a number of useful methods. Refer to the VideoCapture documentation for more information.

In [6]:
dir(capture)
Out[6]:
['__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:

In [7]:
capture.open(0)
Out[7]:
True

Let's double-check that the capture device is open:

In [8]:
capture.isOpened()
Out[8]:
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.

In [9]:
grabbed, frame = capture.read()
print('Frame grabbed: {0}'.format(grabbed))
Frame grabbed: True

Viewing the result

The grabbed frame should be a colour image. Let's look at it's shape:

In [10]:
# The 'shape' of the frame is a 3-tuple giving the number of rows, columns and colour components
frame.shape
Out[10]:
(480, 640, 3)

We can use OpenCV to convert the colour image to a greyscale:

In [11]:
# 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:

In [12]:
imshow(frame_grey, cmap=cm.gray)
Out[12]:
<matplotlib.image.AxesImage at 0x33f3f90>

Beautiful!

Changing resolution

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.)

In [13]:
import cv
In [14]:
capture.set(cv.CV_CAP_PROP_FRAME_WIDTH, 1280)
capture.set(cv.CV_CAP_PROP_FRAME_HEIGHT, 720)
Out[14]:
False

We can now grab the frame just as before:

In [15]:
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

Dealing with BGR images

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:

In [16]:
imshow(frame)
Out[16]:
<matplotlib.image.AxesImage at 0x5dc38d0>

But we can re-order the third dimension by simply specifying the correct indices:

In [17]:
imshow(frame[:,:,(2,1,0)])
Out[17]:
<matplotlib.image.AxesImage at 0x3546b90>