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
Answer from TheoreticallyNick on Stack OverflowUsing 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
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.
[Question] Opening many cameras at once
Grabbing with multiple cameras and opencv
Unable to take pictures with multiple cameras - Python - OpenCV
pi 3b+ - reading two webcams in opencv - Raspberry Pi Stack Exchange
THE PROBLEM
Hello all. I am using opencv in Python to capture still images from many cameras at once. Unfortunately I have found that the cheap 2MP USB cameras that I am using allocate an amount of bandwidth from the USB controller that assumes I'll be operating them at 30fps, which means that I can only open 1 or 2 at a time. The frame rate appears to be not controllable with these cameras from within opencv, nor from v4l in the linux command line where a frame rate property is not listed when I run $v4l2-ctl -d 0 --list-ctrls. Otherwise I was hoping I could simply set frame rate to 0fps, allowing me to open as many cameras as I want and capture from them as needed (assuming that's how it works). However it appears that I cannot open all of the cameras at the same time, which is unfortunate because opencv VideoCapture objects apparently have this handy grab-retrive paradigm that I can't make use of. Instead what I am doing is opening each camera, reading image, then closing... It takes a long time and is totally unnecessary from a hardware point of view, since I only want to grab single frames from each camera. From the USB controller's perspective, I don't have enough bandwidth.
Now I have bought a 5MP camera that I thought might have more options. Indeed it appears I can capture 2MP images from this camera at 6fps, so it seems I would be able to open more cameras at a time in Python. I'll have to buy a few more and try.
v4l from within Python?
Not really related to opencv I guess, but in v4l I noticed there are lots of commands that I haven't explored yet, and I can run them from within my Python script. Might there be a way to open a camera at 0fps, or is this something that will ultimately be prohibited by the hardware of the camera no matter which way I try to go about it?
Better camera?
What am I doing wrong? How is this typically done? Should I explore different connection methods (firewire, USB3, etc)? Is there a special type of camera that is made for such applications that require grabbing single HD frame at low rate?
Thank you for any advice or insight that you can provide!
I have 20 IP cameras (rtsp://192.168.1.101:554/12 - rtsp://192.168.1.120:554/12) and I need to be able to grab images from all 20 cameras at the same time (or as fast as possible). I imagine I need to start the cv2.VideoCapture for easy rtsp feed first, but then how should I go about capturing an image (cv2.imwrite(dest,im) for each the fastest.
I know I am supposed to use grab and retrieve (I think), but I can't seem to find the right syntax.
Can I load multiple VideoCaptures at the same time or does the second one overwrite the second one? I was thinking I could do:
vcap101=cv2.VideoCapture(dev1) vcap102=cv2.VideoCapture(dev2)
Note: When I start the VCaps for all the cameras the images I can pull cv2.imwrite() from there are all 6-7 seconds apart.
