Захват видео с двух камер в OpenCV сразу

как вы снимаете видео с двух или более камер одновременно (или почти) с помощью OpenCV, используя API Python?

у меня есть три веб-камеры, все способные к потоковой передаче видео, расположенные в /dev/video0, /dev/video1 и /dev/video2.

С помощью учебник в качестве примера, Захват изображений с одной камеры просто:

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

и это прекрасно работает.

однако, если я попытаюсь инициализировать вторую камеру, пытаясь read() из него возвращается 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?!

просто чтобы убедиться, что я случайно не дал OpenCV плохой индекс камеры, я проверил каждый индекс камеры индивидуально, и все они работают сами по себе. например,

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?!

что я делаю не так?

Edit: мое оборудование-это Macbook Pro под управлением Ubuntu. Исследуя проблему конкретно на Macbooks, я нашел другие, которые тоже столкнулись с этой проблемой, как на OSX, так и с различными типами камер. Если я получу доступ к iSight, оба вызовы в моем коде терпят неудачу.

4 ответов


Да, вы определенно ограничены полосой пропускания USB. При попытке чтения с обоих устройств в full-rez вы, вероятно, получили ошибку:

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

а затем, когда вы уменьшите res до 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?!

теперь, кажется, работает! Держу пари, у вас обе камеры подключены к одной USB-карте. Вы можете запустить lsusb команда, чтобы убедиться, и она должна указывать что-то вроде:

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

(обратите внимание на обе камеры на одной шине.) Если возможно, вы можете добавить другую карту USB к вашей машине, чтобы получить больше пропускной способности. Я делал это раньше, чтобы запустить несколько камер с полным разрешением на одной машине. Хотя это была рабочая станция tower с доступными слотами для материнской платы, и, к сожалению, у вас может не быть этой опции на ноутбуке MacBook.


используя OPENCV и две стандартные USB-камеры, я смог сделать это с помощью многопоточности. По сути, определите одну функцию, которая открывает окно opencv и элемент VideoCapture. Затем создайте два потока с идентификатором камеры и именем окна в качестве входных данных.

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()

отличный ресурс для обучения потоку в python:https://www.tutorialspoint.com/python/python_multithreading.htm


Я использую "imutils"и читаю веб-камеру на изображении.

импорт imutils

захват vedio кадров

--- WebCam1

cap = cv2.Захватить видео(0) крышка.набор(cv2.CAP_PROP_FRAME_WIDTH, 300) крышка.набор(cv2.CAP_PROP_FRAME_HEIGHT, 300)

--- WebCam2

cap1 = cv2.Захватить видео(1) cap1.набор(cv2.CAP_PROP_FRAME_WIDTH, 300) cap1.набор(cv2.CAP_PROP_FRAME_HEIGHT, 300)

--- WebCam3

cap2 = cv2.Захватить видео(2) cap2.набор(cv2.CAP_PROP_FRAME_WIDTH, 300) cap2.набор(cv2.CAP_PROP_FRAME_HEIGHT, 300)

--- WebCame4

cap3 = cv2.Захватить видео(3) cap3.набор(cv2.CAP_PROP_FRAME_WIDTH, 300) cap3.набор(cv2.CAP_PROP_FRAME_HEIGHT, 300)

Я создаю функцию read_frame () отправить параметр об изображении.fromarray и дисплей

def read_frame(): webCameShow (cap.читать(),display1) webCameShow (cap1.читать(),монитор display2) webCameShow (cap2.читать(),display6) webCameShow (cap3.read (), display7)
окно.после(10, read_frame)

и финальная функция показать видео на "imageFrame"

def webCameShow(N, дисплей): _ , frameXX = N cv2imageXX = cv2.cvtColor (frameXX, cv2.COLOR_BGR2RGBA) imgXX = изображение.fromarray (cv2imageXX) #imgtkXX = ImageTk.Фотоизображение (image=imgXX) Дисплей.imgtk = imgtkXX Дисплей.настройка (image=imgtkXX)

пример. 4-веб-камера

на YouTube: на YouTube


Это было болью для меня в течение длительного времени, поэтому я сделал библиотеку поверх OpenCV для обработки нескольких камер и иллюминаторов. Я столкнулся с кучей проблем, таких как видео, не сжимающиеся по умолчанию, или окна, отображаемые только в основном потоке. До сих пор я могу отображать две веб-камеры 720p в режиме реального времени на Windows.

попробуй:

pip install CVPubSubs

затем, в python:

import cvpubsubs.webcam_pub as w
from cvpubsubs.window_sub import SubscriberWindows

t1 = w.VideoHandlerThread(0)
t2 = w.VideoHandlerThread(1)

t1.start()
t2.start()

SubscriberWindows(window_names=['cammy', 'cammy2'],
              video_sources=[0,1]
              ).loop()

t1.join()
t1.join()

это относительно новое, поэтому расскажите мне о любых ошибках или неоптимизированном коде.