【问题标题】:Python multiprocessing Array and OpenCV3 FramesPython 多处理数组和 OpenCV3 帧
【发布时间】:2019-03-26 18:45:26
【问题描述】:

我阅读了这篇 [post] (Right way to share opencv video frame as Numpy array between multiprocessing processes) 并尝试完成实施。相机正在拍摄刚刚找到的图像,图像的形状,缓冲区和另一个进程中接收到的图像是匹配的。但接收到的图像显示黑白噪声线。 我尝试在读/写数组之前添加锁无济于事。

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

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()

输出是两个好的窗口,一个黑白剥离的窗口,加上以下(修剪):

VideoWorker VideoWorker-1 VideoWorker:得到了 img 形状(2764800,) VideoWorker:完成 主要:形状 (720, 1280, 3) 大小 2764800 fps 30.0 主要:重塑尺寸 2764800 main: frombuffer 形状 (2764800,) main: 循环 buf 重塑 (720, 1280, 3) 主要:框架形状(720、1280、3) main: frombuffer 形状 (2764800,) main: 循环 buf 重塑 (720, 1280, 3) 主要:框架形状(720、1280、3) main: frombuffer 形状 (2764800,) main: 循环 buf 重塑 (720, 1280, 3) 主要:框架形状(720、1280、3) main: frombuffer 形状 (2764800,) main: 循环 buf 重塑 (720, 1280, 3) 主要:框架形状(720、1280、3) 主要流程完成

在阵列上共享帧有点卡住。我的队列工作得很好。 第一次发布到stackoverflow。有什么建议吗?

【问题讨论】:

  • 不确定为什么 class VideoWorker(Process): 和 if name == 'main': 没有粘贴到代码中。代码中的所有缩进也是正确的。
  • 我可能有类似的问题。尝试将您的 numpy 数组保存为图像(使用 OpenCV 的 imwrite 或 skimage)为 png 或 tif 并检查图像是否正确“在引擎盖下”,只有 OpenCV 显示功能,即 Qt 或它正在使用的任何东西都搞砸了.
  • 如何保证worker不会在主进程写入数据的同时读取数据?我在那里看不到任何同步。

标签: python arrays numpy opencv


【解决方案1】:

尝试添加

img = img.reshape(self.shape)

到 np.frombuffer 行下方的 run 方法

img 似乎有错误的形状,因此被误解了。

【讨论】:

    【解决方案2】:

    我想通了。是的,正如 Dan 指出的那样,我必须锁定(之前尝试过一次)。 我还必须正确选择类型和尺寸。重塑喜欢 h x w x c,我习惯了 w x h x c。这是一个没有循环的工作解决方案,其中两个进程通过 Array 显示相同的 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()
    

    感谢 cmets。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-15
        • 2019-11-18
        • 2016-11-07
        • 2019-08-19
        • 2017-10-15
        • 2016-08-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多