numpy Python多处理数组和OpenCV3帧

9rbhqvlz  于 2023-01-26  发布在  Python
关注(0)|答案(4)|浏览(142)

我看了这个[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 : got img shape (2764800,)
VideoWorker: done
main: shape  (720, 1280, 3) size  2764800 fps  30.0
main: reshape size  2764800
main: frombuffer shape  (2764800,)
main: loop buf reshape  (720, 1280, 3)
main: frame shape  (720, 1280, 3)
main: frombuffer shape  (2764800,)
main: loop buf reshape  (720, 1280, 3)
main: frame shape  (720, 1280, 3)
main: frombuffer shape  (2764800,)
main: loop buf reshape  (720, 1280, 3)
main: frame shape  (720, 1280, 3)
main: frombuffer shape  (2764800,)
main: loop buf reshape  (720, 1280, 3)
main: frame shape  (720, 1280, 3)
Main process done

在数组上共享帧时有点卡住了。我的队列工作得很好。第一篇文章是stackoverflow。有什么建议吗?

k4aesqcs

k4aesqcs1#

我想明白了。是的,正如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()

感谢您的评论。

vxf3dgd4

vxf3dgd42#

尝试添加

img = img.reshape(self.shape)

添加到np.frombuffer行下面的run方法
IMG看起来具有错误的形状,因此被误解。

sg24os4d

sg24os4d3#

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

xjreopfe

xjreopfe4#

我也遇到过类似的问题。我有4台摄像机从网络上传输数据。图像帧发生了变化并被堆叠。队列对我来说太慢了,所以我用管道解决了整个问题。队列就是基于此。4台摄像机堆叠在一个4瓦片中,并使用多处理进行处理。在我看来效果非常好。我也没有更多的延迟,使用管道代替队列。

相关问题