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

forked from: Simple Camera Tracking

Get Adobe Flash player
by katian 11 Sep 2009
// forked from forresto's Simple Camera Tracking
package  
{    
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.media.Camera;
	import flash.media.Video;
	import flash.text.TextField;
	import flash.utils.ByteArray;

	
	public class FaceTrack extends Sprite
	{
		private var backwardsMatrix:Matrix;
		private var v:Video;
		private var vidmap:BitmapData;
		private var overlay:Sprite;
		private var obmp:BitmapData;
		private var targetRect:Rectangle;
		private var histo:Vector.<Vector.<Vector.<Number>>>;
		private var cam:Camera;
		private var lastPoint:Point;
		private var lpRect:Rectangle;
		private var going:Boolean;
		
		private var instructs:TextField;
		
		private static const TwoOverPI:Number = 2.0 / Math.PI;
		
		private var canvas:Sprite;
		private var bm:Bitmap;
				
		
		public function FaceTrack():void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			var left:String = "left";
			going = false;
			cam = Camera.getCamera();
			v = new Video(640, 480);
			v.attachCamera(cam);
			v.scaleX = -1;
			v.x = v.width;
			addChild(v);
			stage.addEventListener("click", doCapture);
			backwardsMatrix = new Matrix( -1, 0, 0, 1, v.width, 0);
			vidmap = new BitmapData(640, 480);

			canvas = new Sprite();
			canvas.transform.perspectiveProjection = this.transform.perspectiveProjection;
						
			bm = new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x00ffffff));
			bm.alpha = 0.5;
			addChild(bm);
			
			overlay = new Sprite();
			targetRect = new Rectangle(0, 0, 80, 80);
			addChild(overlay);
			
			instructs = new TextField();
			instructs.autoSize = left;
			instructs.background = true;
			instructs.backgroundColor = 0xffffff;
			instructs.text = "Click your face (or something else) to begin tracking.";
			instructs.x = stage.stageWidth / 2 - instructs.width / 2;
			instructs.y = stage.stageHeight / 2;
			addChild(instructs);
			
			obmp = new BitmapData(80, 80, false);

		}
		
		private function doCapture(e:Event):void {
			vidmap.draw(v, backwardsMatrix);
			var halfdim:int = 80 / 2;
			lastPoint = new Point(stage.mouseX, stage.mouseY);
			lpRect = new Rectangle(stage.mouseX - halfdim, stage.mouseY - halfdim, 80, 80);
			obmp.copyPixels(vidmap, lpRect, new Point());
			histo = new Vector.<Vector.<Vector.<Number>>>(16, true);
			for (var i:int = 0; i < 16; i++) {
				histo[i] = new Vector.<Vector.<Number>>(16, true);
				for (var j:int = 0; j < 16; j++) {
					histo[i][j] = new Vector.<Number>(16, true);
				}
			}
			getHisto(obmp);
			if (!going) {
				going = true;
				removeChild(instructs);
				addEventListener(Event.ENTER_FRAME, trackFrame);
			}
		}
		
		private function getHisto(bd:BitmapData):void {
			//histo = bd.histogram();
			var i:int, j:int, k:int;
			for (i = 0; i < 16; i++) {
				for (j = 0; j < 16; j++) {
					for (k = 0; k < 16; k++) {
						histo[i][j][k] = 0;
					}
				}
			}
			var ba:Vector.<uint> = bd.getVector(bd.rect);
			var r:int, g:int, b:int;
			var px:uint;
			var m:Number, n:Number;
			var stepY:Number = 1.0 / (80);
			var stepX:Number = 1.0 / (80);
			
			for (i = 0, m = -0.5; i < bd.height; i++, m+=stepY) {
				for (j = 0, n = -0.5; j < bd.width; j++, n+=stepX) {
					px = ba[i * bd.width + j];
					r = (px >> 20) & 0xf;
					g = (px >> 12) & 0xf;
					b = (px >>  4) & 0xf;
					histo[r][g][b]+= epachnikov(n,m);
				}
			}
		}
		
		private function epachnikov(xnorm:Number, ynorm:Number):Number {
			return TwoOverPI * (1 - (xnorm^2 + ynorm * ynorm));
			
		}
		private function drawOverlay(r:Rectangle):void {
			overlay.graphics.clear();
			overlay.graphics.lineStyle(3, 065895);
			overlay.graphics.drawCircle(r.x + r.width / 10, r.y + r.height / 2, r.width / 2);
		}
		
		private function trackFrame(event:Event):void {
			var i:int;
			var halfdim:int = 80 / 2;
			var weight:Number;
			var r:int, g:int, b:int;
			var xsum:Number;
			var ysum:Number;
			var cpix:uint;
			var px:Vector.<uint>;
			var newx:Number;
			var newy:Number;
			vidmap.lock();
			obmp.lock();
			vidmap.draw(v, backwardsMatrix);
			var weightsum:Number;
			var origin:Point = new Point();
            for (var q:int = 0; q < 20; q++){ //arbitrarily max iterations.
				obmp.copyPixels(vidmap, lpRect, origin);
				xsum = 0;
				ysum = 0;
				weightsum = 0;
				px = obmp.getVector(obmp.rect);
				i = 0;
				for (var n:int = -halfdim; i < 80; i++, n++) {
					for (var j:int = 0, m:int = -halfdim; j < 80; j++, m++) {
						cpix = px[i*80 +j];
						r = (cpix >> 20) & 0xf;
						g = (cpix >> 12) & 0xf;
						b = (cpix >> 4) & 0xf;
						weight = (histo[r][g][b]); // / numpx;
						//weight = properHisto[r][g][b];// / numpx;
						weightsum += weight;
						xsum += m * weight;
						ysum += n * weight;
					}
				}
				newx = xsum  / weightsum; // / sqnpx;
				newy = ysum  / weightsum; // sqnpx;
				//trace("newx: " + newx + ", newy: " + newy);
				lastPoint.x += Math.round(newx);
				lastPoint.y += Math.round(newy);
				if (lastPoint.x < halfdim) {
					lastPoint.x = halfdim;
				}else if (lastPoint.x > vidmap.width - halfdim) {
					lastPoint.x = vidmap.width - halfdim;
				}
				if (lastPoint.y < halfdim) {
					lastPoint.y = halfdim;
				}else if (lastPoint.y > vidmap.height - halfdim) {
					lastPoint.y = vidmap.height - halfdim;
				}
				lpRect.x = lastPoint.x - halfdim;
				lpRect.y = lastPoint.y - halfdim;
				if (newx*newx + newy*newy < 1) {
					break;
				}
				
			}	
			vidmap.unlock();
			obmp.unlock();

			targetRect.x = lastPoint.x - halfdim;
			targetRect.y = lastPoint.y - halfdim;
			drawOverlay(targetRect);

			bm.bitmapData.lock();
			bm.bitmapData.fillRect(bm.bitmapData.rect, 0x00000000);

			bm.bitmapData.unlock();

		}
		
		
		
	}
	
}