Skip to content

Instantly share code, notes, and snippets.

@waveform80
Last active September 20, 2022 19:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save waveform80/8496879 to your computer and use it in GitHub Desktop.
Save waveform80/8496879 to your computer and use it in GitHub Desktop.
Recording motion before and after detection

Capturing video both before and after motion detection

Assuming you want to record 10 seconds of video before motion is detected, and 10 seconds of video after motion is detected, you can simply create a circular buffer with enough space for 20 seconds of video, wait until motion is detected, then wait 10 seconds more, and only then write the contents of the circular buffer to disk. basic_circular.py demonstrates this.

The second example is a little more complicated and results in a couple of files per motion event: the 10 seconds before and the all seconds that motion is still occurring after first detection. Once motion is detected, we start recording subsequent frames to a file, and while that's going on, dump the circular buffer to another file. Once we stop detecting motion, we close the "after" file, and split recording back to the circular stream. This is demonstrated in advanced_circular.py.

import io
import picamera
from PIL import Image
prior_image = None
def detect_motion(camera):
global prior_image
stream = io.BytesIO()
camera.capture(stream, format='jpeg', use_video_port=True)
stream.seek(0)
if prior_image is None:
prior_image = Image.open(stream)
return False
current_image = Image.open(stream)
# Compare current_image to prior_image to detect motion. This is left
# as an exercise for the reader!
result = False
# Once motion detection is done, make the current image the prior one
prior_image = current_image
return result
def write_before(stream):
# Write the entire content of the circular buffer to disk. No need to lock
# the stream here as we're definitely not writing to it simultaneously
with io.open('before.h264', 'wb') as output:
for frame in stream.frames:
if frame.header:
stream.seek(frame.position)
break
while True:
buf = stream.read1()
if not buf:
break
output.write(buf)
# Wipe the circular stream once we're done
stream.seek(0)
stream.truncate()
def main(camera):
stream = picamera.PiCameraCircularIO(camera, seconds=10)
camera.start_recording(stream, format='h264')
try:
while True:
camera.wait_recording(1)
if detect_motion(camera):
# As soon as we detect motion, split the recording to record
# the bits "after" motion
camera.split_recording('after.h264')
# While that's going, write the 10 seconds "before" motion to
# disk as well, and wipe the circular stream
write_video(stream)
# Wait until motion is no longer detected, then split recording
# back to the in-memory circular buffer
while detect_motion(camera):
camera.wait_recording(1)
camera.split_recording(stream)
finally:
camera.stop_recording()
if __name__ == '__main__':
with picamera.PiCamera() as camera:
camera.resolution = (1280, 720)
main(camera)
import io
import picamera
def detect_motion(camera):
stream = io.BytesIO()
camera.capture(stream, format='jpeg', use_video_port=True)
# Detect motion in the captured image. Presumably one would need a prior
# image here to compare to ... this is left as an exercise for the reader!
motion_detected = False
return motion_detected
def write_video(stream):
# Write the entire content of the circular buffer to disk
with io.open('motion.h264', 'wb') as output:
with stream.lock:
for frame in stream.frames:
if frame.header:
stream.seek(frame.position)
break
while True:
buf = stream.read1()
if not buf:
break
output.write(buf)
def main(camera):
stream = picamera.PiCameraCircularIO(camera, seconds=20)
camera.start_recording(stream, format='h264')
try:
while True:
camera.wait_recording(1)
if detect_motion(camera):
# Once we've detected motion, keep recording for 10 seconds
# and only then dump the stream to disk
camera.wait_recording(10)
write_video(stream)
finally:
camera.stop_recording()
if __name__ == '__main__':
with picamera.PiCamera() as camera:
main(camera)
@gabeale
Copy link

gabeale commented Jul 16, 2021

Hi Dave,
according to you it is possible to web stream while capturing after a motion detection with the same Picamera?
Thx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment