编辑:我有关于视频流是什么的问题,所以我会提供更多的清晰度。该流是从我的网络摄像头的实时视频提要,通过OpenCV访问。我得到的每一帧相机读取它,并将它发送到一个单独的处理过程。该进程根据对图像进行的计算返回文本。然后将文本显示在图像上。我需要实时显示流,如果文本和正在显示的视频之间存在延迟(即,如果文本适用于前一帧,那就可以了)。
也许一个更简单的思考方法是,我正在对摄像头所看到的进行图像识别。我一次发送一个帧到一个单独的进程,对框架进行识别分析,并将文本发回作为一个标题放在实时提要上。显然,处理所需的时间比简单地从摄像头抓取帧并显示出来要花费更多的时间,因此,如果标题和摄像头提要显示的内容出现延迟,这是可以接受的,也是预期的。
现在发生的情况是,由于其他进程,我显示的实时视频是滞后的(当我不向计算过程发送帧时,就不会有任何滞后)。我还确保一次只排队一个帧,这样就避免了队列的重载和延迟。我已经更新了下面的代码以反映这个细节。
我正在使用python中的多处理模块来帮助加快我的主程序。然而,我相信我可能做错了一些事情,因为我不认为计算是并行的。
我希望我的程序从主进程中的视频流中读取图像,并将帧传递给两个子进程,它们对它们进行计算,并将文本发回(包含计算结果)到主进程。
然而,当我使用多重处理时,主进程似乎滞后了,运行速度大约是没有它的一半,这使我相信进程不是完全并行运行的。
在进行了一些研究之后,我推测,延迟可能是由于使用队列在进程之间进行通信(将图像从主程序传递给子进程,并将文本从子进程传递给main)。
但是,我注释掉了计算步骤,只让主进程传递一个图像,子进程返回空白文本,在这种情况下,主进程根本没有减慢。它全速行驶。
所以我相信
1)我没有最优地使用多处理
或
2)这些进程不能真正并行地运行(我可以理解有一点滞后,但它正在将主进程减半)。
这是我的代码大纲。只有一个消费者,而不是2个,但这两个消费者几乎是一样的。如果有人能提供指导,我将不胜感激。
class Consumer(multiprocessing.Process):
def __init__(self, task_queue, result_queue):
multiprocessing.Process.__init__(self)
self.task_queue = task_queue
self.result_queue = result_queue
#other initialization stuff
def run(self):
while True:
image = self.task_queue.get()
#Do computations on image
self.result_queue.put("text")
return
import cv2
tasks = multiprocessing.Queue()
results = multiprocessing.Queue()
consumer = Consumer(tasks,results)
consumer.start()
#Creating window and starting video capturer from camera
cv2.namedWindow("preview")
vc = cv2.VideoCapture(0)
#Try to get the first frame
if vc.isOpened():
rval, frame = vc.read()
else:
rval = False
while rval:
if tasks.empty():
tasks.put(image)
else:
text = tasks.get()
#Add text to frame
cv2.putText(frame,text)
#Showing the frame with all the applied modifications
cv2.imshow("preview", frame)
#Getting next frame from camera
rval, frame = vc.read()发布于 2016-08-12 10:40:54
我希望我的程序在主进程中从视频流中读取图像。
在生产者/使用者实现(也就是上面的实现)中,生产者将任务放入要由使用者执行的队列中,需要与主/控制流程分开,以便它可以在读取结果队列输出的主进程的同时添加任务。
试试看以下几点。已经在使用者进程中添加了睡眠以模拟处理,并添加了第二个使用者以显示它们是并行运行的。
如果处理跟不上输入流,那么最好限制任务队列的大小,以避免它随着内存的使用而流失。可以在调用Queue(<size>)时指定大小。如果队列大小相同,则对.put的调用将被阻塞,直到队列未满为止。
import time
import multiprocessing
import cv2
class ImageProcessor(multiprocessing.Process):
def __init__(self, tasks_q, results_q):
multiprocessing.Process.__init__(self)
self.tasks_q = tasks_q
self.results_q = results_q
def run(self):
while True:
image = self.tasks_q.get()
# Do computations on image
time.sleep(1)
# Display the result on stream
self.results_q.put("text")
# Tasks queue with size 1 - only want one image queued
# for processing.
# Queue size should therefore match number of processes
tasks_q, results_q = multiprocessing.Queue(1), multiprocessing.Queue()
processor = ImageProcessor(tasks_q, results_q)
processor.start()
def capture_display_video(vc):
rval, frame = vc.read()
while rval:
image = frame.get_image()
if not tasks_q.full():
tasks_q.put(image)
if not results_q.empty():
text = results_q.get()
cv2.putText(frame, text)
cv2.imshow("preview", frame)
rval, frame = vc.read()
cv2.namedWindow("preview")
vc = cv2.VideoCapture(0)
if not vc.isOpened():
raise Exception("Cannot capture video")
capture_display_video(vc)
processor.terminate()发布于 2016-08-17 15:59:37
下面是一个更优雅的(IMHO)解决方案,它利用多个进程来处理您的帧:
def process_image(args):
image, frame = args
#Do computations on image
return "text", frame
import cv2
pool = multiprocessing.Pool()
def image_source():
#Creating window and starting video capturer from camera
cv2.namedWindow("preview")
vc = cv2.VideoCapture(0)
#Try to get the first frame
if vc.isOpened():
rval, frame = vc.read()
else:
rval = False
while rval:
yield image, frame
# Getting next frame from camera
rval, frame = vc.read()
for (text, frame) in pool.imap(process_image, image_source()):
# Add text to frame
cv2.putText(frame, text)
# Showing the frame with all the applied modifications
cv2.imshow("preview", frame)Pool.imap应该允许您迭代池的结果,而它仍在处理来自您的摄像机的其他图像。
发布于 2016-08-15 11:06:20
(基于上次代码示例更新的解决方案)
它将从流中获取图像,一旦可用,就将其中一个放到任务队列中,并用最后一个文本显示最后一个图像。
我在里面放了一些活动循环来模拟一个比两个图像之间的处理时间更长的处理过程。我的意思是显示的文本不一定是属于图像的文本,而是最后一个计算出来的文本。如果处理速度足够快,则应该限制图像和文本之间的转移。
请注意,我强制调用get/put,并进行了一些尝试/捕捉。根据医生的说法,空的和满的并不是100%的准确。
import cv2
import multiprocessing
import random
from time import sleep
class Consumer(multiprocessing.Process):
def __init__(self, task_queue, result_queue):
multiprocessing.Process.__init__(self)
self.task_queue = task_queue
self.result_queue = result_queue
# Other initialization stuff
def run(self):
while True:
frameNum, frameData = self.task_queue.get()
# Do computations on image
# Simulate a processing longer than image fetching
m = random.randint(0, 1000000)
while m >= 0:
m -= 1
# Put result in queue
self.result_queue.put("result from image " + str(frameNum))
return
# No more than one pending task
tasks = multiprocessing.Queue(1)
results = multiprocessing.Queue()
# Init and start consumer
consumer = Consumer(tasks,results)
consumer.start()
#Creating window and starting video capturer from camera
cv2.namedWindow("preview")
vc = cv2.VideoCapture(0)
#Try to get the first frame
if vc.isOpened():
rval, frame = vc.read()
frame = cv2.resize(frame, (0,0), fx=0.5, fy=0.5)
else:
rval = False
# Dummy int to represent frame number for display
frameNum = 0
# String for result
text = None
font = cv2.FONT_HERSHEY_SIMPLEX
# Process loop
while rval:
# Grab image from stream
frameNum += 1
# Put image in task queue if empty
try:
tasks.put_nowait((frameNum, frame))
except:
pass
# Get result if ready
try:
# Use this if processing is fast enough
# text = results.get(timeout=0.4)
# Use this to prefer smooth display over frame/text shift
text = results.get_nowait()
except:
pass
# Add last available text to last image and display
print("display:", frameNum, "|", text)
# Showing the frame with all the applied modifications
cv2.putText(frame,text,(10,25), font, 1,(255,0,0),2)
cv2.imshow("preview", frame)
# Getting next frame from camera
rval, frame = vc.read()
# Optional image resize
# frame = cv2.resize(frame, (0,0), fx=0.5, fy=0.5)下面是一些输出,您可以看到图像和结果之间的延迟,以及返回的结果。
> ('display:', 493, '|', 'result from image 483')
> ('display:', 494, '|', 'result from image 483')
> ('display:', 495, '|', 'result from image 489')
> ('display:', 496, '|', 'result from image 490')
> ('display:', 497, '|', 'result from image 495')
> ('display:', 498, '|', 'result from image 496')https://stackoverflow.com/questions/38864711
复制相似问题