Jes*_*per 4 python compression opencv raspberry-pi
我们有一个通过 USB3 连接到 Raspberry Pi 4 的相机。该相机只能提供 RAW 图像 [2056x1542x3],我们可以以大约 30 FPS 的速度读取该图像。在 Raspberry Pi 4 上,我们需要将这些图像保存到磁盘 - 由于 SD 卡的空间和写入速度,无论如何保存 RAW 图像(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()
Run Code Online (Sandbox Code Playgroud)
libjpeg-turbo
OpenCV 使用所有可能的硬件标志进行编译,以实现加速计算。在大约 5 或 6 FPS 时,Raspberry Pi 4 使用全部 4 个内核的大约 100%。对于非线程配置也是如此。我们手动设置相机的帧速率并监视生成的线程数量(大约为 5-6 FPS 时的 3-4 个并发线程)。我们选择 JPEG(尽管它是有损的),因为 PNG 或 TIFF 压缩需要更长的时间来计算。
有什么办法可以改善这一点吗?
我认为 Dan 发现您可以获得拜耳图像将证明您问题的解决方案,但是我对使用 Broadcom 的 MMAL “多媒体抽象层”在 VideoCore GPU 上进行 JPEG 编码以减少 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()
Run Code Online (Sandbox Code Playgroud)
该代码很大程度上基于 Picamera MMAL 的东西 -此处。该代码可能不是最佳的 - 例如,我不知道如何将缓冲区的数量增加到 2,这将启用双缓冲并可能产生很大的差异。我也不确定如何使其更加事件驱动,因为它目前相当同步。
正如我所说,您可以更改它以将拜耳图像编码为 JPEG,通过更改,mmal.MMAL_ENCODING_RGB24
您可能仍然可以使用它。
如果有人对 MMAL 的东西了解更多并且能够改进它,请随时使用我的代码,改进它并将其添加为新答案并让我知道,以便我们都可以学习。
我注意到它目前似乎也不支持 JPEG 质量设置,因此如果有人可以改进它,请告诉我。
关键词:Raspberry Pi、GPU、JPEG 编码、JPEG 编码器、MMAL、Videocore GPU、Broadcom、多媒体抽象层、Raspi。