Pulling full resolution from a webcam with OpenCV (Windows)

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

Comments ( 12 )

  1. Rob
    I had been using code similar to your top example (with Python 3.9.0 and Opencv 4.5.1 on Windows 8.1) which worked fine with the built-in 640x480 webcam on my laptop. But it wouldn't work with a HD USB camera. I used your code, and now it works fine - many thanks! Two strange things - first the parameter for VideoCapture is still "0" - the same as I was using for the webcam in the original code. Usually, you use "1" or "2" for additional cameras. Secondly, running the new code mostly accesses the USB HD camera - but just occasionally it accesses the *original* webcam, even though there has been no change in the code.
    • saulius
      Hi Rob, glad it was useful! Maybe cameras enumerate randomly? Also cap_dshow.cpp in opencv code (windows camera capture part) is ancient and requires total rewrite.
  2. kcwcc
    This seems to be highly camera dependant. It worked GREAT for my internal webcam, but not for my external webcams. Might be something to do with openCV, hardware, win10...who knows? Internal webcam (720p, 30FPS) Method 1: Not DIRECT SHOW Method 2: Direct show with FPS 6.12 seconds to access and set up camera 2.53 seconds to access and set up camera 1280 x 720 resolution 1280 x 720 resolution FPS:26 FPS:29 Logitech C920 (1080p, 30FPS) Method 1: Not DIRECT SHOW Method 2: Direct show with FPS 80.50 seconds to access and set up camera 1.58 seconds to access and set up camera 1920 x 1080 resolution 1920 x 1080 resolution FPS:25 FPS:14 Method 1: Not DIRECT SHOW Method 2: Direct show with FPS 81.95 seconds to access and set up camera 1.55 seconds to access and set up camera 1280 x 720 resolution 1280 x 720 resolution FPS:26 FPS:14 Logitech C270 (720p, 30FPS (doubt that)) Method 1: Not DIRECT SHOW Method 2: Direct show with FPS 0.28 seconds to access and set up camera 1.18 seconds to access and set up camera 1280 x 720 resolution 1280 x 720 resolution FPS:18 FPS:12 Cheap Chinese (1080p, 30FPS) Method 1: Not DIRECT SHOW Method 2: Direct show with FPS 51.26 seconds to access and set up camera 2.30 seconds to access and set up camera 1920 x 1080 resolution 1920 x 1080 resolution FPS:26 FPS:19 Method 1: Not DIRECT SHOW Method 2: Direct show with FPS 51.97 seconds to access and set up camera 2.28 seconds to access and set up camera 1280 x 720 resolution 1280 x 720 resolution FPS:26 FPS:19 It's pretty annoying actually. Thanks for posting though!
  3. kcwcc
    Damn. It reformatted my comment. Sorry about that
    • saulius
      It's me who should apologize. Looks like WP does not like formatted text in comments.
  4. kcwcc
    This appears to be very camera dependent. Worked great for my internal webcam but not for external webcams. No idea why but frame rate takes a BIG hit. Tried 4 cameras and different results for all of them at both 1080p and 720p.
    • saulius
      Unfortunately you are correct. OpenCV Camera capture backend has many underlying implementations. Camera capture code in Windows screams for complete rewrite.
  5. bnguyen
    THANK YOU! On my Windows machine, python3.6 and cv2 4.5.4., using CAP_MSMF sort of work but take 2 minutes for the video feed to start, and cannot call the webcam config tool like CAP_DSHOW when do set(cv2.CAP_PROP_SETTINGS, 1) """ 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')) """ These 3 lines are so ridiculous they might as well be magic incantation. I'm using logitech C920, and this is the only exact way that it would work. Changing the lines order in any way won't work, delete either the lower case or upper case "mjpg" and it won't work. Absolutely insane and I'm curious if you had to dig in the opencv source to figure out this one weird trick.
    • saulius
      Thank you for sharing your insights! Indeed OpenCV camera capture part on Windows is a joke.
    • saulius
      Actually, fixed some nasty bugs for one project but due to lack of time did not commit to main repository - it needs much more time and complete rewrite.
  6. EZA
    My god, I feel like I've gone nuts, but I got it to work! So I followed all the instructions here and on sites like: https://github.com/opencv/opencv/issues/17687 and https://github.com/opencv/opencv/issues/12822 My main problem wasn't just the Resolution - but that the camera would take forever to turn on (30-60sec), and would come out blank/black. Went down an endless rabbit hole, but the solution (!?) was so stupid, I still can't figure it out completely. Details: I have an old Logitech C615 plugged into a laptop with a built-in webcam, and a cheap Chinese webcam (super cheap). Until now, When the Chinese webcam was plugged in, it took device "0" (ie cv2.VideoCapture(0)), and I'm on Windows, so the Backend kept reverting to MSMF at 640x480. The built-in took device "1" (any other webcam took 2,3, etc). Oddly, the cheap Chinese ones worked just fine, and I could adjust the resolution (they're 1080p, but I can't get more than 1280x720), and would always turn on immediately. Obviously the CAP_MSMF was the problem, so I did CAP_DSHOW like everyone recommended. It opened the camera window quickly (ie. cv2.imshow, sometimes), but would show a black screen or get jammed. [Windows would say "Camera On" in a popup, but the blue light on the Logitech wouldn't go on]. Long story short - for some odd reason, when I plug a Logitech Webcam into my laptop, it automatically re-shuffles the camera order. SOOOOO, changing the cv2.VideoCapture(1, cv2.CAP_DSHOW) worked, and turned on the Logitech camera! I have no idea what's going on. I'm assuming that the Direct Show and Logitech have some sort of strange handshake capabilities to tell it to be #1 instead.
    • saulius
      Looks so trivial, but I know how it feels to be stuck.

Leave a reply

Your email address will not be published.