如何将多线程与 cv2.VideoCapture() 一起使用?
How to use multithreading with and cv2.VideoCapture()?
我想显示两个或多个单独的视频,并使用 cv2 应用了轻微的图像处理。
如果我不使用 threading/multiprocessing
会浪费大量时间来显示使用 cv2.waitKey(timeThatCouldBeSpentFetchingAFrameForAnotherVideo)
的帧。
我尝试使用 threading
,但它无法正常工作。我收到此警告:WARNING: nextEventMatchingMask should only be called from the Main Thread! This will throw an exception in the future.
。这通常会导致崩溃。
所以,我决定尝试实现 multiprocessing
,理论上它应该比 threading
处理更复杂的图像更快(对吗??)。 I used this as an example. 但是,在这种情况下,我 运行 进入了另一个问题,这种方法只能让我获得视频的第一帧。另外,我尝试将 cv2.VideoCapture() 放在 Process
之外,但结果是:TypeError: cannot pickle 'cv2.VideoCapture' object
.
这是我的代码:
class CamManager:
def __init__(self):
self.saving = Saving()
self.cams = self.createCamObjList()
self.buffers = [Buffer(cam.FPS*BUFFER_SIZE) for cam in self.cams]
def createCamObjList(self):
l = []
for i, url in enumerate(STREAM_URLS):
saved_data = self.saving.getDataFor(url)
cam = BufferedCamera(url, i, saved_data)
l.append(cam)
return l
def startStreamCapture(self):
queue_for_cams = multiprocessing.Queue()
processes = [multiprocessing.Process(
target=cam.readloop, args=[queue_for_cams]).start() for cam in self.cams]
while True:
if not queue_for_cams.empty():
from_queue = queue_for_cams.get()
self.buffers[from_queue[0]].add(from_queue[1])
class BufferedCamera():
def __init__(self, streamURL, cam_id, saved_data=None):
self.streamURL = streamURL
self.cam_id = cam_id
# get current camera's framerate
cam = cv2.VideoCapture(streamURL)
self.FPS = cam.get(5)
if self.FPS == 0:
self.FPS = 24
cam.release()
print(f"Input res: {cam.get(3)}x{cam.get(4)} | FPS: {self.FPS}")
# use that framerate to adjust the time between each iteration of mainloop
self.period = int((1.0/self.FPS)*1000)
def readloop(self, queue):
while True:
self.read(queue)
def read(self, queue):
cam = cv2.VideoCapture(self.streamURL)
_, frame = cam.read()
if frame is not None:
queue.put((self.cam_id, frame))
cv2.waitKey(self.period)
我通过在我的 Process
函数中和 readloop 之前创建 cv2.VideoCapture
对象来让 multiprocessing
工作:
def readloop(self, queue):
cam = cv2.VideoCapture(self.streamURL)
while True:
self.read(queue, cam)
我想显示两个或多个单独的视频,并使用 cv2 应用了轻微的图像处理。
如果我不使用 threading/multiprocessing
会浪费大量时间来显示使用 cv2.waitKey(timeThatCouldBeSpentFetchingAFrameForAnotherVideo)
的帧。
我尝试使用 threading
,但它无法正常工作。我收到此警告:WARNING: nextEventMatchingMask should only be called from the Main Thread! This will throw an exception in the future.
。这通常会导致崩溃。
所以,我决定尝试实现 multiprocessing
,理论上它应该比 threading
处理更复杂的图像更快(对吗??)。 I used this as an example. 但是,在这种情况下,我 运行 进入了另一个问题,这种方法只能让我获得视频的第一帧。另外,我尝试将 cv2.VideoCapture() 放在 Process
之外,但结果是:TypeError: cannot pickle 'cv2.VideoCapture' object
.
这是我的代码:
class CamManager:
def __init__(self):
self.saving = Saving()
self.cams = self.createCamObjList()
self.buffers = [Buffer(cam.FPS*BUFFER_SIZE) for cam in self.cams]
def createCamObjList(self):
l = []
for i, url in enumerate(STREAM_URLS):
saved_data = self.saving.getDataFor(url)
cam = BufferedCamera(url, i, saved_data)
l.append(cam)
return l
def startStreamCapture(self):
queue_for_cams = multiprocessing.Queue()
processes = [multiprocessing.Process(
target=cam.readloop, args=[queue_for_cams]).start() for cam in self.cams]
while True:
if not queue_for_cams.empty():
from_queue = queue_for_cams.get()
self.buffers[from_queue[0]].add(from_queue[1])
class BufferedCamera():
def __init__(self, streamURL, cam_id, saved_data=None):
self.streamURL = streamURL
self.cam_id = cam_id
# get current camera's framerate
cam = cv2.VideoCapture(streamURL)
self.FPS = cam.get(5)
if self.FPS == 0:
self.FPS = 24
cam.release()
print(f"Input res: {cam.get(3)}x{cam.get(4)} | FPS: {self.FPS}")
# use that framerate to adjust the time between each iteration of mainloop
self.period = int((1.0/self.FPS)*1000)
def readloop(self, queue):
while True:
self.read(queue)
def read(self, queue):
cam = cv2.VideoCapture(self.streamURL)
_, frame = cam.read()
if frame is not None:
queue.put((self.cam_id, frame))
cv2.waitKey(self.period)
我通过在我的 Process
函数中和 readloop 之前创建 cv2.VideoCapture
对象来让 multiprocessing
工作:
def readloop(self, queue):
cam = cv2.VideoCapture(self.streamURL)
while True:
self.read(queue, cam)