CVCamShot
The cvcamshot Python module provides the CVCamShot class for simple access to snapshots from a webcam. Whenever you call CVCamShot.get() you get the most recent image from the webcam. Details on the Why? and How? are given below.
Download
The module is available as plain Python source file:
Installers like pip and conda are not supported by the author. Simply put it into your working directory and import it with import cvcamshot.
Requirements
Only OpenCV’s cv2 package is required. See OpenCV install instructions.
Usage
First create a CVCamShot object. Then call its get method whenever you want to have a snapshot. Stop and release the camera by calling the stop method.
Camera device is specified by an integer argument to the CVCamShot constructor, which passes the integer directly to OpenCV’s VideoCapture constructor. See documentation of VideoCapture for details.
Minimal example
from cvcamshot import CVCamShot
# start stream from cam
shot = CVCamShot(device=2, width=640, height=480)
# take snapshot
img = shot.get()
# stop stream
shot.stop()
print(img.shape)
# output: (640, 480, 3)
Non-minimal example
from cvcamshot import CVCamShot
import matplotlib.pyplot as plt
import time
# start stream from cam (device is OpenCV cam ID)
shot = CVCamShot(device=2, width=640, height=480)
print('taking 3 snapshots')
imgs = []
for i in range(3):
print('next snapshot in 1 second...')
time.sleep(1)
# take snapshot
imgs.append(shot.get())
# stop stream
shot.stop()
fig, axs = plt.subplots(1, 3)
axs[0].imshow(imgs[0])
axs[1].imshow(imgs[1])
axs[2].imshow(imgs[2])
plt.show()
Don’t use OpenCV’s VideoCapture directly!
OpenCV provides VideoCapture.read(), which yields an image from a webcam. The problem is, that it does not yield the cam’s current view of the world, but the next frame not read before. If the webcam produces images at a rate of 25 frames per second and your program requests only 5 snapshots per second, then you will get outdated frames; the more outdated the longer your program is running.
A typical application is live video stream transform (say, marking all faces via some machine learning model). Processing one frame may require more time than the cam needs for recording the next frame. Using OpenCV directly your transformed video stream will show the cam’s recording in slow motion. Instead, we would like to have a live stream, that is, we have to drop all frames we cannot process in time.
What CVCamShot does
CVCamShot creates a separate thread (via operating system, not Python’s asynio API) which runs in parallel to your program. The separate thread reads frames from the webcam as soons as they are available. CVCamShot.get() returns the most recent frame captured by the thread. Thus, frames are read from the cam all the time, even if your program does some heavy calculations. Frames read between two get calls are dropped.
A straight-forward implementation would store each frame coming from the cam. The next frame overwrites the previous one. A call to getthen simply returns the stored frame. Such an implementation would require lots of CPU time, because 20 to 30 images would have to be decoded from the webcam’s data stream (using VideoCapture.read()). CVCamShot avoids this overhead (decode frames, then drop them). A call to get tells the capture thread that we need an image. The capture thread waits for the next frame from the cam, decodes the frame and returns the image. If there is no call to get waiting for an image, frames aren’t decoded, just grabbed via VideoCapture.grab().