Reading from two cameras in OpenCV at once

How do you capture video from two or more cameras at once (or nearly) with OpenCV, using the Python API?

I have three webcams, all capable of video streaming, located at /dev/video0, /dev/video1, and /dev/video2.

Using the tutorial as an example, capturing images from a single camera is simply:

import cv2
cap0 = cv2.VideoCapture(0)
ret0, frame0 = cap0.read()
cv2.imshow('frame', frame0)
cv2.waitKey()

And this works fine.

However, if I try to initialize a second camera, attempting to read() from it returns None:

import cv2
cap0 = cv2.VideoCapture(0)
cap1 = cv2.VideoCapture(1)
ret0, frame0 = cap0.read()
assert ret0 # succeeds
ret1, frame1 = cap1.read()
assert ret1 # fails?!

Just to ensure I wasn't accidentally giving OpenCV a bad camera index, I tested each camera index individually and they all work by themselves. eg

import cv2
#cap0 = cv2.VideoCapture(0)
cap1 = cv2.VideoCapture(1)
#ret0, frame0 = cap0.read()
#assert ret0
ret1, frame1 = cap1.read()
assert ret1 # now it works?!

What am I doing wrong?

Edit: My hardware is a Macbook Pro running Ubuntu. Researching the issue specifically on Macbooks, I've found others that have run into this problem too, both on OSX and with different types of cameras. If I access the iSight, both calls in my code fail.


Yes you're definitely limited by the USB bandwidth. Attempting to read from both devices at full-rez you probably got error:

libv4l2: error turning on stream: No space left on device
VIDIOC_STREAMON: No space left on device
Traceback (most recent call last):
  File "p.py", line 7, in <module>
    assert ret1 # fails?!
AssertionError

And then when you reduce the res to 160x120:

import cv2
cap0 = cv2.VideoCapture(0)
cap0.set(3,160)
cap0.set(4,120)
cap1 = cv2.VideoCapture(1)
cap1.set(3,160)
cap1.set(4,120)
ret0, frame0 = cap0.read()
assert ret0 # succeeds
ret1, frame1 = cap1.read()
assert ret1 # fails?!

now it seems to work! I bet you have both cams connected on the same USB card. You can run lsusb command to make sure, and it should indicate something like:

Bus 001 Device 006: ID 046d:081b Logitech, Inc. Webcam C310
Bus 001 Device 004: ID 0409:005a NEC Corp. HighSpeed Hub
Bus 001 Device 007: ID 046d:0990 Logitech, Inc. QuickCam Pro 9000
Bus 001 Device 005: ID 0409:005a NEC Corp. HighSpeed Hub
Bus 001 Device 003: ID 0409:005a NEC Corp. HighSpeed Hub
Bus 001 Device 002: ID 1058:0401 Western Digital Technologies, Inc. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub

(Note both cameras on same bus.) If possible, you can add another USB card to your machine to gain more bandwidth. I've done this before in order to run multiple cams at full resolution on a single machine. Albeit that was a tower workstation with available motherboard slots, and unfortunately you may not have that option on a MacBook laptop.


I have use "imutils" and read webcam show on the image.

import imutils

capture vedio frames

--- WebCam1

cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH,300) cap.set(cv2.CAP_PROP_FRAME_HEIGHT,300)

--- WebCam2

cap1 = cv2.VideoCapture(1) cap1.set(cv2.CAP_PROP_FRAME_WIDTH,300) cap1.set(cv2.CAP_PROP_FRAME_HEIGHT,300)

--- WebCam3

cap2 = cv2.VideoCapture(2) cap2.set(cv2.CAP_PROP_FRAME_WIDTH,300) cap2.set(cv2.CAP_PROP_FRAME_HEIGHT,300)

--- WebCame4

cap3 = cv2.VideoCapture(3) cap3.set(cv2.CAP_PROP_FRAME_WIDTH,300) cap3.set(cv2.CAP_PROP_FRAME_HEIGHT,300)

i create function read_frame() send parameter about Image.fromarray and display

def read_frame(): webCameShow(cap.read(),display1) webCameShow(cap1.read(),display2) webCameShow(cap2.read(),display6) webCameShow(cap3.read(),display7)
window.after(10, read_frame)

and final function show video on the "imageFrame"

def webCameShow(N,Display): _, frameXX = N cv2imageXX = cv2.cvtColor(frameXX, cv2.COLOR_BGR2RGBA) imgXX = Image.fromarray(cv2imageXX) #imgtkXX = ImageTk.PhotoImage(image=imgXX) Display.imgtk = imgtkXX Display.configure(image=imgtkXX)

example. 4-webcam

Youtube: Youtube


Using OPENCV and two standard USB cameras, I was able to do this using multithreading. Essentially, define one function which opens an opencv window and VideoCapture element. Then, create two threads with the camera ID and window name as inputs.

import cv2
import threading

class camThread(threading.Thread):
    def __init__(self, previewName, camID):
        threading.Thread.__init__(self)
        self.previewName = previewName
        self.camID = camID
    def run(self):
        print "Starting " + self.previewName
        camPreview(self.previewName, self.camID)

def camPreview(previewName, camID):
    cv2.namedWindow(previewName)
    cam = cv2.VideoCapture(camID)
    if cam.isOpened():  # try to get the first frame
        rval, frame = cam.read()
    else:
        rval = False

    while rval:
        cv2.imshow(previewName, frame)
        rval, frame = cam.read()
        key = cv2.waitKey(20)
        if key == 27:  # exit on ESC
            break
    cv2.destroyWindow(previewName)

# Create two threads as follows
thread1 = camThread("Camera 1", 1)
thread2 = camThread("Camera 2", 2)
thread1.start()
thread2.start()

Great resource for learning how to thread in python: https://www.tutorialspoint.com/python/python_multithreading.htm

链接地址: http://www.djcxy.com/p/83784.html

上一篇: OpenCV VideoCapture无法在OSX上打开相机

下一篇: 立即从OpenCV中的两台摄像机读取数据