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 guide for instructions)

Prerequisites

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 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

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)