Python multiprocessing Array and OpenCV3 Frames



我读了这个[帖子](在多处理进程之间将opencv视频帧共享为Numpy数组的正确方法(并尝试完成实现。 相机正在拍摄刚刚找到的图像,图像的形状,缓冲区和接收到的图像在另一个过程中是匹配的。 但是收到的图像显示黑白噪声线。 我尝试在读/写数组之前添加锁,但无济于事。

这是代码。基本上,我想将图像放入numpy中,然后放入数组中,以便另一个进程可以读取图像:

class VideoWorker(Process):
def __init__(self, shared_Array, shape,width, height, fps):
super(VideoWorker, self).__init__()
# passing width /height as want to write video file later...
self.width = width
self.height = height
self.fps = fps
self.shared_Array = shared_Array
self.shape = shape
def run(self):
name = "VideoWorker"
print ('%s %s' % (name, self.name))
cv2.namedWindow(name,cv2.WINDOW_NORMAL)
cv2.resizeWindow(name,640,480)
while True:
img = np.frombuffer(self.shared_Array,dtype=ctypes.c_uint8)
print("%s : got img shape %s " % (name, str(img.shape)))
cv2.imshow(name, img)
if cv2.waitKey(20) & 0xFF == ord('q'):
break
print("%s: done" %name)
if __name__ == '__main__':
camera = cv2.VideoCapture(0)
camera.set(cv2.CAP_PROP_FRAME_WIDTH,1280)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT,720)
width = camera.get(cv2.CAP_PROP_FRAME_WIDTH)
height = camera.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = camera.get(cv2.CAP_PROP_FPS)
cv2.namedWindow("orig",cv2.WINDOW_NORMAL)
cv2.resizeWindow("orig",640,480)
cv2.namedWindow("loop",cv2.WINDOW_NORMAL)
cv2.resizeWindow("loop",640,480)
grabbed, frame = camera.read()
shape = frame.shape
cv2.imshow("orig",frame)
print("main: shape ",shape, "size ", frame.size, "fps ",fps)
# size is L x W x channels
shared_Array = Array(ctypes.c_uint8, shape[0] * shape[1] *shape[2], lock=False)
worker = VideoWorker(shared_Array, shape, width, height, fps )
worker.start()
print("main: reshape size ",shape[0]*shape[1]*shape[2])
while True:
buf = np.frombuffer(shared_Array,dtype=np.uint8)
print("main: frombuffer shape ",buf.shape)
buf = buf.reshape(shape)
print("main: loop buf reshape ",buf.shape)
grabbed, frame = camera.read()
cv2.imshow("loop",frame)
print ("main: frame shape ",frame.shape)
if not grabbed:
break
buf[:] = frame
if worker.is_alive() == False:
break
if cv2.waitKey(20) &  0xFF == ord('q'):
break
print("Main process done")
worker.join()
camera.release()
cv2.destroyAllWindows()

输出是两个良好的窗口和一个黑/白剥离窗口,以及以下内容(修剪(:

视频
工作者 视频工作者-1 视频工作者 : 得到图像形状 (2764800,( 视频工作者:完成 主:形状 (720, 1280, 3( 尺寸 2764800 fps 30.0 主衣身:整形尺寸 2764800 主:从缓冲形状 (2764800,( 主:环形 BUF 重塑 (720, 1280, 3( 主:框架形状 (720, 1280, 3( 主:从缓冲形状 (2764800,( 主:环形 BUF 重塑 (720, 1280, 3( 主:框架形状 (720, 1280, 3( 主:从缓冲形状 (2764800,( 主:环形 BUF 重塑 (720, 1280, 3( 主:框架形状 (720, 1280, 3( 主:从缓冲形状 (2764800,( 主:环形 BUF 重塑 (720, 1280, 3( 主:框架形状 (720, 1280, 3( 主进程完成

在阵列上共享帧有点卡住了。我的队列工作正常。 第一个发布到堆栈溢出。 建议?

我想通了。是的,正如 Dan 指出的那样,我必须锁定(之前尝试过一次(。 此外,我还必须正确获得类型和尺寸。 重塑喜欢 h x w x c,我习惯了 w x h x c。 这是一个没有循环的工作解决方案,其中两个进程通过数组显示相同的 opencv3 图像。

import cv2
import multiprocessing as mp
import numpy as np
import ctypes
import time

class Worker(mp.Process):
def __init__(self,sharedArray,lock, width, height, channels):
super(Worker, self).__init__()
self.s=sharedArray
self.lock = lock
self.w = width
self.h = height
self.c = channels
return
def run(self):
print("worker running")
self.lock.acquire()
buf = np.frombuffer(self.s.get_obj(), dtype='uint8')
buf2 = buf.reshape(self.h, self.w, self.c)
self.lock.release()
print("worker ",buf2.shape, buf2.size)
cv2.imshow("worker",buf2)
cv2.waitKey(-1)

if __name__ == '__main__':
img = cv2.imread('pic640x480.jpg')
shape = img.shape
size = img.size
width = shape[1]
height = shape[0]
channels = shape[2]
realsize = width * height * channels
print('main ', shape, size, realsize)
s = mp.Array(ctypes.c_uint8, realsize)
lock = mp.Lock()
lock.acquire()
buf = np.frombuffer(s.get_obj(), dtype='uint8')
buf2 = buf.reshape(height, width, channels)
buf2[:] = img
lock.release()
worker = Worker(s,lock,width, height, channels)
worker.start()
cv2.imshow("img",img)
cv2.waitKey(-1)
worker.join()
cv2.destroyAllWindows()

感谢您的评论。

尝试添加

img = img.reshape(self.shape)

到运行方法正好在 np.frombuffer 行下方

IMG似乎形状错误,因此被误解了。

顺便说一句,我放弃了这种方法。 我确定在Raspberry Pi 3B上,跨进程地址空间发送1280x720图像的开销太大了,CPU被固定在98%只是移动帧。 我回到了线程,似乎比单线程代码的性能提高了百分之几。

我也有类似的问题。我有 4 台摄像机从网络流式传输。图像帧已更改并堆叠。排队对我来说太慢了,所以我用管道解决了整个问题。队列基于此。4 个摄像头堆叠在一个 4 个图块中,并通过多处理进行处理。在我看来效果很好。我也没有使用管道而不是队列的延迟。