Recently I had some extra time on my hand, so I’ve decided to write a simple Python script, for HDIPCAM. I’m a beginner in Python, and this was a good excuse to use it for something practical.
The idea behind the script was basically to be run on a server, waiting for motion and start recording when motion is detected.
HDIPCAM is a poor excuse for a security camera. If you search for it (or for the device ID MEYE-035366-CCFBB) most likely there won’t be any results. It’s a cheap, low quality product, with no real support for data storage. It seems models in higher price range support an SD card, with this one though, the only option is FTP, which does not work, with no explanation of what could be the problem. The quality of control panel in general is reflected in the image bellow:
Getting the Data
The control panel and the camera itself can be accessed through a web client. For the camera, there’s GET request being made for each frame. This is, as everything else, poorly implemented; images are getting constantly appended to a DOM, causing your computer sooner or latter to start struggling for RAM.
GET requests are made to the URL in format:
/snapshot.cgi?user=%s&pwd=%s, at this point I shall not comment on security implications of such implementation. Each time you make a request a fresh image is returned. In practice, a web client makes about one request per second, resulting in 1fps.
To start, I grabbed two images with time difference of one second. To get a measure of how similar two images are, you can calculate the root-mean-square (RMS) value of the difference between the images. You can read more about it on effbot and ActiveState. I’m using effbot’s method at the moment, which works reasonably well.
When I had this, I put two images side by side and saved them together with time and RMS value. There’s a noise on each frame which means that the value will never be zero. In my case everything that could be considered a movement had a value six or above.
With this in mind I was able to make a watchdog method which can run indefinitely, capturing and saving each frame for which motion is detected.
There was always couple of false positives, like for example a fly landing on a camera’s lens or a cat passing by. Some of them are impossible to be prevented, others, like for example a tree swaying in the wind, could be eliminated though. For this reason I’ve added a support for masks, basically, a region of the image will be covered with a black square, hence being ignored when comparison is made.
To have a real video first I needed more (than one) images per second. This could be easily achieved with threads. Basically I’ve made a loop to capture, process and save images, each in a separated thread; to control fps, I’ve used
time.sleep(0.25) would in theory result in 4fps. The bottleneck in this approach is the network (or a camera itself) which will timeout whenever there are too many requests per second.
At the moment I can capture eight or at least four frames per second, which is enough to create a relatively smooth video. To connect images together I’m using
ffmpeg (external call). First I’ve used
-i %d.jpg parameter, which would use a bunch of numerically named images as an input and join them together producing a video. That would terminate the process if any image in the sequence was missing (which does happen with occasional timeouts). Therefore I’ve switched to
-f image2 -pattern_type glob -i '*.jpg'. This grabs all images regardless of a filename. For images to be in the proper order though, filenames need to be padded with zeros.
Finally I’ve used
argparse so that script can be called from a terminal, with various arguments.
Putting It All Together
With all elements in place, this is how the script functions:
- watchdog is constantly monitoring images,
- if difference is detected, recorder is started,
- recorder is trying to capture Nfps,
- depending on fps parameter, each Nth frame is checked for motion,
- if no motion is detected for five seconds, recording is suspended,
- images are converted to video with ffmpeg.
You can get the script on github.com/vxmxpx/hdipcam.