有機ELよりも薄い紙TV
Flexで有機ELの薄さなんて目じゃない厚さが紙のTVを作成しました。
動作ムービーはこちら
http://jp.youtube.com/watch?v=oczVc3YbN-w
赤色抽出+ラベリング+自由変換でできます。
赤色抽出はこちら
http://www.hatayan.org/weblog/archives/2005/11/30/123132.php
ラベリングはこちら
http://d.hatena.ne.jp/nitoyon/20071003/as3_labeling
自由変形はこちら
http://www.rubenswieringa.com/code/as3/flex/DistortImage/
を参考にしました。
TVとして認識させる方法
こんな感じに紙に4点赤い印をつけます。
これだけでOK
まだまだいろいろと課題があって、肌色も抽出されてしまう場合があるのと、ポイントが交差してしまう場合があるのでその処理が必要です。
ソースはこちら
途中冗長的な部分があります(汗
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()"> <mx:Script> <![CDATA[ import org.flashsandy.display.*; //カメラの作成 private var camera:Camera; private function init():void{ //カメラの設定 camera = Camera.getCamera(); if (camera != null) { camera.setQuality(0, 95); camera.setMode(640 , 480 , 60 , true ); camera.setMotionLevel(0); myFlv.attachCamera( camera ); camera.addEventListener(ActivityEvent.ACTIVITY , onActive); } else { trace("You need a camera."); } myFlv2.width = myFlv.width; myFlv2.height = myFlv.height; myFlv2.play(); } //カメラアクティブイベント private function onActive( e:ActivityEvent ):void{ this.addEventListener( Event.ENTER_FRAME , getPoint ); } //ポイントの取得と画像の変換 private var distortion:DistortImage = new DistortImage(500, 375, 3, 3); private function getPoint(e:Event):void{ //赤色抽出 //http://www.hatayan.org/weblog/archives/2005/11/30/123132.phpがオススメ var my_bd:BitmapData = new BitmapData( myFlv.width , myFlv.height ); var green_bd:BitmapData = new BitmapData( myFlv.width , myFlv.height ); var blue_bd:BitmapData = new BitmapData( myFlv.width , myFlv.height ); my_bd.draw(myFlv); green_bd.copyChannel( my_bd , my_bd.rect , new Point() , 2 , 1 ); blue_bd.copyChannel( my_bd , my_bd.rect , new Point() , 3 , 1 ); blue_bd.draw( green_bd, new Matrix(), new ColorTransform(), 'lighten'); my_bd.draw( blue_bd , new Matrix(), new ColorTransform(), 'subtract'); my_bd.applyFilter( my_bd , my_bd.rect , new Point() , myBlur ); my_bd.threshold( my_bd , my_bd.rect , new Point() , '>' , 0xff500000 , 0xffffffff ); my_bd.threshold( my_bd , my_bd.rect , new Point() , '!=', 0xffffffff , 0xff000000 ); //赤色があるところを検出 var rect:Rectangle =my_bd.getColorBoundsRect(0xffffffff , 0xffffffff , true ); //ラベリング var label:Array = new Array(); var lno:uint = 0xffffff00; var i:int = 0; for (var x:int = 0; x < my_bd.width; x++) { for (var y:int = 0; y < my_bd.height; y++) { if (my_bd.getPixel(x, y) == 0xFFFFFF) { // 白色の場合 lno += 30; label[i] = lno; i++; my_bd.floodFill(x , y, lno ); } } } var pointNew:Array = new Array(); //ポイントを線でつなぐ //この辺は上のfor文とあわせてもOKだと思う。 myCanvas.graphics.clear(); //グリッドの表示//myCanvas.graphics.lineStyle( 1 , 0xffff0000 , 1.0 , false ); var rect:Rectangle = my_bd.getColorBoundsRect( 0xffffffff , label[0] , true ); myCanvas.graphics.moveTo( rect.x + rect.width/2 , rect.y + rect.height/2 ); for( i = 0 ; i < label.length ; i++ ){ rect = my_bd.getColorBoundsRect( 0xffffffff , label[i] , true ); pointNew[i] = new Point( rect.x + 5 , rect.y + 5); myCanvas.graphics.lineTo( rect.x + rect.width/2 , rect.y + rect.height/2 ); } rect = my_bd.getColorBoundsRect( 0xffffffff , label[0] , true ); myCanvas.graphics.lineTo( rect.x + rect.width/2 , rect.y + rect.height/2 ); myCanvas.graphics.endFill(); myImage.source = new Bitmap( my_bd ); var bd:BitmapData = new BitmapData( myFlv.width , myFlv.height ); bd.draw( myFlv2 ); //自由変形 if( pointNew.length == 4 ){ distortion.setTransform( myCanvas.graphics , bd , pointNew[1] , pointNew[3] , pointNew[2] , pointNew[0] ); } } ]]> </mx:Script> <mx:BlurFilter id="myBlur" blurX="3" blurY="3"/> <mx:VideoDisplay x="10" y="10" width="640" height="480" id="myFlv"/> <mx:Image x="694" y="10" width="258" height="216" id="myImage"/> <mx:Canvas x="10" y="10" width="676" height="576" id="myCanvas"/> <mx:VideoDisplay x="675" y="331" source="test.flv" autoPlay="true" id="myFlv2" visible="false" complete="{myFlv2.play();}" /> </mx:Application>
作ってて一人ですごい感激してしまった(>_<)