package { import fl.controls.*; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.display.Loader; import flash.display.Shape; import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import flash.filters.ColorMatrixFilter; import flash.geom.Matrix; import flash.geom.Point; import flash.geom.Rectangle; import flash.media.Camera; import flash.media.Video; import flash.net.URLRequest; import flash.text.TextField; [SWF(width="640", height="480")] public class Webcam extends Sprite { // private var bw_matrix:Array,con_mat:Array,alpha_invert_matrix:Array; // private var bw_filt:ColorMatrixFilter,con_filt:ColorMatrixFilter,alpha_filt:ColorMatrixFilter ; // used by contrast filter // private var g:Number = -2; // private var r:Number = -2; // private var b:Number = -2; // video size private var vid_w:int = 640; private var vid_h:int = 480; // furniture icon scaling private var icon_scale:Number = .4; private var icon_list:Array; // magic numbers, determining icon movement private var a:uint = 1; private var k:int = 3; private var i:int; private var distortion:DistortImage; private var top_off:int; // UI thingies private var distSlider:Slider; private var treshSlider:Slider; private var alpha_cb:CheckBox; private var orig_cb:CheckBox; // private var active_tb:TextField; // private var passive_tb:TextField; private var dist_shape:Shape; private var hc_bmd:BitmapData; // private var hc_bmd2:BitmapData; private var origo:Point; // cointainer for the furniture private var shape_container:Array; // bitmaps used, along with a variable to hold the currently active piece of furniture private var bmd_1:BitmapData; private var bitm_1:Bitmap; private var video1:Video; private var j:int; private var your_it:Bitmap; private var yout_it_timer:uint; private var sourceRect:Rectangle; private var white_bmd:BitmapData; private var flipVerticalMatrix:Matrix; // the grid private var grid:Shape; // colour of icons private var colour_active:uint = 0xFFF7A005; private var colour_passive:uint = 0xFF04d523; // number of seconds a given piece of furniture is "it" private var active_seconds:uint = 4; /** * Constructor * */ public function Webcam() { origo = new Point(0,0); distortion = new DistortImage(vid_w, vid_h, 1, 1); white_bmd = new BitmapData(vid_w, vid_h, true, 0xFFFFFFFF); initShapes(); initUI(); initGrid(); initFilters(); dist_shape = new Shape(); var cam:Camera = Camera.getCamera(); video1 = new Video(vid_w,vid_h); video1.attachCamera(cam); hc_bmd = new BitmapData(vid_w, vid_h, true, 0xFFFFFFFF); // hc_bmd2 = new BitmapData(vid_w, vid_h, true, 0xFFFFFFFF); sourceRect = new Rectangle(0, 0, vid_w, vid_h); bmd_1 = new BitmapData(vid_w, vid_w, false, 0xFFFFFFFF); bitm_1 = new Bitmap(); bitm_1.bitmapData = bmd_1; this.addChildAt(bitm_1,this.getChildIndex(distSlider)); addEventListener(Event.ENTER_FRAME, onEnterFrame); distSliderChanged(null); j = 151; your_it = shape_container[0]; yout_it_timer=0; } /** * Main event-loop function * */ public function onEnterFrame(ev:Event):void { // draws a flipped version of the cam feed onto out bitmap hc_bmd.draw(video1, flipVerticalMatrix, null,null, null, false); // if enabled, this permits distortion of the image to compensate for offset camera positioning // hc_bmd.draw(dist_shape); // this does a binary threshold-analysis and sticks the result in the alpha-channel for easy hit-detection hc_bmd.threshold(hc_bmd,sourceRect,origo,">",0xFF000000 + (treshSlider.value/100)*0x00FFFFFF,0x00000000 /* ,0xFF000000 */); // there's a bug somewhere in this bit, it's used to show the original feed or the alpha-channel for debugging and tuning if(orig_cb.selected) { bmd_1.copyPixels(hc_bmd,sourceRect,origo); } else{ if(alpha_cb.selected) { bmd_1.copyChannel(hc_bmd,sourceRect,origo,BitmapDataChannel.ALPHA,BitmapDataChannel.GREEN); } // else // { // hc_bmd.fillRect(hc_bmd.rect,0xFFFFFFFF); // } } // do we need to find a new piece of furniture to move around? if(j>active_seconds*30 || your_it == null) { //find a new one j=0; your_it = null; for each(var i_shape:Bitmap in shape_container) { if(hit_test(i_shape)) { // change current selection your_it = i_shape; // update colours i_shape.bitmapData.threshold(i_shape.bitmapData,i_shape.getRect(i_shape),new Point(),'>',0x01010101,colour_active); for each(var j_shape:Bitmap in shape_container) { if(j_shape != i_shape) { j_shape.bitmapData.threshold(j_shape.bitmapData,j_shape.getRect(j_shape),new Point(),'>',0x01010101,colour_passive); } } break; } } } // move the currently selected furniture-piece if necessary if(your_it != null) { try_move(your_it); } j++ } /** * this sets up a filter that flips the image on its head */ private function initFilters():void { flipVerticalMatrix = new Matrix(); flipVerticalMatrix.scale(1,-1); flipVerticalMatrix.translate(0,vid_h); } /** * Handles any distortion of the image (commented out currently) */ private function distSliderChanged(e:Event):void { dist_shape.graphics.clear(); top_off = (vid_w/2)*(distSlider.value/100)-vid_w/2; distortion.setTransform(dist_shape.graphics, hc_bmd, origo, new Point(vid_w,0), new Point(vid_w-top_off,vid_h), new Point(top_off,vid_h)); } // private function toggle_orig_cb(e:Event):void // { // if(!orig_cb.selected) // { // bitm_1.bitmapData = white_bmd; // } // else // { // bitm_1.bitmapData = bmd_1; // } // } private function toggle_alpha_cb(e:Event):void { if(!alpha_cb.selected && !orig_cb.selected) { bitm_1.bitmapData = white_bmd; } else { bitm_1.bitmapData = bmd_1; } } private function toggleUI(e:KeyboardEvent):void { if(e.keyCode == 32) //spacebar { distSlider.visible = !distSlider.visible; treshSlider.visible = !treshSlider.visible; alpha_cb.visible = !alpha_cb.visible; orig_cb.visible = !orig_cb.visible; } } private function initUI():void { distSlider = new Slider(); distSlider.setSize(vid_h/2,20); distSlider.direction = SliderDirection.VERTICAL; distSlider.move(vid_w,0); distSlider.addEventListener(Event.CHANGE,distSliderChanged); distSlider.maximum = 100; distSlider.value = 100; this.addChild(distSlider); treshSlider = new Slider(); treshSlider.setSize(vid_h/2,20); treshSlider.direction = SliderDirection.VERTICAL; treshSlider.move(vid_w,vid_h/2); treshSlider.maximum = 100; treshSlider.value = 50; this.addChild(treshSlider); alpha_cb = new CheckBox(); alpha_cb.label = 'Show alpha'; alpha_cb.y = vid_h - 50; alpha_cb.addEventListener(Event.CHANGE, toggle_alpha_cb); this.addChild(alpha_cb); orig_cb = new CheckBox(); orig_cb.label = 'Show original'; orig_cb.y = vid_h - 70; orig_cb.addEventListener(Event.CHANGE, toggle_alpha_cb); this.addChild(orig_cb); stage.addEventListener(KeyboardEvent.KEY_DOWN,toggleUI); } private function initShapes():void { icon_list = ['http://www.itu.dk/~friism/files/MoY/chair.png' /*,'green/chair.png','green/easychair.png','green/paper.png','green/plant.png','green/rug.png','green/tv.png','green/turntable.png','green/lamp.png','green/table.png'*/]; shape_container = new Array(); for each(var shape_string:String in icon_list) { var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteListerner); loader.load(new URLRequest(shape_string)); } } private function loaderCompleteListerner(e:Event):void { var loaded_bm:Bitmap = Bitmap(e.target.loader.content); loaded_bm.scaleX = loaded_bm.scaleY = icon_scale; loaded_bm.x = getRandom(50,vid_w-50); loaded_bm.y = getRandom(50,vid_h-50); loaded_bm.smoothing = true; shape_container.push(loaded_bm); this.addChild(loaded_bm); } private function hit_test(a_shape:Bitmap):Boolean { return hc_bmd.hitTest(origo,a,a_shape.getRect(bitm_1)) } private function try_move(a_shape:Bitmap):void { i=1; while(hit_test(a_shape) && i<100) { a_shape.x = Math.min(a_shape.x + k*i,vid_w-40); //E if(hit_test(a_shape)) { a_shape.x = Math.max(a_shape.x - k*i,20); a_shape.y = Math.min(a_shape.y + k*i,vid_h-40); }//S else { return; } if(hit_test(a_shape)) { a_shape.x = Math.max(a_shape.x - k*i,20); a_shape.y = Math.max(a_shape.y - k*i,20); }//W else { return; } if(hit_test(a_shape)) { a_shape.x = Math.min(a_shape.x + k*i,vid_w-40); a_shape.y = Math.max(a_shape.y - k*i,20); }//N else { return; } if(hit_test(a_shape)) { a_shape.y = Math.min(a_shape.y + k*i,vid_h-40);//beginning } else { return; } i+=1; } } private function getRandom( minVal:Number, maxVal:Number):Number{ return minVal + Math.random() * (maxVal - minVal); } private function initGrid():void { grid = new Shape(); addChild(grid); grid.graphics.lineStyle(1,colour_active,.25); grid.graphics.moveTo(.25*vid_w,0); grid.graphics.lineTo(.25*vid_w,vid_h); grid.graphics.moveTo(.5*vid_w,0); grid.graphics.lineTo(.5*vid_w,vid_h); grid.graphics.moveTo(.75*vid_w,0); grid.graphics.lineTo(.75*vid_w,vid_h); grid.graphics.moveTo(0,vid_h*1/3); grid.graphics.lineTo(vid_w,vid_h*1/3); grid.graphics.moveTo(0,vid_h*2/3); grid.graphics.lineTo(vid_w,vid_h*2/3); } } }