这是一种方法。我使用PiCamera以 60 fps 的速度捕捉 MJPEG 帧 8 秒。请阅读本文档中的第 4.7 节。
我选择了视频端口,因为它是最快的捕获方法,因为它不会通过对多个帧进行平均来进行复杂的去噪,这会减慢速度。
我选择 MJPEG “Motion JPEG”作为输出格式,因为这意味着帧在收到之前在 GPU 上进行了 JPEG 压缩,这意味着我需要更少的 CPU 资源和更少的 RAM,因为这些帧是压缩的。
当每一帧到达时,除了简单地将其附加到 RAM(内存)中的 JPEG 压缩帧列表之外,我没有做任何其他处理。
录制完成后,我只需遍历内存中的帧列表,将它们从 JPEG 转换回 OpenCV 用于图像的 Numpy 数组,然后显示它们。由于它们是以 60fps 的速度采集的,这意味着每 16 毫秒记录一个新帧。因此,如果我以 64 毫秒的延迟播放,它应该会慢 4 倍。
#!/usr/bin/env python3
import numpy as np
import cv2
import time
import picamera
class SplitFrames(object):
def __init__(self):
self.frame_num = 0
# List of all the JPEG-encoded frames we receive
self.frames = []
# Total memory used
self.memory = 0
def write(self, buf):
if buf.startswith(b'\xff\xd8'):
# Start of new frame
l = len(buf)
print(f'DEBUG: New frame of {l} bytes')
self.frames.append(buf)
self.frame_num += 1
self.memory += l
else:
print(f'ERROR: partial frame of {len(buf)} bytes received belonging to previous frame')
################################################################################
# Main program - alter these variables according to needs
################################################################################
targetFPS, duration = 60, 8
width, height = 1024, 768
print(f'Recording frames of {width}x{height} at {targetFPS} fps for {duration} seconds')
################################################################################
# Recording loop
################################################################################
with picamera.PiCamera(framerate=targetFPS) as camera:
camera.resolution=(width,height)
camera.start_preview()
# Give the camera some warm-up time
time.sleep(2)
output = SplitFrames()
start = time.time()
camera.start_recording(output, format='mjpeg')
camera.wait_recording(duration)
camera.stop_recording()
finish = time.time()
# Calculate a few statistics
fps = output.frame_num / (finish - start)
avg = int(output.memory/output.frame_num)
MB = output.memory/(1024*1024)
print(f'Captured {output.frame_num} frames at {fps:.3f} fps, average bytes/frame={avg}, total RAM={MB:.3f} MB')
################################################################################
# Playback loop - grab frames from list and display with delay
################################################################################
for frame_num, frame in enumerate(output.frames):
print(f'DEBUG: Playing back frame {frame_num}')
im = cv2.imdecode(np.frombuffer(frame, dtype=np.uint8), cv2.IMREAD_COLOR)
cv2.imshow('Slow Motion Replay', im)
cv2.waitKey(64)
运行时,输出如下所示:
Recording frames of 1024x768 at 60 fps for 8 seconds
DEBUG: New frame of 26661 bytes
DEBUG: New frame of 33335 bytes
DEBUG: New frame of 33558 bytes
DEBUG: New frame of 34146 bytes
...
...
DEBUG: New frame of 34208 bytes
DEBUG: New frame of 34408 bytes
DEBUG: New frame of 34356 bytes
DEBUG: New frame of 34248 bytes
Captured 480 frames at 59.763 fps, average bytes/frame=36938, total RAM=16.909 MB
正如您所看到的,它仅使用 17MB 的 RAM 来实现 8s 的 60fps @ 1024x768 像素,不到 1GB RasPi 3 的 RAM 的 2%,不到 4GB RasPi 4 的 0.5%,因此您可以运行更长时间而不会用完内存。
然后它会立即以四分之一的速度播放。这是录制 iPhone 高速计时器后播放的迷你动画 GIF:
注意 1:您不必使用OpenCV进行播放,您可以使用任何其他可以显示 JPEG 的包。
注意 2:您可以在重放循环中显示图像之前调整图像大小、对其进行注释或以某种方式对其进行处理。
注意 3:请注意,您可以将cv2.imshow()
回放循环中的 替换为对OpenCV VideoWriter()
的调用并将视频保存到磁盘,而不是根据需要将其显示在屏幕上。
注意 4:您可以添加一个quality
参数camera.start_recording()
来控制图像质量/大小。或者您可以更改为原始 RGB 或 YUV 格式。
关键词:RasPi、Raspberry Pi、RaspberryPi、图像处理、视频录制、PiCamera、高速、高速、60 fps、慢动作、慢动作、慢动作、缓冲区、内存中缓冲、回放。