在树莓Pi上保存图像流的最快方法

2024-04-18 16:43:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我们有一个摄像头通过USB3连接到树莓皮4。相机只能提供原始图像[2056x1542x3],我们可以读取约30帧/秒。在Raspberry Pi 4上,我们需要将这些图像保存到磁盘-由于空间和SD卡的写入速度,以任何速度保存原始图像(10 MB/张)都是不可行的。相反,我们希望压缩这些图像,然后尽可能快地保存它们。你知道吗

我们当前的解决方案类似于下面的代码片段:


def save_image(frame,filename):
    cv2.imwrite(filename,frame)

...

(ret, frame) = cam.get_next_frame()
if ret == IS_SUCCESS:
    timestamp = get_timestamp()
    filename = conf["cv_image_folder"] + timestamp + ".jpg"
    save_thread = threading.Thread(target=save_image, args=(frame,filename,))
    save_thread.start()

OpenCV是用libjpeg-turbo和所有可能的硬件标志编译的,用于加速计算。在所有的4个或6个树莓果核中,大约有4个果核。非线程配置也是如此。我们在相机上手动设置帧速率,并监视生成的线程数(大约3-4个并发线程,每秒5-6帧)。我们选择JPEG(即使它有损),因为PNG或TIFF压缩需要更长的计算时间。你知道吗

有什么办法可以改进吗?你知道吗


Tags: 图像imagegetsavefilename线程threadframe
1条回答
网友
1楼 · 发布于 2024-04-18 16:43:51

我认为丹的发现,你可以得到拜耳图像将证明你的问题的解决方案,但是我做了一些工作的概念,使用Broadcom的MMAL“多媒体抽象层”做JPEG编码的VideoCore GPU上,以减少CPU负载,并想把它放在这里。结合丹的建议和/或其他寻求做类似事情的人,它可能会对你有用。你知道吗

由于在GPU上运行,它可以以每秒4帧左右的速度将(相当大的)图像编码到磁盘,同时几乎不使用CPU。我观察到3个CPU内核处于空闲状态,第四个内核的使用率徘徊在10-15%左右。你知道吗

代码只需获取一个名为"image.jpg"的图像,并将其大小调整为所使用的维度,然后重复编码并将其发送到磁盘100次。你知道吗

#!/usr/bin/env python3

import io
import numpy as np
from picamera import mmal, mmalobj as mo
from PIL import Image
from threading import Event

# Globals
w, h = 2048, 1536      # These seem to need to be multiples of 64, or maybe 16
EncoderAvail = Event()
EncoderAvail.set()

# Set up MMAL-based JPEG encoding
encoder = mo.MMALImageEncoder()
encoder.inputs
encoder.inputs[0].format = mmal.MMAL_ENCODING_RGB24
encoder.inputs[0].framesize = (w, h)
encoder.inputs[0].commit()
encoder.outputs[0].copy_from(encoder.inputs[0])
encoder.outputs[0].format = mmal.MMAL_ENCODING_JPEG
encoder.outputs[0].commit()
encoder.outputs[0].params[mmal.MMAL_PARAMETER_JPEG_Q_FACTOR] = 90

def image_callback(port, buf):
    with open(f"frame-{frame}.jpg", 'wb') as jpeg:
        jpeg.write(buf.data)
        EncoderAvail.set()
    #return bool(buf.flags & mmal.MMAL_BUFFER_HEADER_FLAG_FRAME_END)
    return True

encoder.outputs[0].enable(image_callback)
encoder.inputs[0].enable(lambda port, buf: True)

# Encode the same image repeatedly as we are measuring the encode time not acquire time
im = Image.open('image.jpg').resize((w,h))
rgb_data = np.array(im)

for frame in range(100):
    print(f"Frame: {frame}")

    # Make red bar across top that gets longer with each frame to be sure we are getting them all
    rgb_data[0:10,:frame,0] = 255

    EncoderAvail.wait()
    buf = encoder.inputs[0].get_buffer()
    buf.data = rgb_data[:]
    EncoderAvail.clear()
    encoder.inputs[0].send_buffer(buf)

encoder.outputs[0].disable()
encoder.inputs[0].disable()

代码在很大程度上基于Picamera MMAL的内容-here。代码可能不是最优的-例如,我不知道如何将缓冲区的数量增加到2,这将启用双缓冲,并可能产生很大的差异。我也不知道如何使它更事件驱动,因为它是相当同步的时刻。你知道吗

如我所说,您可以通过更改mmal.MMAL_ENCODING_RGB24将Bayer图像编码为JPEG,这样您就可以继续使用它了。你知道吗

如果有人知道更多关于MMAL的东西,并能够改进它,请随时采取我的代码,改进它,并添加它作为一个新的答案,让我知道,所以我们都可以学习。你知道吗

我注意到,它目前似乎并不尊重JPEG的质量设置,所以如果有人可以改善,请让我知道。你知道吗

关键词:Raspberry Pi、GPU、JPEG编码、JPEG编码器、MMAL、Videocore GPU、Broadcom、多媒体抽象层、Raspi。你知道吗

相关问题 更多 >