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.
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.
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
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
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!
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 !
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é.