简体   繁体   English

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

[英]Fastest way to save image stream on Raspberry Pi

We have a camera connected to a Raspberry Pi 4 via USB3.我们有一个通过 USB3 连接到 Raspberry Pi 4 的相机。 The camera can only provide RAW images [2056x1542x3] which we can read at about 30 FPS.相机只能提供 RAW 图像 [2056x1542x3],我们可以以大约 30 FPS 的速度读取。 On the Raspberry Pi 4 we need to save these images to disk - due to space and write speed to the SD card it is not feasible to save the RAW images (10 MB/piece) at any rate really.在 Raspberry Pi 4 上,我们需要将这些图像保存到磁盘 - 由于 SD 卡的空间和写入速度,以任何速度保存 RAW 图像(10 MB/张)实际上是不可行的。 Instead we want to compress these images and then save them as fast as possible.相反,我们希望压缩这些图像,然后尽可能快地保存它们。

Our current solution looks similar to the below snippet:我们当前的解决方案类似于以下代码段:


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 is compiled with libjpeg-turbo and all possible HW-flags for accelerated computing. OpenCV 是用libjpeg-turbo和所有可能的硬件标志编译的,用于加速计算。 At about 5 or 6 FPS the Raspberry Pi 4 uses about 100% of all 4 cores.在大约 5 或 6 FPS 时,Raspberry Pi 4 使用大约 100% 的所有 4 个内核。 The same goes for a non-threaded configuration.非线程配置也是如此。 We manually set the framerate on the camera and monitor the number of threads spawned (which is about 3-4 concurrent threads at 5-6 FPS).我们在相机上手动设置帧率并监控产生的线程数(在 5-6 FPS 时大约 3-4 个并发线程)。 We choose JPEG (even though its lossy) since PNG or TIFF compression takes longer to compute.我们选择 JPEG(即使它是有损的),因为 PNG 或 TIFF 压缩需要更长的时间来计算。

Is there any way to improve this?有什么办法可以改善这种情况吗?

I think Dan's discovery that you can get the Bayer image is going to prove the solution to your problem, however I did some work on the concept of using Broadcom's MMAL "Mulitmedia Abstraction Layer" to do JPEG encoding on the VideoCore GPU to lessen the CPU load and wanted to place it here.我认为 Dan 发现您可以获得 Bayer 图像将证明您的问题的解决方案,但是我在使用 Broadcom 的 MMAL “多媒体抽象层”在 VideoCore GPU 上进行 JPEG 编码以减少 CPU 的概念上做了一些工作加载并想把它放在这里。 It may prove useful to you in combination with Dan's suggestion and/or to other folk seeking to do similar things.结合丹的建议和/或其他寻求做类似事情的人,它可能对您有用。

As a result of running on the GPU, it can encode your (rather large) images to disk at around 4 frames per second whilst using almost no CPU .由于在 GPU 上运行,它可以将您的(相当大的)图像以每秒 4 帧左右的速度编码到磁盘,同时几乎不使用 CPU I observed 3 CPU cores were idle and the fourth core hovered on and off around 10-15% usage.我观察到 3 个 CPU 内核空闲,第四个内核在 10-15% 左右的使用率上下徘徊。

The code just takes a single image called "image.jpg" and resizes it to the dimensions you are using and then repeatedly encodes that and sends it to disk 100 times.该代码只需要一个名为"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()

The code is heavily based on the Picamera MMAL stuff - here .代码很大程度上基于 Picamera MMAL 的东西—— 这里 The code is probably not optimal - for example, I do not know how to increase the number of buffers to 2 which would enable double-buffering and potentially make a big difference.代码可能不是最佳的 - 例如,我不知道如何将缓冲区的数量增加到 2,这将启用双缓冲并可能产生很大的不同。 I am also not sure how to make it more event-driven as it is rather synchronous at the moment.我也不确定如何使它更受事件驱动,因为它目前相当同步。

As I said, you can change it to encode Bayer images to JPEG, by changing mmal.MMAL_ENCODING_RGB24 so you may be able to still use it.正如我所说,您可以通过更改mmal.MMAL_ENCODING_RGB24将其更改为将拜耳图像编码为 JPEG,以便您仍然可以使用它。

If anyone knows more about the MMAL stuff and is able to improve it, please feel free to take my code, improve it and add it as a new answer and let me know so we can all learn.如果有人对 MMAL 的内容有更多了解并能够对其进行改进,请随时使用我的代码,对其进行改进并将其添加为新答案并告诉我,以便我们都可以学习。

I noticed that it doesn't currently seem to honour the JPEG Quality setting either, so if anyone can improve that, please let me know.我注意到它目前似乎也不支持 JPEG 质量设置,所以如果有人可以改进它,请告诉我。

Keywords : Raspberry Pi, GPU, JPEG encoding, JPEG encoder, MMAL, Videocore GPU, Broadcom, Multimedia Abstraction Layer, Raspi.关键词:Raspberry Pi,GPU,JPEG 编码,JPEG 编码器,MMAL,Videocore GPU,Broadcom,多媒体抽象层,Raspi。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 stream 之前将 Raspberry pi 中的文件保存到 Influxdb 并在 Grafana 中可视化? - How to save file in Raspberry pi before stream to Influxdb and visualize in Grafana? 如何通过图像处理保存图像[Raspberry Pi] - How To Save Image Via Image Processing [Raspberry Pi] 将 PiCamera 图像阵列从一个 Raspberry Pi 传输到另一个 - Stream PiCamera Image Array from one Raspberry Pi to another 如果树莓派停电,有没有办法在python中保存变量值? - Is there a way to save the variable value in python In case of power failure on the raspberry pi? 覆盆子pi picamera-图像比较 - raspberry pi picamera - image comparison 从图像/阵列生成补丁并保存坐标的最快方法 - Fastest way to generate patches from an image/array and save the coordinates 谁能解释如何使用OpenCV在Raspberry Pi上从kinect保存RGB图像? - Could anyone explain how to save RGB image from kinect on Raspberry Pi using OpenCV? Raspberry Pi:使用framebuffer图像查看器(FBI),是否可以在不打开其他FBI显示器的情况下更改图像? - Raspberry Pi: Using framebuffer image viewer (FBI), is there a way to change an image without opening another FBI display? 如何在Raspberry Pi / Python中将文本保存为音频? - How to save a text to audio in Raspberry Pi/Python? 调整图像大小的最快方法 - Fastest way to resize image
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM