16

I am using OpenCV to open and read from several webcams. It all works fine, but I cannot seem to find a way to know if a camera is available.

I tried this code (cam 2 does not exist):

import cv2
try:
    c = cv2.VideoCapture(2)
except:
    print "Cam 2 is invalid."

But this just prints a lot of errors:

VIDEOIO ERROR: V4L: index 2 is not correct!
failed to open /usr/lib64/dri/hybrid_drv_video.so
Failed to wrapper hybrid_drv_video.so
failed to open /usr/lib64/dri/hybrid_drv_video.so
Failed to wrapper hybrid_drv_video.so
GStreamer Plugin: Embedded video playback halted; module v4l2src0 reported: Internal data stream error.
OpenCV Error: Unspecified error (GStreamer: unable to start pipeline
) in cvCaptureFromCAM_GStreamer, file /builddir/build/BUILD/opencv-3.2.0/modules/videoio/src/cap_gstreamer.cpp, line 832
VIDEOIO(cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L2, reinterpret_cast<char *>(index))): raised OpenCV exception:

/builddir/build/BUILD/opencv-3.2.0/modules/videoio/src/cap_gstreamer.cpp:832: error: (-2) GStreamer: unable to start pipeline
 in function cvCaptureFromCAM_GStreamer

OpenCV Error: Unspecified error (unicap: failed to get info for device
) in CvCapture_Unicap::initDevice, file /builddir/build/BUILD/opencv-3.2.0/modules/videoio/src/cap_unicap.cpp, line 139
VIDEOIO(cvCreateCameraCapture_Unicap(index)): raised OpenCV exception:

/builddir/build/BUILD/opencv-3.2.0/modules/videoio/src/cap_unicap.cpp:139: error: (-2) unicap: failed to get info for device
 in function CvCapture_Unicap::initDevice

CvCapture_OpenNI::CvCapture_OpenNI : Failed to enumerate production trees: Can't create any node of the requested type!
<VideoCapture 0x7fa5b5de0450>

No exception is thrown. When using c.read() later, I do get False, but I would like to do this in the initialisation phase of my program.

So, how do I find out how many valid cameras I have or check if a certain number 'maps' to a valid one?

8
  • "no exception is thrown": yes, because you caught them all unhandled. Always only catch the exceptions you're willing to handle. Commented Jan 1, 2018 at 13:06
  • @AndrasDeak the print "Cam 2 is invalid" is never shown. Commented Jan 1, 2018 at 13:13
  • 2
    Ah, that makes it a bit more interesting (but I stand by my earlier statement). So...what kind of errors does it print? Please read minimal reproducible example and How to Ask :P Commented Jan 1, 2018 at 13:16
  • @AndrasDeak adding import cv2 was all that was needed to make this MCV. I added the errors as well. Commented Jan 1, 2018 at 13:32
  • Úsing cv2.VideoCapture( invalid device number ) does not throw exceptions. It constructs a <VideoCapture object> containing an invalid device - if you use it you get exceptions. Test the constructed object for None and not IsOpen() to weed out invalid ones. See answer for code example. Commented Jan 1, 2018 at 13:37

4 Answers 4

21

Using cv2.VideoCapture( invalid device number ) does not throw exceptions. It constructs a <VideoCapture object> containing an invalid device - if you use it you get exceptions.

Test the constructed object for None and not isOpened() to weed out invalid ones.


For me this works (1 laptop camera device):

import cv2 as cv 

def testDevice(source):
   cap = cv.VideoCapture(source) 
   if cap is None or not cap.isOpened():
       print('Warning: unable to open video source: ', source)

testDevice(0) # no printout
testDevice(1) # prints message

Output with 1:

Warning: unable to open video source:  1

Example from: https://github.com/opencv/opencv_contrib/blob/master/samples/python2/video.py lines 159ff

cap = cv.VideoCapture(source)
    if 'size' in params:
        w, h = map(int, params['size'].split('x'))
        cap.set(cv.CAP_PROP_FRAME_WIDTH, w)
        cap.set(cv.CAP_PROP_FRAME_HEIGHT, h)
if cap is None or not cap.isOpened():
    print 'Warning: unable to open video source: ', source
5
  • 1
    "Non-existent device" is at the core of this question: how to tell if a device at a given source ID is not available. Commented Jan 1, 2018 at 13:18
  • 1
    @AndrasDeak had to install opencv first to test it - for me it works - no crash Commented Jan 1, 2018 at 13:32
  • The example from opencv_contrib does not check if cv2.VideoCapture() returns None—it checks whether classes.get(params.get('class', None), VideoSynthBase) is None. See the whole thing: github.com/opencv/opencv_contrib/blob/…
    – gsc
    Commented Jun 4, 2019 at 8:37
  • The proposed solution does not work for Point Grey (FLIR) cameras. Neither does my cam.Init() idea posted here.
    – ZF007
    Commented Jun 7, 2019 at 14:58
  • 1
    I have found in practice that cv::VideoCapture() does throw exceptions under some circumstances (OpenCV 3.1.0 because upgrading is hard). Beware.
    – Thomas
    Commented Jul 6, 2020 at 10:01
8

Another solution, which is available in Linux is to use the /dev/videoX device in the VideoCapture() call. The devices are there when the cam is plugged in. Together with glob(), it is trivial to get all the cameras:

import cv2, glob

for camera in glob.glob("/dev/video?"):
    c = cv2.VideoCapture(camera)

Of course a check is needed on c using isOpened(), but you are sure you only scan the available cameras.

1

Here is a "NOT working" solution to help you prevent tumbling over in this pitfall:

import cv2 as cv
import PySpin

print (cv.__version__)

# provided by Patrick Artner as solution to be working for other cameras than
#                                                  those of Point Grey (FLIR).

def testDevice(source):
   cap = cv.VideoCapture(source) 
   if cap is None or not cap.isOpened():
       print('Warning: unable to open video source: ', source)

# ... PySpin / Spinnaker (wrapper/SDK libary) ...

system   = PySpin.System.GetInstance()
cam_list = system.GetCameras()

cam = ''
cam_num = 0

for ID, cam in enumerate(cam_list):
    # Retrieve TL device nodemap
    if ID == cam_num:
        print ('Got cam')
        cam = cam

        cam.Init()

        # ... CV2 again ...

        for i in range(10):
            testDevice(i) # no printout
6
  • what is so special on Point Grey FLIR cameras? Commented Jun 7, 2019 at 15:09
  • also I am cofused - does this solution work for this kind of cameras (using PySpin wrapper?) Is this kind of camera useable with cv2 at all? Commented Jun 7, 2019 at 15:11
  • I don't know yet and trying to figure this out as we speak. I've migrated from PyCapture2 to PySpin but lost functions like cameraPowerON/OFF and a few more. There is a isValid() test I describe in another Q/A session that does more or less the trick (read: patchwork) but read/writeRegister functions are a lost case here. As far as I can see now they make use of the GENiCAM structured naming/framework and thus work with nodes and active camera instance (as seen in the code provided). Actually, I was kind of flabbergasted CV2 couldn't get its fingers behind the door in the camera.
    – ZF007
    Commented Jun 7, 2019 at 15:22
  • Maybe you should create your own question then - this does not seem to be an answer to the original post. If you come to some answer, you probably could post a question/selfanswer to the likes of how to detect amount of Pint Grey FLIR cameras ... they seem to have their own kind of API: flir.com/iis/machine-vision Commented Jun 7, 2019 at 15:25
  • 1
    Imaging what happens if we collect all "NOT working" ways to do things as answers to questions on SO ... your cam = cam does nothing by the way - it will be overwritten by the next value in your loop for ID, cam in enumerate(cam_list): and only ever have the last camera object in it - not all. you mean well, but I guess this might get dv -you'll see. Commented Jun 7, 2019 at 15:33
0

You can try this code:

from __future__ import print_function
import numpy as np
import cv2

# detect all connected webcams
valid_cams = []
for i in range(8):
    cap = cv2.VideoCapture(i)
    if cap is None or not cap.isOpened():
        print('Warning: unable to open video source: ', i)
    else:
        valid_cams.append(i)

caps = []
for webcam in valid_cams:
    caps.append(cv2.VideoCapture(webcam))

while True:
    # Capture frame-by-frame
    for webcam in valid_cams:
        ret, frame = caps[webcam].read()
        # Display the resulting frame
        cv2.imshow('webcam'+str(webcam), frame)
    k = cv2.waitKey(1)
    if k == ord('q') or k == 27:
        break

# When everything done, release the capture
for cap in caps:
    cap.release()

cv2.destroyAllWindows()

Not the answer you're looking for? Browse other questions tagged or ask your own question.