In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Motion Tracer Demo

MotionTracerDemo
@author Test Dept
Get Adobe Flash player
by Test_Dept 03 Mar 2010
/**
 * Copyright Test_Dept ( http://wonderfl.net/user/Test_Dept )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/3Dmp
 */

package {

	import flash.display.Bitmap;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.media.Camera;
	import flash.media.Video;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;

	/**
	 * MotionTracerDemo
	 * @author Test Dept
	 */
	[SWF(backgroundColor="#cccccc", width="465", height="465")]
	public class MotionTracerDemo extends Sprite {

		private var _video : Video;
		private var _tracer : MotionTracer;
		private var _cursorPane : Sprite;

		public function MotionTracerDemo() {
			addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
		}
				
		private function addedToStageHandler(event : Event) : void {

			var camera : Camera = Camera.getCamera();
			
			if (camera == null) {
				var textField : TextField = new TextField();
				textField.autoSize = TextFieldAutoSize.LEFT;
				textField.text = "requires web camera.";
				addChild(textField);
				return;
			}

			camera.setMode(320, 240, 12, true);

			_tracer = new MotionTracer(80, 60);

			_video = new Video(camera.width, camera.height);
			_video.x = 4;
			_video.y = 4;
			_video.attachCamera(camera);
			addChild(_video);
			
			var bmp : Bitmap = new Bitmap(_tracer.bitmapData);
			bmp.x = _video.width + 8;
			bmp.y = 4;
			addChild(bmp);

			_cursorPane = new Sprite();
			addChild(_cursorPane);
			
			addEventListener(Event.ENTER_FRAME, function(event : Event) : void {
				_tracer.capture(_video);
			} );

			_tracer.addEventListener(Event.CHANGE, function(event : Event) : void {

				var g : Graphics = _cursorPane.graphics;
				var x : Number = _tracer.currentX * _video.width / _tracer.width;
				var y : Number = _tracer.currentY * _video.height / _tracer.height;

				g.clear();
				g.lineStyle(2, 0x00ff00);
				g.moveTo(x, 0);
				g.lineTo(x, _video.height);
				g.moveTo(0, y);
				g.lineTo(_video.width, y);
			} );
		}
	}
}

import flash.display.BitmapData;
import flash.media.Video;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.events.EventDispatcher;
import flash.events.Event;
import flash.filters.BlurFilter;

class MotionTracer extends EventDispatcher {

	private const _matchThreshold : Number = 32;
	private const _moveThreshold : Number = 64;

	private const _percentMinMoved : Number = 0.1;
	private const _percentMaxMoved : Number = 25;
	
	private var _minMoved : Number;
	private var _maxMoved : Number;
	
	private var _width : Number;
	private var _height : Number;

	private var _calcBmp : BitmapData;
	private var _lastBmp : BitmapData;
	
	private var _currentX : Number;
	private var _currentY : Number;
	
	public function MotionTracer(width : Number, height : Number) {

		_width = width;
		_height = height;

		_calcBmp = new BitmapData(width, height);
		_lastBmp = null;

		_currentX = 0;
		_currentY = 0;
		
		var numPixels : Number = width * height;
		_minMoved = numPixels * _percentMinMoved / 100;
		_maxMoved = numPixels * _percentMaxMoved / 100;
	}

	public function get bitmapData() : BitmapData {
		return _calcBmp;
	}

	public function get currentX() : Number {
		return _currentX;
	}

	public function get currentY() : Number {
		return _currentY;
	}

	public function get width() : Number {
		return _width;
	}

	public function get height() : Number {
		return _height;
	}

	public function capture(video : Video) : void {

		var bmp : BitmapData = new BitmapData(_width, _height);
		var scaleX : Number = _width / video.width;
		var scaleY : Number = _height / video.height;
		bmp.draw(video, new Matrix(scaleX, 0, 0, scaleY) );

		if (_lastBmp != null) {
			calc(_lastBmp, bmp);
		}

		_lastBmp = bmp;
	}

	private function calc(bmp1 : BitmapData, bmp2 : BitmapData) : void {

		var x : int;
		var y : int;

		_calcBmp.fillRect(new Rectangle(0, 0, _width, _height), 0xffffffff);
		for (y = 0; y < _height; y++) {
			for (x = 0; x < _width; x++) {
				var match : Boolean = matchColor(
					bmp1.getPixel(x, y), bmp2.getPixel(x, y) );
				if (!match) {
					_calcBmp.setPixel(x, y, 0x000000);
				}
			}
		}

		// LPF
		_calcBmp.applyFilter(_calcBmp,
			new Rectangle(0, 0, _width, _height),
			new Point(0, 0),
			new BlurFilter(2, 2) );

		var numMoved : int = 0;
		var moveX : Number = 0;
		var moveY : Number = 0;
		
		for (y = 0; y < _height; y++) {
			for (x = 0; x < _width; x++) {
				var value : int = _calcBmp.getPixel(x, y) & 0xff;
				if (value < _moveThreshold) {
					moveX += x;
					moveY += y;
					numMoved++;
				}
			}
		}
		
		if (_minMoved <= numMoved && numMoved <= _maxMoved) {

			_currentX = moveX / numMoved;
			_currentY = moveY / numMoved;

			dispatchEvent(new Event(Event.CHANGE) );			
		}
	}
			
	private function matchValue(value : int) : Boolean {
		return -_matchThreshold <= value && value <= _matchThreshold;
	}

	private function matchColor(color1 : uint, color2 : uint) : Boolean {
		var rgb1 : Array = getRGB(color1);
		var rgb2 : Array = getRGB(color2);
		return matchValue(rgb1[0] - rgb2[0])
			|| matchValue(rgb1[1] - rgb2[1])
			|| matchValue(rgb1[2] - rgb2[2]);
	}

	private static function getRGB(color : uint) : Array {
		return [(color >>> 16) & 0xff, (color >>> 8) & 0xff, color & 0xff];
	}
}