Cer*_*rin 18 python camera opencv
如何使用Python API一次(或几乎)使用OpenCV从两个或多个摄像头捕获视频?
我有三个网络摄像头,都具有视频流功能,位于/ dev/video0,/ dev/video1和/ dev/video2.
以教程为例,从单个摄像头捕获图像就是:
import cv2
cap0 = cv2.VideoCapture(0)
ret0, frame0 = cap0.read()
cv2.imshow('frame', frame0)
cv2.waitKey()
Run Code Online (Sandbox Code Playgroud)
这很好用.
但是,如果我尝试初始化第二个摄像头,尝试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?!
Run Code Online (Sandbox Code Playgroud)
为了确保我不会意外地给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?!
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
编辑:我的硬件是运行Ubuntu的Macbook Pro.在Macbook上专门研究这个问题,我发现其他人也遇到过这个问题,无论是在OSX上还是在不同类型的摄像头上.如果我访问iSight,我的代码中的两个调用都会失败.
是的,你肯定受到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
Run Code Online (Sandbox Code Playgroud)
然后当你将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?!
Run Code Online (Sandbox Code Playgroud)
现在它似乎工作!我打赌你在同一个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
Run Code Online (Sandbox Code Playgroud)
(请注意同一总线上的两台摄像机.)如果可能,您可以在机器上添加另一块USB卡以获得更多带宽.之前我已经完成了这项工作,以便在一台机器上以全分辨率运行多个凸轮.虽然这是一个带有可用主板插槽的塔式工作站,但不幸的是,你可能没有在MacBook笔记本电脑上使用该选项.
使用OPENCV和两个标准USB摄像机,我能够使用多线程来做到这一点。本质上,定义一个打开opencv窗口和VideoCapture元素的函数。然后,创建两个线程,并以摄像机ID和窗口名称作为输入。
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()
Run Code Online (Sandbox Code Playgroud)
学习如何在python中进行线程学习的绝佳资源:https://www.tutorialspoint.com/python/python_multithreading.htm
在@TheoreticalNick 之前发布的内容中添加一点:
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())
Run Code Online (Sandbox Code Playgroud)
这将为您拥有的每个网络摄像头打开一个新线程。就我而言,我想打开三个不同的提要。在 Python 3.6 上测试。如果您有任何问题,请告诉我,还要感谢 TheoreticallyNick 提供可读/可运行的代码!
小智 5
我使用了“imutils”并阅读了图像上的网络摄像头显示。
import imutils
Run Code Online (Sandbox Code Playgroud)
捕捉视频帧
#--- 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)
Run Code Online (Sandbox Code Playgroud)
我创建函数read_frame发送关于 Image.fromarray 的参数并显示
def read_frame():
webCameShow(cap.read(),display1)
webCameShow(cap1.read(),display2)
webCameShow(cap2.read(),display6)
webCameShow(cap3.read(),display7)
window.after(10, read_frame)
Run Code Online (Sandbox Code Playgroud)
和最终功能在“imageFrame”上显示视频
def webCameShow(N,Display):
_, 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)
Run Code Online (Sandbox Code Playgroud)
例子。 4-网络摄像头
优酷:优 酷
有点晚了,但您可以使用我的 VideGear 库的CamGear API,它继承地提供多线程,并且您可以用更少的行数编写相同的代码。另外,从好的方面来说,所有摄像机流都将完全同步。
# import required libraries
from vidgear.gears import VideoGear
import cv2
import time
# define and start the stream on first source ( For e.g #0 index device)
stream1 = VideoGear(source=0, logging=True).start()
# define and start the stream on second source ( For e.g #1 index device)
stream2 = VideoGear(source=1, logging=True).start()
# infinite loop
while True:
frameA = stream1.read()
# read frames from stream1
frameB = stream2.read()
# read frames from stream2
# check if any of two frame is None
if frameA is None or frameB is None:
#if True break the infinite loop
break
# do something with both frameA and frameB here
cv2.imshow("Output Frame1", frameA)
cv2.imshow("Output Frame2", frameB)
# Show output window of stream1 and stream 2 seperately
key = cv2.waitKey(1) & 0xFF
# check for 'q' key-press
if key == ord("q"):
#if 'q' key-pressed break out
break
if key == ord("w"):
#if 'w' key-pressed save both frameA and frameB at same time
cv2.imwrite("Image-1.jpg", frameA)
cv2.imwrite("Image-2.jpg", frameB)
#break #uncomment this line to break out after taking images
cv2.destroyAllWindows()
# close output window
# safely close both video streams
stream1.stop()
stream2.stop()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
34089 次 |
| 最近记录: |