Motion detection with Raspberry Pi
Explore motion detection using two methods: manual calculations and H.264 motion vectors.
Motion detection is a tricky problem to solve, the key is to balance sensitivity so that it doesn’t catch light changes but still catches movements in the frame. In this article I will describe 2 methods to achieve motion detection: calculating frame differences manually and harnessing the power of the H.264 encoder. Finally, we’ll store the results online using using M2x, AT&T’s Internet-of-Things platform.
Full source code is available at the end of the article.
Raspberry Pi is a low cost single-board computer that is built with the intention of teaching computer science in schools. With the camera module and the small footprint of the Raspberry Pi this setup is the perfect platform for our motion detection system.
Don’t have a Raspberry Pi or the camera module? You can get them here:
- Raspberry Pi Model B+ (B PLUS) 512MB Computer Board on Amazon
- Raspberry Pi 5MP Camera Board Module on Amazon
Plan of action
The goal of the project is to monitor the camera for movement. Once we detect movement in the video stream we will switch over to still camera mode and take photos over the span of several seconds to capture the movement in high resolution snapshots.
We will be using Python as the programming language. Python is a clean language, has a large collection of community developed libraries, and has great support.
Fun fact: Eben Upton and his team envisioned Python as the introduction to programming Raspberry Pi’s which is where the “Pi” in the name comes from.
Method 1: Manual snapshots
Manual motion calculation requires us to take continuous photos. We use 2 buffers, one contains the current raw data and the other one contains the previous frame. After capturing each frame we compare the 2 buffers against each other. For performance reasons the snapshots taken every second are small thumbnail sized photos.
We loop through all the pixels in the green channel of the 2 buffers because the green channel is the highest quality channel. Each pixel value from frame 1 is compared to the matching pixel in frame 2. If the value differs more than the threshold the pixel is considered different and added to the count. Once this process is completed and the total number of changed pixels is higher than the sensitivity we consider movement to be detected and take a full snapshot.
Manual Snapshot Final Thoughts
The idea is simple and straightforward but there is one big disadvantage to this approach. Calculating movement by comparing raw pixel values makes it overly sensitive to static, brightness changes and minor movements. These are not the movements that we like to detect which results in a lot of false positives.
Method 2: Using motion vectors
The first thing I wanted to do is to prevent using shell commands, after researching online I found the picamera python library that achieves this requirement.
The Raspberry Pi’s camera is capable of outputting the motion vector estimates that the H.264 encoder calculates while compressing video. We will harness this data by outputting it to a separate video channel stream.
To hook into the frame by frame data from the picamera library we have to attach an output handler to the picamera object. We created our own to analyze the vector data generated by the H.264 encoder of the Raspberry Pi camera.
The output handler requires that the code in the analyze callback to be executed before the next frame is getting rendered. If that doesn’t happen you get dropped frames and unreliable behavior. because of this, we can’t put our snapshot and upload logic in the analyse method since this takes several seconds to be completed.
Our solution is simple and elegant, in our main loop, is to make a second handler check for a ‘motion has detected’ flag. Our original motion handler keeps handling the events from the encoder but just sets the flag in our second handler. This is quick and does not block the output handler.
Once our second handler detects that the flag has been set to true, the capture logic initiates and ignores any addition movement until the capture process has been completed.
Motion Vector Method Final Thoughts
Using the motion channel was a good decision, it removes the disadvantages of brightness changes and noise in the pixel data by harnessing the power of the H.264 encoder. By using the picamera library we also removed the use of shell commands.
Uploading to AT&T’s M2X
We now have a montage file that has a grid of all the snapshots taken when motion was detected. Next we will wrap the project up by uploading the final image to our AT&T’s M2X device.
First we have to upload the image to a public storage service, for this project I decided to use CloudApp.
With the existence of the post_capture_callback hook in our Pimotion class, implementing the upload logic is very simple. In our custom callback method we use the CloudApp API library (included in the project files) to upload our montage file to their service.
The source code of the CloudApp API class can be found on GitHub.
With the public URL of the montage file available to us, we can complete the last step of our upload process. POSTing the URL to our M2X device. AT&T provides an official M2X Python library that we will be using in this project.
Using the Raspberry Pi as the platform is a perfect fit for a motion detection system. The small footprint allows us to embed the Pi in a small encasing to monitor movement without bulky and expensive hardware.
Using the motion vector data channel from the H.264 encoder allowed us to detect motion with a fairly accurate result. The python lib picamera made using the various Pi camera module functions a breeze.
With AT&T’s M2X python library, uploading our final montage photo to our device was possible with just three (3) lines of code.
The full source code with installation instructions can be found here: https://github.com/citrusbyte/pimotion
Originally published at bits.citrusbyte.com