Nuestros mejores programadores han agotado sus provisiones de café, en su búsqueda a tiempo completo por la solución, hasta que Gloria encontró la respuesta en Beanstalk por lo tanto en este momento la comparte con nosotros.
Solución:
Sí, definitivamente estás limitado por el ancho de banda USB. Intentando leer desde ambos dispositivos a full-rez probablemente obtuviste un 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
assert ret1 # fails?!
AssertionError
Y luego, cuando reduce la resolución a 160×120:
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?!
ahora parece funcionar! Apuesto a que tienes ambas cámaras conectadas en la misma tarjeta USB. Tu puedes correr lsusb
comando para asegurarse, y debería indicar algo como:
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
(Tenga en cuenta que ambas cámaras están en el mismo bus). Si es posible, puede agregar otra tarjeta USB a su máquina para ganar más ancho de banda. He hecho esto antes para ejecutar múltiples cámaras a resolución completa en una sola máquina. Aunque esa era una estación de trabajo de torre con ranuras para placa base disponibles, y desafortunadamente es posible que no tenga esa opción en una computadora portátil MacBook.
Usando OPENCV y dos cámaras USB estándar, pude hacer esto usando subprocesos múltiples. Esencialmente, defina una función que abra una ventana opencv y un elemento VideoCapture. Luego, cree dos subprocesos con la identificación de la cámara y el nombre de la ventana como entradas.
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()
Gran recurso para aprender a enhebrar en python: https://www.tutorialspoint.com/python/python_multithreading.htm
Agregando un poco a lo que @TheoreticallyNick publicó anteriormente:
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())
Esto abrirá un nuevo hilo para cada cámara web que tenga. En mi caso, quería abrir tres feeds diferentes. Probado en Python 3.6. ¡Avíseme si tiene algún problema, también gracias a TheoreticallyNick por el código legible/funcional!
Recuerda que puedes compartir esta noticia si si solucionó tu problema.