Pulling full resolution from a webcam with OpenCV (Windows)

0 Comments

OpenCV while being the most popular tool for a lot of machine vision applications it relies on a third party and some poorly maintained code. Capturing MJPEG compressed video from a UVC USB camera was always the case and it did not work or worked with some issues. This situation is especially bad for Windows OS.

Currently Python 3.8.4 pip has these versions of OpenCV available to be installed directly: 3.4.8.29, 3.4.9.31, 3.4.9.33, 3.4.10.35, 4.1.2.30, 4.2.0.32, 4.2.0.34, 4.3.0.36

Each version can be installed (and replaced) with ease by typing so it’s fairly easy to test versions that are in pip package manager repository:

pip install opencv-python==4.3.0.36

Classic / minimalistic way to capture images is like this:

import cv2

camera = cv2.VideoCapture(0)

while (1):
    retval, im = camera.read()
    cv2.imshow("image", im)

    k = cv2.waitKey(1) & 0xff
    if k == 27:
        break

camera.release()
cv2.destroyAllWindows()

Unfortunately, sometimes it needs some more parameters to actually capture MJPEG stream. For older OpenCV (last tested 3.4.2.x) versions there was a solution to add cv2.CAP_PROP_FOURCC property set and the whole code to have 1920×1080 at 30fps stream looked like this:

import cv2

camera = cv2.VideoCapture(0)

codec = 0x47504A4D  # MJPG
camera.set(cv2.CAP_PROP_FPS, 30.0)
camera.set(cv2.CAP_PROP_FOURCC, codec)
camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)

while (1):
    retval, im = camera.read(0)
    cv2.imshow("image", im)

    k = cv2.waitKey(1) & 0xff
    if k == 27:
        break

camera.release()
cv2.destroyAllWindows()

Once the last OpenCV version available in the pip repository was updated and this workaround stopped working. Since 3.4.10.35 OpenCV version was rolled out it stopped working at all and frames could not be captured anymore. One more property had to be added cv2.CAP_DSHOW so now code looks like this:

import cv2

camera = cv2.VideoCapture(0, cv2.CAP_DSHOW)

codec = 0x47504A4D  # MJPG
camera.set(cv2.CAP_PROP_FPS, 30.0)
camera.set(cv2.CAP_PROP_FOURCC, codec)
camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)

while (1):
    retval, im = camera.read()
    cv2.imshow("image", im)

    k = cv2.waitKey(1) & 0xff
    if k == 27:
        break

camera.release()
cv2.destroyAllWindows()

One problem remains. Frames are not being captured at 30 frames per second rate. So one more fix and we have 1080p@30fps with MJPEG compression stream in our code.

import cv2

camera = cv2.VideoCapture(0, cv2.CAP_DSHOW)

camera.set(cv2.CAP_PROP_FPS, 30.0)
camera.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc('m','j','p','g'))
camera.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc('M','J','P','G'))
camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)

while (1):
    retval, im = camera.read()
    cv2.imshow("image", im)

    k = cv2.waitKey(1) & 0xff
    if k == 27:
        break

camera.release()
cv2.destroyAllWindows()

This solution may not work for all operating systems, versions, and cameras. Most intense tests were performed with C1 family cameras.

Leave a reply

Your email address will not be published.