expands bogdanmarian.com
click and drag this icon to move layer toggle

Python Motion Detection and Compositing using PIL (the Python Imaging Library)

Motion.py

Motion.py is a package for detecting motion using the Python Imaging Library (PIL). By comparing two saved images or frames from a camera we can detect which pixels have changed. A threshold is used to account for noise and lower quality images.

download Motion.py
view source

Functions

compare_images(
  Image frame1,
  Image frame2,
  int threshold,
  int key_type
)

frame1 and frame2 are the images to be compared, the rest of the parameters are optional. If no threshold is passed or COMPUTE_THRESHOLD (0) in its place one is computed based on the size of the image. The higher the threshold the more change is required to detect motion. the key_type determines how the bands are tested to filter pixel change. Valid types are:

ANY_RGB any band (R,G,B) differs by the threshold (default)
ANY_2RGB at least 2 bands (R+G,G+B,R+B) differ by the threshold
SUM_RGB the sum of each band (R+G+B) differs by the threshold

compare_images returns a green Image (0,255,0) with the changed pixels from frame2 layered on top. frame1 and frame2 must be the same size.

green_key(
  Image canvas,
  Image key_image,
  Image frame2,
  int key_type
)

green_key() takes three images and an optional key_type. The canvas image is the base image for this composite. The green key_image is used to take the pixels from frame2 and layered them onto the canvas. The key_type determines how an internal mask will be created for compositing. Valid types are:

KEY_REG no mask, just key all green pixels (0,255,0) (default)
KEY_BLUR applied PIL blurring and smoothing to the mask - increases coverge, provides transparency
KEY_BLUR_BRIGHT blur,smooth and brighten mask (*2) - increases coverage, lowers transparency
KEY_BLUR_BRIGHT_MORE blur,smooth, brighten mask more (n^2) - increase coverage, opacity, decreases details

Below are some code examples of different thresholds and how key_types affect motion detection and compositing.


Tutorial

Example 1. default

from Motion import *

frame1 = Image.open("frame1.jpg")
frame2 = Image.open("frame2.jpg")
canvas = Image.open("canvas.jpg")

key_image = compare_images(frame1,frame2)
finished_image = green_key(canvas,key_image,frame2)


Left is frame1, Right is frame2. Since no threshold or key_type is passed the defaults are used.

And this is the canvas serving as the base for the composite.

The green area in key_image is the portion of the two images where no motion was detected. The area that is visible represents the pixels that have exceeded the default threshold.
A mask is created internally by green_key(). In this example no blur or smoothing is applied to the mask.
The finished_image that is returned by green_key() layers frame2 on top of the canvas based on the key_image




Example 2. lower threshold

from Motion import *

frame1 = Image.open("frame1.jpg")
frame2 = Image.open("frame2.jpg")
canvas = Image.open("canvas.jpg")

key_image = compare_images(frame1,frame2,8)
finished_image = green_key(canvas,key_image,frame2)

The green area in key_image is spotty beacuse the threshold of 8 used in this example is too low and detects minute pixels changes caused by a variety of reasons ( lighting changes, noise, compression, interferance ... )
Without any blurring and smoothing applied to the mask sections of it we may want to ignore show through.
The finished_image shows the artifacts in the composite. A threshold this low is better suited for a higher resolution or larger image.




Example 3. higher threshold

from Motion import *

frame1 = Image.open("frame1.jpg")
frame2 = Image.open("frame2.jpg")
canvas = Image.open("canvas.jpg")

key_image = compare_images(frame1,frame2,88)
finished_image = green_key(canvas,key_image,frame2)

The green area in key_image detects little motion because the threshold is set too high. Not only does the color of the pixel have to change but at least one of the bands must change by 88/255
Even without blurring and smoothing applied to the mask a good deal of information is lost because the threshold's filtering was too strong.
The finished_image shows little of the frame2 image.




Example 4. compare types

from Motion import *

frame1 = Image.open("frame1.jpg")
frame2 = Image.open("frame2.jpg")
canvas = Image.open("canvas.jpg")

key_image = compare_images(frame1,frame2,0,ANY_2RGB)
finished_image = green_key(canvas,key_image,frame2)

These samples show how to change the comparison type when calling compare_images(). The finished image still uses the default mask with no enhancements.

The left column shows the results of the ANY_2RGB and the right using SUM_RGB. ANY_2RGB is more selective, SUM_RGB requires less change in the pixels to detect motion.








Example 5. green_key types

from Motion import *

frame1 = Image.open("frame1.jpg")
frame2 = Image.open("frame2.jpg")
canvas = Image.open("canvas.jpg")


key_image = compare_images(frame1,frame2)
finished_image = green_key(canvas,key_image,frame2,KEY_BLUR)

These samples show the use of blurring when calling green_key().

The left column shows the results of the KEY_BLUR and the right using KEY_BLUR_BRIGHT. KEY_BLUR applies smoothing and blurring to the internal mask. KEY_BLUR_BRIGHT applies these filters and multiplies mask values by a factor of 2.





This last column illustrates the use of the key_type KEY_BLUR_BRIGHT_MORE which applies blurring filters and squares mask values. The result is a mask with more opacity and coverage.








Example 6. custom

from Motion import *

frame1 = Image.open("frame1.jpg")
frame2 = Image.open("frame2.jpg")
canvas = Image.open("canvas.jpg")

key_image = compare_images(frame1,frame2,18,ANY_RGB)
finished_image = green_key(canvas,key_image,frame2,KEY_BLUR_BRIGHT)

This example shows a tweaked version combining a lower threshold, blurring, and linear brightening. The resulting composite retains most of its opacity while softening the mask's edges.


The lower threshold detects extra pixels (cloudy areas in green) but with blurring and smoothing these wont be as noticable in the finished image.
After blurring and brightening is performed on the mask there are still some artifacts but they are resonably subtle.
The finished_image