<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="sodnpoo.xsl" type="text/xsl"?>
<xml page="/?t=rpi"><a href="http://sodnpoo.com/?x=html">HTML version</a><post>
  <tag value="birdcam"/>
  <tag value="rpi"/>
  <title>picam motion detection and overlaying timestamps</title>
  <date>4 May 2014</date>
  <p>
  I wanted to add timestamps to the video that's captured while using <a href="/posts.xml/raspberrypi_camera_with_opencv_motion_detection_and_recording.xml">my picam, opencv-based motion detection</a> application. The easiest way would probably be to read and modify every frame in userspace on the Pi, before letting the GPU encode it to h264, however I'd like to keep frame rates as high as possible - so would rather the Pi did the minimum amount of work it needs to do. I only really need the frame number and a timestamp and some way to merge them with the video.
  </p>
  <p>
  The MMAL API for the Pi's camera has a bunch of flags in the 'buffer header' objects that get passed around as the image data flows from component to component. By counting the instances of one of these - MMAL_BUFFER_HEADER_FLAG_FRAME_END - you can track frame numbers. I've modified the code to emit the frame number and an epoch timestamp when motion is detected. To prevent it from producing hundreds of these events, it only emits when another flag: MMAL_BUFFER_HEADER_FLAG_KEYFRAME - is set at the start of a keyframe. This pegs the rate a the keyframe rate; every two seconds. An example keyframe event looks like this in the logs:
  </p>
  <pre>
  KEYFRAME (1397291533:1)
  </pre>
  <p>
  The logs are written to stderr and the h264 video stream is written to stdout. To record them both, the app is run like this:
  </p>
  <pre>
  ./mmal_opencv_modect &gt; video.h264 2&gt; video.log
  </pre>  
  <p>
  As it turns out the h264 file it spits out is less than perfect, some things play it at a high frame rate and some things don't play it at all. To clean it up I've been pushing it through ffmpeg to create a nice avi:
  </p>
  <pre>
  ./ffmpeg -r 30 -i video.h264 -q:v 1 -r 30 video.avi
  </pre>
  <p>
  This step doesn't need to happen on the pi, and can be offloaded to faster machine - and while we're post processing we may as well be adding timestamp overlays too :) Initially I tried to use ffmpeg's 'drawtext' filter and to start with it looked promising; it has expressions so that text strings can be positioned across exact frame ranges. Unfortunately each of these are specified individually on the command line and more than a thousand exceeds the maximum command line length - at least here on my machine.
  </p>
  <p>
  Instead I've written a <a href="https://github.com/sodnpoo/rpi-mmal-opencv-modetect/blob/master/scripts/modect2sub.py">python script</a> that can take the log output from mmal_opencv_modect and convert it into a MicroDVD subtitle file. The MicroDVD format uses frame numbers, so is easy to translate from the keyframe events in the logs. The epoch timestamp is also converted to something a little more human friendly. The script is run like this:
  </p>
  <pre>
  ./scripts/modect2sub.py video.log &gt; video.sub
  </pre>
  <p>
  Now we have the subtitle file it just needs to be merged with the h264 stream. Using ffmpeg, compiled with libass support:
  </p>
  <pre>
  ./ffmpeg -r 30 -i video.h264  -vf "subtitles=video.sub" -q:v 1 -r 30 video.avi
  </pre>
  <p>
  Github repo can be found <a href="https://github.com/sodnpoo/rpi-mmal-opencv-modetect">here</a>.
  </p>
</post><post>
  <tag value="birdcam"/>
  <tag value="rpi"/>
  <title>raspberrypi camera with opencv motion detection and recording</title>
  <date>2 Apr 2014</date>
  <p>
  I've just <a href="https://github.com/sodnpoo/rpi-mmal-opencv-modetect">pushed some code</a> for the raspberry pi and it's camera - based on <a href="http://www.raspberrypi.org/forums/viewtopic.php?f=43&amp;t=44982">tasanakorn's work</a> - up to github that uses some very simple <a href="http://opencv.org/">OpenCV</a> to do background subtraction and then detect movement. When it detects motion, the camera image data is sent on to the h264 encoder in the VideoCore and the h264 stream is written to stdout. The detection and encoding happen in different threads, so that even though we can't do motion detection at full frame rate, that doesn't affect the recording frame rate. Here's some frame rates and CPU utilisation numbers taken at various camera modes (incl. the new 640x480 at 90 FPS!):
  </p>
  <pre>
 720p30 : OpenCV = 15.05, Video = 30.51, ~60% CPU
1080p30 : OpenCV = 14.90, Video = 30.02, ~75% CPU
 VGAp90 : OpenCV = 21.57, Video = 91.12, ~90% CPU
  </pre>
  <p>
  To build, follow the README instructions in the github repo. Once it's built you can run it like this:
  </p>
  <pre>
  ./mmal_opencv_modect &gt; video.h264
  </pre>
  <p>
  I'm hoping to use some more raspberry pi's (and camera modules) to replace the analogue system we're currently using for <a href="/birdcam/">birdcam</a>. The resolution is much higher and the 90 FPS mode should show the very fast movement of some of the smaller birds. The pi based system should be more distributed and scalable than the current system too.
  </p>
</post></xml>
