23

I have two webcams attached to my laptop (one built in), both of which work. (If I use Cheese, a webcam thingy that comes with Ubuntu, it uses the external one). If I use

cap = cv.CreateCameraCapture(0)

or

cap = cv.CreateCameraCapture(-1)

I get my built in webcam. If I use

cap = cv.CreateCameraCapture(1)

It doesn't work and the object `cap' displays as:

<Capture (nil)>

Same with CaptureFromCAM. So I'd like to know what openCV is trying to do and why it doesn't seem to know about the second camera. There should be two devices available (there are /dev/videoN entries for both).

Lucas
  • 1,869
  • 4
  • 20
  • 36
  • 1
    The output from `strace` might be very helpful in determining what system input OpenCV is considering. – Brian Cain Nov 08 '11 at 03:17
  • related: https://stackoverflow.com/questions/58962748/opencv-with-multiple-webcams-how-to-tell-which-camera-is-which-in-code – David Cary Sep 15 '20 at 20:13

7 Answers7

36

I have been able to work around this problem by iterating over the webcam indexes until reading that camera no longer returns anything:

index = 0
arr = []
while True:
    cap = cv2.VideoCapture(index)
    if not cap.read()[0]:
        break
    else:
        arr.append(index)
    cap.release()
    index += 1
return arr

This method returns a list of all indexes that return something when read; I'm sure it can be improved upon, but there are hardly ever more than a few webcams and this runs pretty quickly.

Patrick Yeadon
  • 361
  • 1
  • 3
  • 3
  • 7
    Someone should update this question's answer to this one. No reason why a basic design pattern can't be used to find attached or available devices – Mark Carpenter Jr Jan 01 '20 at 19:38
24

Great answer by @Patrick, but I'd like to improve on it and can't comment yet.

I think Patricks setup assumes that the cameras do not have empty indexes in between them. But in my case, my built-in camera was at index 0, and USB webcam was at index 2. So "if not cap.read()[0]" broke out of the while loop at index 1, never catching the others. We have to specify how many indexes we're willing to go over and check, and just not add the ones that are null.

def returnCameraIndexes():
    # checks the first 10 indexes.
    index = 0
    arr = []
    i = 10
    while i > 0:
        cap = cv2.VideoCapture(index)
        if cap.read()[0]:
            arr.append(index)
            cap.release()
        index += 1
        i -= 1
    return arr

This successfully gave me the indexes I need. Again, thanks to Patrick for the layout!

pydrink
  • 341
  • 2
  • 3
  • thanks @pydrink, and I needed also to skip the 0-index since it's the built-in and I just needed the "extra" ones :) – alcor Jun 26 '20 at 17:09
  • 1
    @alcor I'm too lazy to confirm it as I'm not involved with using OpenCV right now, but I seem to remember experiencing that the built-in camera wasn't necessarily always at index 0, in between running my code where I might have had the USB camera unplugged and plugged in again, possibly using a different USB port :-) – pydrink Nov 08 '21 at 19:38
14

This is a general problem of the OpenCV, as you can see below. It seems that only the builtin, or the first USB cam (only if you do not have a buildin cam) works in OpenCV:

How to use a camera with OpenCV

Cannot access usb webcam through OpenCV, Cygwin

OpenCV capture from USB not iSight (OSX)

Currently, there is no way to extract the number of cameras, as listed in this feature request:

https://code.ros.org/trac/opencv/ticket/935

Community
  • 1
  • 1
Sam
  • 19,708
  • 4
  • 59
  • 82
  • What if you used the "try" and "except" functions to sorta "count" how many cameras it can open without an error? – Edgecase Dec 24 '18 at 18:00
1

It is possible to create a list of cameras without using cap.read().

import cv2

index = 0
arr = []
while True:
    cap = cv2.VideoCapture(index)
    try:
        if cap.getBackendName()=="MSMF":
            arr.append(index)
    except:
        break
    cap.release()
    index += 1

print(arr)
Saido
  • 11
  • 1
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 04 '22 at 22:12
  • This works when `arr.append(index)` is outside the if-block. – Francis Laclé Apr 05 '22 at 12:08
0

For windows, you can build a .pyd extension. https://github.com/yushulx/python-capture-device-list

There isn't an easy crossplatform way yet; ideally someone collates a solution for each OS and then builds them into .pyd.

aong152
  • 143
  • 2
  • 6
-1

I believe that under Linux the valid indices for video inputs are the numbers of the videoN devices in the /dev directory. Hence the following will give a list of valid indices:

import os
devs = os.listdir('/dev')
vid_indices = [int(dev[-1]) for dev in devs 
               if dev.startswith('video')]
vid_indices = sorted(vid_indices)
vid_indices
  • Be sure to check out this askubuntu question if using the above solution: https://askubuntu.com/questions/1123601/four-dev-video-entries-but-just-one-camera It seems that two devices are often listed in /dev for each video device, one for capture, one for metadata. – pydrink Oct 12 '20 at 12:14
-9

I think you should try this:

import cv2

cap = cv2.VideoCapture(1)

while True:
    _, frame = cap.read()
    cv2.imshow('frame', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
Drise
  • 4,310
  • 5
  • 41
  • 66
N.S
  • 1,363
  • 15
  • 18