0

我正在使用 PiCamera 构建一个运动检测器,它将图像发送到消息队列以让 ML 检测到一个人(或不检测),然后响应客户端。运动检测代码大部分来自 pyimagesearch.com 并且运行良好。

一旦我知道检测到一个人,我现在想保存视频(包括原始的几帧)。由于检测到人的延迟(约 3 秒),我计划使用循环 IO 环形缓冲区来确保捕获最初几秒的移动。这意味着我需要更改在检测运动时循环帧的方式。目前我正在使用:

rawCapture = PiRGBArray(camera, size=tuple(resolution))
camera = PiCamera()
for f in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
    frame = f.array
    # resize, blur, grayscale frame etc.
    # compare to average of last few frames to detect motion

我的理解是这只是抓取最新的帧(即不是每一帧)并继续循环直到检测到运动。这就是我想要的,因为我不希望通过尝试检查每一帧来使过程落后于实时。

为了改变这个循环逻辑来利用环形缓冲区,我想我可以使用这样的东西:

camera = PiCamera()
with camera:
    ringbuf = picamera.PiCameraCircularIO(camera, seconds=60)
    camera.start_recording(ringbuf, format='h264')
        while True:
            # HOW TO GET LATEST FRAME FROM ringbuf???
            # resize, blur, grayscale frame etc.
            # compare to average of last few frames to detect motion

如上面的片段所示,如何从 ringbuf 获取最新帧作为 numpy 数组以通过运动检测检查执行?我已经看到通过在调用 start_recording 时添加 motion_output=detect_function 来获取每一帧的示例,但这将检查每一帧,我不希望该过程落后于实时动作。

4

1 回答 1

0

所以我似乎已经解决了这个问题。解决方法如下。我猜我每次切换到 detect_motion 函数时都会丢失一帧,但这对我来说很好。使用 saveAt 可以让我在检测到运动后的固定秒数后将视频导出到文件。

def detect_motion(camera):
    camera.capture(rawCapture, format="bgr", use_video_port=True)
    frame = rawCapture.array
    # resize, blur, grayscale frame etc.
    # compare to average of last few frames to detect motion    


with camera:
    stream = PiCameraCircularIO(camera, seconds=60)
    camera.start_recording(stream, format='h264')
    try:
        while True:
            time.sleep(.3)
            if detect_motion(camera):
                print('Motion detected!')
                saveAt = datetime.now() + timedelta(seconds=30)
            else:
                print('Nothing to see here')
            if saveAt:
                print((saveAt - datetime.now()).seconds)
                if saveAt < datetime.now():
                    write_video(stream)
                    saveAt = None
            
于 2020-12-20T10:31:09.717 回答