Motion detection with the #RaspberryPi camera and Python

Foundation forum member ‘brainflakes‘ has managed to write a Python script to take and analyse images from the Raspberry Pi camera module in order to detect movement. He explains what it does on the forum:

While watching for motion it pipes a thumbnail image from raspistill at around 1fps to analyse (it keeps everything in memory to avoid wearing out the SD card). Once motion is detected it calls raspistill again to write a high-res jpeg to disk.

It also checks free disk space and if under a set limit it starts to delete the oldest images to make sure there is always enough free space for new images.

While running on my rev1 B it consumes around 12% CPU / 4% ram and manages to capture a full size image once ever 2-3 secs.

If you need to install PIL run “sudo aptitude install python-imaging-tk”

Here’s the script:

import StringIO
import subprocess
import os
import time
from datetime import datetime
from PIL import Image

# Motion detection settings:
# Threshold (how much a pixel has to change by to be marked as "changed")
# Sensitivity (how many changed pixels before capturing an image)
# ForceCapture (whether to force an image to be captured every forceCaptureTime seconds)
threshold = 10
sensitivity = 20
forceCapture = True
forceCaptureTime = 60 * 60 # Once an hour

# File settings
saveWidth = 1280
saveHeight = 960
diskSpaceToReserve = 40 * 1024 * 1024 # Keep 40 mb free on disk

# Capture a small test image (for motion detection)
def captureTestImage():
command = "raspistill -w %s -h %s -t 0 -e bmp -o -" % (100, 75)
imageData = StringIO.StringIO()
imageData.write(subprocess.check_output(command, shell=True))
imageData.seek(0)
im = Image.open(imageData)
buffer = im.load()
imageData.close()
return im, buffer

# Save a full size image to disk
def saveImage(width, height, diskSpaceToReserve):
keepDiskSpaceFree(diskSpaceToReserve)
time = datetime.now()
filename = "capture-%04d%02d%02d-%02d%02d%02d.jpg" % (time.year, time.month, time.day, time.hour, time.minute, time.second)
subprocess.call("raspistill -w 1296 -h 972 -t 0 -e jpg -q 15 -o %s" % filename, shell=True)
print "Captured %s" % filename

# Keep free space above given level
def keepDiskSpaceFree(bytesToReserve):
if (getFreeSpace() < bytesToReserve): for filename in sorted(os.listdir(".")): if filename.startswith("capture") and filename.endswith(".jpg"): os.remove(filename) print "Deleted %s to avoid filling disk" % filename if (getFreeSpace() > bytesToReserve):
return

# Get available disk space
def getFreeSpace():
st = os.statvfs(".")
du = st.f_bavail * st.f_frsize
return du

# Get first image
image1, buffer1 = captureTestImage()

# Reset last capture time
lastCapture = time.time()

while (True):

# Get comparison image
image2, buffer2 = captureTestImage()

# Count changed pixels
changedPixels = 0
for x in xrange(0, 100):
for y in xrange(0, 75):
# Just check green channel as it's the highest quality channel
pixdiff = abs(buffer1[x,y][1] - buffer2[x,y][1])
if pixdiff > threshold:
changedPixels += 1

# Check force capture
if forceCapture:
if time.time() - lastCapture > forceCaptureTime:
changedPixels = sensitivity + 1

# Save an image if pixels changed
if changedPixels > sensitivity:
lastCapture = time.time()
saveImage(saveWidth, saveHeight, diskSpaceToReserve)

# Swap comparison buffers
image1 = image2
buffer1 = buffer2

Many thanks to brainflakes for this – fantastic to see people getting stuck in with some useful applications for the camera

Read the original post on the Raspberry Pi Foundation forum

5 comments for “Motion detection with the #RaspberryPi camera and Python

    • @Kevin. it would work with other cameras yes.

      You would need to modify the captureTestImage() function.

      there are a few ways to achieve this. Including using pygame. or opencv.

      I would suggest searching “capturing images from webcams in python” and you should find a few tutorials. then replace the captureTestImage() with the image acquiring code from the tutorials. As long as it returns an image and an image buffer, the rest of the code should work fine.

  1. […] ใช้กล้องของ Raspberry Pi จับว่าเมื่อไหรที่ภาพมีการเปลี่ยนแปลงครับ แต่แทนที่จะใช้ Motion เพื่อดักจับความเปลี่ยนแปลง ก็เขียนสคริป  Python แทน โดยใช้ Python Image Library (PIL) มาช่วยดึงภาพจากสองเวลา แล้วเทียบกันว่า pixel เปลี่ยนไปกี่จุด ถ้ามากพอจึงจะถือว่าภาพเกิดการเปลี่ยนแปลง แล้วก็ใจดีแจก source code มาด้วยครับ ที่มา Raspberry Pi ผ่านทาง http://178.62.14.192/?p=4296 […]

  2. Hi,
    This is a great post had it working for some time but recently it just stopped altogether and wont capture any images. I have checked and the camera still works fine. It halts on the line
    imageData.write(subprocess.check_output(command, shell=True))
    And the error text includes a reference to
    “/usr/lib/python2.7/subprocess.py”,
    I think this started after I upgraded recently (sudo apt-get upgrade). Do you know of an issue that might cause this?
    Thanks
    Dave

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.