web-dev-qa-db-fra.com

Capture vidéo à la fois de deux caméras OpenCV

Comment capturer des vidéos de deux caméras ou plus à la fois (ou presque) avec OpenCV, à l'aide de l'API Python?

J'ai trois webcams, toutes capables de streaming vidéo, situées dans/dev/video0,/dev/video1 et/dev/video2.

En utilisant le didacticiel à titre d’exemple, capturer des images à partir d’un seul appareil photo est tout simplement:

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

Et ça marche bien.

Cependant, si j'essaye d'initialiser une deuxième caméra, essayer de read() à partir de celle-ci retourne 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?!

Juste pour m'assurer que je ne transmettais pas accidentellement à OpenCV un mauvais index de caméra, j'ai testé chaque index de caméra individuellement et ils fonctionnent tous seuls. par exemple.

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

Qu'est-ce que je fais mal?

Edit: Mon matériel est un Macbook Pro sous Ubuntu. En recherchant spécifiquement le problème des Macbooks, j'ai trouvé d'autres personnes qui ont également rencontré ce problème, à la fois sous OSX et avec différents types de caméras. Si j'accède à l'iSight, les deux appels de mon code échouent.

10
Cerin

Oui, vous êtes certainement limité par la bande passante USB. En essayant de lire à partir des deux appareils à la pleine vitesse, vous avez probablement une erreur:

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

Et puis quand vous réduisez la résolution à 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?!

maintenant cela semble fonctionner! Je parie que vous avez les deux cames connectées sur la même carte USB. Vous pouvez exécuter la commande lsusb pour vous en assurer, et cela devrait indiquer quelque chose comme:

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

(Notez que les deux caméras sont sur le même bus.) Si possible, vous pouvez ajouter une autre carte USB à votre appareil pour obtenir plus de bande passante. Je l'ai déjà fait auparavant afin de faire fonctionner plusieurs caméras en pleine résolution sur une seule machine. Même s’il s’agissait d’un poste de travail tour doté de logements pour carte mère, il est malheureusement possible que cette option ne soit pas disponible sur un ordinateur portable MacBook.

5
vmlaker

En utilisant OPENCV et deux caméras USB standard, j'ai pu le faire en multithreading. Pour l’essentiel, définissez une fonction qui ouvre une fenêtre ouverte et un élément VideoCapture. Créez ensuite deux threads avec l’ID de la caméra et le nom de la fenêtre comme entrées. 

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

Excellente ressource pour apprendre à enfiler des scripts python: https://www.tutorialspoint.com/python/python_multithreading.htm

4
TheoreticallyNick

J'ai utilisé "imutils" et lu émission de webcam sur l'image.

importer des imutils

capture vedio cadres 

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

je crée la fonction read_frame () envoyer un paramètre sur Image.fromarray et afficher 

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

et la fonction finale montre la vidéo sur le "imageFrame"

def webCameShow (N, Affichage): _, 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)

exemple . 4-webcam

Youtube: Youtube

frame0 = cv2.VideoCapture(1)
frame1 = cv2.VideoCapture(2)

doit être:

frame0 = cv2.VideoCapture(0)  # index 0
frame1 = cv2.VideoCapture(1)  # index 1

Donc ça coule

0
Gio Lac Cagliari

Ajoutant un peu à ce que @TheoreticalNick a posté plus tôt:

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():
        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 threads as follows
thread1 = camThread("Camera 1", 0)
thread2 = camThread("Camera 2", 1)
thread3 = camThread("Camera 3", 2)

thread1.start()
thread2.start()
thread3.start()
print()
print("Active threads", threading.activeCount())

Cela ouvrira un nouveau fil pour chaque webcam que vous avez. Dans mon cas, je voulais ouvrir trois flux différents. Testé sur Python 3.6. Faites-moi savoir si vous avez des problèmes, également grâce à TheoreticalNick pour le code lisible/fonctionnel!

0
Jacob W. Dallas

essayez d'utiliser ce code ... cela a fonctionné comme prévu ... ceci est pour deux cames, si vous voulez plus de cames, créez simplement les objets "VideoCapture ()" ont: cv2.VideoCapture (3) et le code correspondant dans la boucle while 

import cv2

frame0 = cv2.VideoCapture(1)
frame1 = cv2.VideoCapture(2)
while 1:

   ret0, img0 = frame0.read()
   ret1, img00 = frame1.read()
   img1 = cv2.resize(img0,(360,240))
   img2 = cv2.resize(img00,(360,240))
   if (frame0):
       cv2.imshow('img1',img1)
   if (frame1):
       cv2.imshow('img2',img2)

   k = cv2.waitKey(30) & 0xff
   if k == 27:
      break

frame0.release()
frame1.release()
cv2.destroyAllWindows()

BONNE CHANCE ! 

0
Sajil Vohra

Cela a été une douleur pour moi pendant longtemps, alors j'ai créé une bibliothèque au-dessus d'OpenCV pour gérer plusieurs caméras et fenêtres. J'ai rencontré de nombreux problèmes, tels que des vidéos ne compressant pas par défaut ou des fenêtres ne s'affichant que dans le fil principal. Jusqu'à présent, je suis capable d'afficher deux webcams 720p en temps réel sous Windows. 

Essayer: 

pip install CVPubSubs

Ensuite, en 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()

C'est relativement nouveau, alors parlez-moi de tout bogue ou de tout code non optimisé. 

0
SimLeek