// forked from minon's くまの人メイカー(全自動版) // forked from fumix's あの人メイカー(全自動版) // 1. イケてる自分の顔をwebカメラに映す。 // 2. SAVEボタンではいチーズ! // // ほんとはsaqooshaさんのクマ帽子の画像でやりたいけど画像ない・・・ // ↓ // くまでやったよ! // スケールまわりだいぶ適当、とりあえずくまに変えただけ。ゴミだらけ。 // ↓ // 角度と拡大縮小、たぶんそれなりにちゃんと対応してるいる…はず(俺の顔 // 顔ラボ:顔検出WebAPI仕様 // http://kaolabo.com/webapi/spec package { import com.bit101.components.PushButton; import mx.graphics.codec.JPEGEncoder; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; import flash.display.LoaderInfo; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.events.TimerEvent; import flash.geom.Matrix; import flash.geom.Point; import flash.media.Camera; import flash.media.Video; import flash.net.URLLoader; import flash.net.URLRequest; import flash.net.URLRequestMethod; import flash.system.LoaderContext; import flash.text.TextField; import flash.utils.ByteArray; import flash.utils.Timer; /** * @author fumix */ [SWF(backgroundColor="#000000", frameRate="31", width="465", height="465")] public class AnohitoMaker extends Sprite { private var _camera : Camera; private var _w : int; private var _h : int; private var _video : Video; private var _startScale : Number; private var _startPoint : Point; private var _kuma : Sprite; private var _megane : Sprite; private var _referenceObject : Sprite; private var _btn : PushButton; private var _timer : Timer; private var _count : int; private var _xml:XML; private const APIURL : String = 'http://www.planet-ape.net/wonderfl/kaolabo.php'; /** * コンストラクタ */ public function AnohitoMaker() { if (stage) initialize(); else addEventListener(Event.ADDED_TO_STAGE, initialize); } /** * 初期化 * @param event */ private function initialize(event : Event = null) : void { removeEventListener(Event.ADDED_TO_STAGE, initialize); //プロパティの初期化 _startPoint = new Point(); //背景 _w = stage.stageWidth; _h = stage.stageHeight; var bmd : BitmapData = new BitmapData(_w, _h, true, 0x000000); addChild(new Bitmap(bmd)); //webカメラ _camera = Camera.getCamera(); //カメラあり if(_camera != null) { setupCamera(); //カメラ無し } else { var txt : TextField = new TextField(); txt.textColor = 0xFFFFFF; txt.text = 'カメラ無し'; addChild(txt); } //あの画像読み込み var url : String = "http://labs.minomix.net/kuma/kuma.png"; var loader : Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadCompleteHandler); loader.load(new URLRequest(url), new LoaderContext(true)); //保存ボタン _btn = new PushButton(this, 0, 0, 'capture', buttonClickHandler); } /** * ボタンクリック * @param event */ private function buttonClickHandler(event : MouseEvent) : void { //タイマーハンドラ(カウントダウン) /* _count = 3; _btn.label = String(_count); _timer = new Timer(1000, 3); _timer.addEventListener(TimerEvent.TIMER, timerHandler); _timer.start(); */ _btn.visible = false; requestAPIFacialRecognition(); } /** * 顔認識APIリクエスト */ private function requestAPIFacialRecognition() : void { //画像バイナリ生成 var cap : BitmapData = new BitmapData(_w, _h); cap.draw(_video); var enc : JPEGEncoder = new JPEGEncoder(80); var byteArray : ByteArray = enc.encode(cap); addChild(new Bitmap(cap)); //POSTリクエスト生成 var request:URLRequest = new URLRequest(APIURL); request.method = URLRequestMethod.POST; request.contentType = "image/jpeg"; request.data = byteArray; //リクエスト用ローダー生成 var loader:URLLoader = new URLLoader(request); loader.addEventListener(Event.COMPLETE, onLoaderComplate); //リクエスト実行 loader.load(request); } /** * リクエスト実行完了 * @param event */ private function onLoaderComplate(event : Event) : void { //スコア var score:Number = 0; //戻り値 _xml = deleteNameSpace(event.target.data); var faces : XMLList = _xml.faces[0].face; //顔認識されなかった場合 if(faces.length() < 1){ var txt : TextField = new TextField(); txt.textColor = 0xFFFFFF; txt.text = 'no faces!'; addChild(txt); return; } //認識した顔からくまの位置とスケールを計算 var kuma_width : Number = 53;//くま画像から左右の眼の幅。 //認識した顔の左右の眼のx,y var faceLeftEye_x : Number = faces[0].elements('left-eye').@x; var faceLeftEye_y : Number = faces[0].elements('left-eye').@y; var faceRightEye_x : Number = faces[0].elements('right-eye').@x; var faceRightEye_y : Number = faces[0].elements('right-eye').@y; //左右の眼の座標から幅と高さ var faceEyeWidth : Number = faceLeftEye_x - faceRightEye_x; var faceEyeHeight : Number = faceLeftEye_y - faceRightEye_y; //左右の眼の距離 var faceEyeDistance : Number = Math.sqrt(faceEyeWidth * faceEyeWidth + faceEyeHeight * faceEyeHeight); //拡大率 var scale : Number = faceEyeDistance / kuma_width; //回転角度 var rot : Number = Math.atan2(faceEyeHeight, faceEyeWidth); _kuma.scaleX = _kuma.scaleY = scale; _kuma.rotation = rot * 180 / Math.PI; _kuma.x = faceRightEye_x + faceEyeWidth / 2; if(faceRightEye_y > faceLeftEye_y) { _kuma.y = faceLeftEye_y - faceEyeHeight / 2; } else { _kuma.y = faceRightEye_y + faceEyeHeight / 2; } addChild(_kuma); } /** * 名前空間を削除します * @param オリジナルストリング(XML形式) * @return namespace宣言を取り去ったXML */ private function deleteNameSpace(xmlText : String) : XML { // remove the namespaces from the string representation of the XML xmlText = xmlText.replace(new RegExp("xmlns[^\"]*\"[^\"]*\"", "gi"), ""); xmlText = xmlText.replace(new RegExp("xsi[^\"]*\"[^\"]*\"", "gi"), ""); // set the string rep. of the XML back to real XML return new XML(xmlText); } /** * タイマーハンドラ(カウントダウン) * @param event */ private function timerHandler(event : TimerEvent) : void { _count--; _btn.label = String(_count); if(_count == 0) { _btn.visible = false; requestAPIFacialRecognition(); } } /** * 画像読み込み完了 * @param event */ private function loadCompleteHandler(event : Event) : void { var content : Bitmap = LoaderInfo(event.target).content as Bitmap; var bmd : BitmapData = content.bitmapData; var bmd_kuma : BitmapData = new BitmapData(320, 320, true, 0x00FFFFFF); //くま bmd_kuma.draw(bmd); var bm_kuma : Bitmap = new Bitmap(bmd_kuma); bm_kuma.x = -160; bm_kuma.y = -189; _kuma = new Sprite(); _kuma.addChild(bm_kuma); } /** * webカメラセットのアップ */ private function setupCamera() : void { _camera.setMode(Math.floor(_w / 2), Math.floor(_h / 2), 15); _video = new Video(_w, _h); _video.attachCamera(_camera); addChild(_video); } } } くまの人メイカー(全自動版)角度と拡大/縮小