81 lines
3.6 KiB
Markdown
81 lines
3.6 KiB
Markdown
---
|
||
title: "Motion Sensitive Image Capturing In Python"
|
||
date: 2014-07-28T00:00:00
|
||
slug: motion-sensitive-image-capturing-in-python
|
||
|
||
---
|
||
This is quite a nice little script that uses the PyGame library to access the computers webcam, and then takes a succession of photos, comparing percentage differences between the photos taken to determine whether or not any motion has occurred. If it does detect motion, then it captures 2 photos per second for 30 seconds and saves them to the file system.
|
||
|
||
While this script uses the PyGame library for image capture, it could easily be modified to use other libraries or image capture methods - such as using the camera module on a Raspberry Pi (see [this](http://www.raspberrypi.org/documentation/usage/camera/python/README.md) guide for instructions)
|
||
|
||
## Prerequisites
|
||
|
||
* [PyGame Library](http://www.pygame.org/news.html)
|
||
* Python Imaging Library (PIL) - [Pillow](http://pillow.readthedocs.org/en/latest/index.html)
|
||
* A webcam with up-to-date drivers installed
|
||
|
||
## The clever bit
|
||
|
||
The clever bit wasn’t actually my idea - for a while I was struggling for ways to compare still images, until I found [this gem](http://rosettacode.org/wiki/Percentage_difference_between_images#Python) on Rosetta Code that returns a percentage difference between the two images.
|
||
|
||
So what this little bit of code actually does is:
|
||
|
||
* Turn the two arrays of image data into one array of tuples, with each tuple representing equivalent pixels in each image
|
||
* If the image is grayscale, just goes through each pixel and adds the difference in the numerical values of those pixels together
|
||
* If the image is in RGB mode, it does exactly the same but with the values of the different colour bands, instead of just the pixel values
|
||
* _ncomponents_ is the number of the components in the image (i.e. width _height_ number of bands)
|
||
* *hen get the percentage of “dif” relative to the number of possible colours in the image (255), and divide it by the number of components
|
||
|
||
It’s a little convoluted, but it gives quite a good difference in the image.
|
||
|
||
One thing I’m not 100% sure on is the boundary for motion capture - I’ve set it to a 2.5% difference which worked well for me, but if you’re outdoors it’s best to make that higher, to account for all of the extra movement (e.g. wind)
|
||
|
||
## The script
|
||
|
||
Download the script [here](/files/motion_33.py)
|
||
|
||
```python
|
||
import pygame
|
||
import pygame.camera as camera
|
||
import time
|
||
import pygame.image as im
|
||
from PIL import Image
|
||
from itertools import izip
|
||
import os
|
||
|
||
camera.init()
|
||
cam = camera.Camera(camera.list_cameras()[0],(640,480))
|
||
cam.start()
|
||
size = cam.get_size()
|
||
|
||
#This code is from Rosetta Code http://rosettacode.org/wiki/Percentage_difference_between_images#Python
|
||
def check_images(i1,i2):
|
||
i1 = im.tostring(i1,"RGB")
|
||
i1 = Image.frombytes("RGB",size,i1)
|
||
i2 = im.tostring(i2,"RGB")
|
||
i2 = Image.frombytes("RGB",size,i2)
|
||
|
||
pairs = izip(i1.getdata(), i2.getdata())
|
||
if len(i1.getbands()) == 1:
|
||
dif = sum(abs(p1 - p2) for p1,p2 in pairs)
|
||
else:
|
||
dif = sum(abs(c1 - c2) for p1,p2 in pairs for c1,c2 in zip(p1,p2))
|
||
|
||
ncomponents = size[0] * size[1] * 3
|
||
return (dif / 255.0 * 100) / ncomponents
|
||
|
||
while 1:
|
||
i1 = cam.get_image()
|
||
time.sleep(1)
|
||
i2 = cam.get_image()
|
||
dif = check_images(i1,i2)
|
||
|
||
if dif > 2.5:
|
||
for x in range(0,30):
|
||
timestamp = time.strftime("%Y-%m-%d--%H:%M:%S")
|
||
image.save(cam.get_image(), timestamp + ".jpg")
|
||
time.sleep(0.5)
|
||
|
||
time.sleep(1)
|
||
```
|