pythonopencvwebcamvideo-captureuvc

USB Camera: OpenCV VideoCapture Returns Partial Frames


I am developing a program to process frames from a USB camera on Ubuntu. Currently I'm using OpenCV in python. When I try to read a frame using a cv2.VideoCapture object I only get partial frames.

The camera I'm using is a Kayeton GS1M2812 USB camera, which claims to be UVC compliant. Most applications (like cheese, for instance) list the camera among available webcams, but don't display any frames. Google Hangouts, on the other hand, can display live frames from the camera without a problem.

I can also successfully capture images and video using streamer. e.g.:

streamer -c /dev/video1 -o capture.jpg

Initially when I tried to use cv.VideoCapture, I got select timeouts and no images. After some research I found that restarting the uvcvideo module with nodrop=1 allowed me to at least get partial frames from opencv (like the one linked above).

I tried setting the uvcvideo timeout param to a ridiculously large value and messed with all the other params and various quirks, but to no avail.

I did find that changing the resolution (cv.CAP_PROP_FRAME_WIDTH and cv.CAP_PROP_FRAME_HEIGHT) to 320x240 or smaller before each call to read() results in capturing a full frame, but anything larger doesn't.

I've also tried changing various parameters with v4l2-ctl, but that hasn't worked either.

What can I do to fix this?

Here is my python code:

import cv2 as cv
import numpy as np
import sys

if len(sys.argv) != 2:
    print("invalid arguments")
    sys.exit()

camNo = int(sys.argv[1])
print("opening camera %d" % camNo)

cap = cv.VideoCapture(camNo)

print("done")

while True:
    cap.set(cv.CAP_PROP_FRAME_WIDTH,640);
    cap.set(cv.CAP_PROP_FRAME_HEIGHT,480);
    ret, frame = cap.read()
    print(ret)

    if(frame is None):
        print("Received empty frame. Exiting")
        sys.exit()

    cv.imshow('frame', frame)
    if cv.waitKey(30) & 0xFF == ord('q'):
        break

cap.release()
cv.destroyAllWindows()

This code works correctly when I use my laptop's builtin webcam (usually /dev/video0), but displays partial frames when I use the USB camera.

I am using python 2.7.12 and opencv 3.3.1 on Ubuntu 16.04


Solution

  • Probably by default opencv is requesting uncompressed images from your webcam. That's why when you reduce the resolution or FPS you get a full image otherwise the bandwidth is insufficient for the whole image.

    You can try setting the codec cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG')).