代码之家  ›  专栏  ›  技术社区  ›  Frey

在多个处理进程之间以Numpy数组形式共享opencv视频帧的正确方法

  •  2
  • Frey  · 技术社区  · 8 年前

    我想在OpenVC中与我的多处理子进程共享捕获的帧,但是 video_capture.read() 创建一个新对象,并且不写入我将通过包装共享的numpy数组 multiprocessing.Array()

    代码如下:

    ret, frame = video_capture.read()
    shared_array = mp.Array(ctypes.c_uint16, frame.shape[0] * frame.shape[1], lock=False)
    while True:
        b = np.frombuffer(shared_array)
        ret, b = video_capture.read()
    

    但是缓冲区 b 被重写 read() 作用因此,我不会写入缓冲区/共享数组。

    在子流程中,我执行以下操作:

    img = np.frombuffer(shared_array)
    cv2.imshow('Video', img)
    

    仅包含视频第一帧的共享阵列。如何正确写入共享数组,以便能够读取子进程中的每个帧? 我不想使用队列或管道。共享内存是一种方式,因为更多进程将消耗帧。

    1 回复  |  直到 8 年前
        1
  •  3
  •   javidcf    8 年前

    有两个问题,一个是共享阵列的大小和形状,另一个是如何访问它。要解决第一个问题,首先需要确保创建的数组的大小与视频帧的大小相对应。您已经阅读了一个框架,并使用了它的宽度和高度(尽管 you can do it without reading any frame ),但未说明其频道数。

    ret, frame = video_capture.read()
    shape = frame.shape
    shared_array = mp.Array(ctypes.c_uint16, shape[0] * shape[1] * shape[2], lock=False)
    

    您选择了 uint16 作为数据类型,这很好(同样,您可以使用 video_capture.get(cv2.CAP_PROP_FORMAT) 获取帧的确切数据类型,但您可以选择所需的任何内容,因为NumPy会将值转换为数组数据类型)。但是,创建NumPy数组时,必须指定要使用的数据类型,否则将使用 float64 默认情况下:

    b = np.frombuffer(shared_array, dtype=np.uint16)
    

    然后您必须将其重塑为帧的形状(并不是说这不会创建新的NumPy数组,它只是一个视图,所以它仍然使用共享缓冲区):

    b = b.reshape(shape)
    

    最后,当您读取帧时,您不想覆盖 b 变量,而是写入数组。此外,您应该仅在实际读取帧时执行此操作:

    while True:
        ret, frame = video_capture.read()
        if ret:
            b[:] = frame