Wednesday, March 27, 2013

PHP Image Comparison: Motion Detection

So a few years ago I spent quite a while using Java to dismantle images from a video feed to detect motion. Using some of the tricks I learned there, I started porting the concept to PHP. Some of my current goals here include but are not limited to the following:
  • Merging/blending images together.
  • Finding motion/changes between two or more images.
  • Reporting said motion/changes as a center coordinate, bounding rectangle, or best yet a vector.

Download

If you're anything like me and don't want to read all my mumbo-jumbo, then you can just go ahead and checkout and download the code on Github here.

Breakdown

First a break down of the main classes... What do they do:
SimpleImage
A class that represents an image. Has functions that help load images from files, stream images to a client, crop, resize, merge/overlay another image, etc.
State
Basically a wrapper for a 2D array of numbers. Provides functions for determining the average, standard-deviation and some other interesting things about said array of numbers. Also some manipulators to filter or change the numbers into other meaningful data. States can be derived from images, or functions of other states.

Code Examples

Blending images together.
What for?
  • Artificial super long exposure photography.
  • Part of my process to display motion detection in a feed of images from a webcam.
include "SimpleImage.php";
include "Util.php";

// get a list of images from a subdirectory
$imagePath = "./img/3/";
$files = listFilesInDirectory($imagePath);

// setup an image to work with
$baseImage = new SimpleImage($imagePath.$files[0]);

// setup an array of all other images
$images = array();
for ($i = 1; $i < count($files); $i++)
 $images[] = new SimpleImage($imagePath.$files[$i]);

// merge the latter images into the first image.
$baseImage->merge($images);

// stream image to client
$baseImage->output();
The above process was run on some images like this:
The result looking like this:
Motion/Change detection
In the following example, the actual change is determined within the first few lines. The second half of the code is just there to display results of said detection.
include "SimpleImage.php";
include "State.php";

// setup two images to work with
$i1 = new SimpleImage("./img/4/IMG_0392.JPG");
$i2 = new SimpleImage("./img/4/IMG_0393.JPG");

// setup the states that will work with and interpret the numbers
$state = new State(15, 8, $i1);
$state = $state->difference(new State(15, 8, $i2), rgbColorDistance);
$state->abs()->denoiseStdDev()->scale(10)->round(0);

// for purposes of visual debugging, merge the two images together
$i1->merge($i2);

// using the merged image, layer on a visual of state differences
$result = $state->drawImageIndicator($i1);

// $box will hold an array (x,y,w,h) that indicates location of change
$box = $state->getBoundingBox($i1->getWidth(), $i1->getHeight());
$color = imagecolorallocate($result->getImage(), 10, 255, 10);
imagerectangle($result->getImage(), $box["x"]-1, $box["y"]-1, 
 $box["x"]+$box["w"]+1, $box["y"]+$box["h"], 
 $color);

// $cog will hold an array (x,y) indicating center of change
$cog = $state->getCenterOfGravity($i1->getWidth(), $i1->getHeight());
imagearc($result->getImage(), 
 $cog["x"], $cog["y"], 7, 7,  0, 360, 
 imagecolorallocate($result->getImage(), 255, 255, 0));
imagearc($result->getImage(), 
 $cog["x"], $cog["y"], 9, 9,  0, 360, 
 imagecolorallocate($result->getImage(), 255, 0, 0));

// stream image to client
$result->output();
The above process was run on these two images:
The result looking like this:

Goals for my next version

  • Add edge detection and island detection (multiple hotspots of change) in one image.
  • Removing non-still objects from a set of images to produce one still image. (ie: Remove tourists from my picture of some famous monument)
Post a Comment