Motion detection with Javascript and a web camera

February 7, 2014

I initially wrote this small application as I was waiting for a few designs to get finalized at work. I didn’t really plan to do anything with it, but I then decided that I might as well release the source code.

So what is it? It’s a basic motion detector/follower written in javascript. It tracks movement with the red square.

There’s no need for any third party libs. The entire application is really only three files. You’ll need a modern browser to run it, but other than that, you’re good to go.

And now to the interesting part, implementation.

How does it work?

The core concept is really simple. Compare one frame against the other. This in it self would be breathtakingly slow, so what I do is that I scale down the frames to two 64px x 48px images and compare them against one and other. I then go through each pixel and see if I can notice a difference.

for(var y = 0; y < height; y++) {
	for(var x = 0; x < width; x++) {
		var pixel1 = temp1Context.getImageData(x,y,1,1);
		var pixel1Data = pixel1.data;

		var pixel2 = temp2Context.getImageData(x,y,1,1);
		var pixel2Data = pixel2.data;

		if(comparePixel(pixel1Data, pixel2Data) == false) {
			// The two pixels differ, do something.
		}
	}
}

Sadly, the webcam generates a lot of noise, so in order to not detect the noise I’ve implemented a range sensitivity on the colors. In essence, what I do, is I go through the RGBA channels of the second pixel, and check if the color is within a range of the first pixel. If the color is out of range, I determine that the pixel has changed and flag the position.

/*
 * Compares an individual pixel (within a range based on sensitivity).
 *
 * @param <Array> p1 The first pixel [r,g,b,a].
 * @param <Array> p2 The second pixel [r,g,b,a].
 *
 * @return <Boolean> If they are the same.
 *
 */
function comparePixel(p1, p2) {
	var matches = true;
	var sensitivity = 40;

	for(var i = 0; i < p1.length; i++) {
		var t1 = Math.round(p1[i]/10)*10;
		var t2 = Math.round(p2[i]/10)*10;

		if(t1 != t2) {
			if((t1+sensitivity < t2 || t1-sensitivity > t2)) {
				matches = false;
			}
		}
	}

	return matches;
}

Once I’ve looped through the small thumbnails, I then calculate the positions for the larger video, which is 640px x 480px. The biggest problem is pixel accuracy, the larger the thumbnail, the more accurate the detection is, but at the expense of performance.

You can try it out here (and you’ll obviously need a web camera). And you can download and mess around with the code here.

Tags