Using a server for Remote Motion Detection from Raspberry Pi or any device that can do MJPEG-Streaming

The Raspberry Pi is a great device for home security. I have been using the Raspberry Pi and some TrendNet (update, TrendNet’s newer firwmare is terrible, does not work well with motion jpeg) cameras as well for many years, and I was wondering how I could merge multiple devices into a single unified home security package that would store everything on a central server. The catch is that I could only use the TrendNet devices as-is without putting custom firmware on them. I tried ‘zoneminder’ for a while, but I could never get the motion detection to work, I even dug into the code and tried to figure out the bug but I had limited time and gave up due to the volume of code I would have to read and understand.

So I decided to write a python script using OpenCV to read MJPG streams on the server from any device that can output a MJPG stream and do the motion detection processing on the server. It was surprisingly easy, and I have gained a new respect for python in the process!

The main functionality I wanted was:
1. Allow motion detection on any device that I have on my network (Raspberry Pi, ODroid-C1, older TrendNet WebCams).
2. Automatically reconnect if stream is lost.
3. Save images to the server (or other network location)
4. change the directory and file permissions so any user can read write them (unlike the motion package I have used for years)
5. Save a single best summary image in a directory to make it easy to review events.

For the Raspberry Pi or ODroid-C1, you must install MJPG-Streamer to stream the image to the network. This program is fantastic and results in an extremely low CPU load. I won’t go into that as you should go to the source for up to date instructions.

This is the script I use to start the stream on the Pi, this gives about 5 images per second when motion is detected.

killall mjpg_streamer
sleep 10
/pathtostreamer/mjpg_streamer
-o "/pathtostreamer/output_http.so
-w "/pathtostreamer/www"
-i "/pathtostreamer/input_raspicam.so
-x 1280 -y 720 -fps 10 -ex night -ISO 800 -awb auto" &

If you want higher resolution but lower frame rate, you can use -x 1920 -y 1080.
(Note: ISO does not work for MJPG-Streamer at the time of writing this)

For the TrendNet Cameras you need to setup an MJPEG stream and get the URL from the Camera to put into this program. I just ordered a new outdoor TrendNet Camera and will post the instructions once I have set it up. (Bad new, the new TrendNet Cameras have limited motion jpeg to very very low resolutions, making them useless with this project. I will be replacing my TrendNet cameras with Raspberry Pi’s)

The python code to do the motion detection from the server is on BitBucket.org here:
BitBucket project for remotemotion.py

The program will automatically create the motion directory containing a subdirectory for each camera on your network. In each subdirectory it will create a date folder for the current day and save the jpg images there.
I created a function to create these directories and set the file permissions so that the program can run as root, but it will save under the main users home folder so they can edit or delete the images easily.
It will also create a summary directory where it will store the ‘best’ image from a sequence of events for fast review.

You will need to edit the script and set the gPathForImages, and gPathForSummary variables and create the list of motion streams you want to monitor. I will be cleaning this up in the future, but for now it works fine.

Motion Detection is done by averaging the last 500 frames of image deltas and looking for any spike above 130% of the average. So far this has worked really well, but I implemented a very quick and dirty averaging window that needs improvement.
The Summary image is chosen by saving the image from an event that has the highest difference between 2 sequential frames. I did not think this would work that well, but so far it has been doing a very decent job!

To get an Ubuntu server to auto start this program you need to create a file /etc/init/remotemotion.conf


start on runlevel [2345]
stop on runlevel [!2345]
exec /path/to/remotemotion.py

I wrote this in an evening, so it does not do everything I would like. I will post updates as I make them, some of the future things I would like are:
1. Ability to add or remove streams from the running program.
2. Face detection so I can flag images containing a face.
3. Body detection so I can flag images containing people.
4. Save status and statistics in a file so I can write a web page to display it.

The load on my old laptop, running Ubuntu Server with a 1st gen core-i5 and a 1920×1080 pixel image is pretty much 100% on one CPU. This means I should be able to monitor another 3 cameras unless the bandwidth gets too high. If I start running into bandwidth issues I may write my own MJPG-Streamer with Motion Detection in C++ that runs on the pi and mirrors the logic on the server but still allows my own motion detection for commercial cameras.

Also, I may decide to rewrite the server program in c++ for better performance as it seems to be putting a larger load on my server than it should. The kids will get annoyed if their minecraft server gets jerky!