顔領域抽出でモーフィングっぽいの
顔領域抽出でモーフィングっぽいの
*
* ImagePipes Concept
* http://imagepipes.kayac.com/
* を使って顔領域を抽出し、
* 顔領域がつながることを優先して、フェードイン・アウト。
* 写真によっては結構見れるものになっていると思う。
*
* smileとかfaceとか工夫しても、
* 検索して取り出した写真に正面の顔が写ってないことが多い。
* 「girl tokyo」とか表示されているのに、うまく取得できない時用の
* おじさんが写っていることも多いけど、ご容赦。
*
* =====
* 1)YahooPipes経由でFlickrから、「girl tokyo」の検索結果を取得
* 2)偏ると面白くないので、ランダムに画像のURLを取り出す。
* 3)ImagePipesから、画像毎の顔領域を取得
* 4)うまく取れない場合(写真に正面の顔が写ってないことも少なくない)、
* あらかじめ用意した、うまく取れることがわかっている画像で再取得。
* 5)顔領域がつながることを優先して、変形させながらフェードイン・アウト。
*
*
/**
* Copyright umhr ( http://wonderfl.net/user/umhr )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/36YK
*/
/*
* 顔領域抽出でモーフィングっぽいの
*
* ImagePipes Concept
* http://imagepipes.kayac.com/
* を使って顔領域を抽出し、
* 顔領域がつながることを優先して、フェードイン・アウト。
* 写真によっては結構見れるものになっていると思う。
*
* smileとかfaceとか工夫しても、
* 検索して取り出した写真に正面の顔が写ってないことが多い。
* 「girl tokyo」とか表示されているのに、うまく取得できない時用の
* おじさんが写っていることも多いけど、ご容赦。
*
* =====
* 1)YahooPipes経由でFlickrから、「girl tokyo」の検索結果を取得
* 2)偏ると面白くないので、ランダムに画像のURLを取り出す。
* 3)ImagePipesから、画像毎の顔領域を取得
* 4)うまく取れない場合(写真に正面の顔が写ってないことも少なくない)、
* あらかじめ用意した、うまく取れることがわかっている画像で再取得。
* 5)顔領域がつながることを優先して、変形させながらフェードイン・アウト。
*
* */
package{
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Loader;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.MouseEvent;
import flash.filters.DropShadowFilter;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.system.LoaderContext;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import com.adobe.serialization.json.*;
[SWF(width = "465", height = "465", backgroundColor = 0, frameRate = "30")]
public class Main extends Sprite{
private var layerFaces:Sprite = new Sprite;
private var faceRectangle_array:Array;
private var imgRectangle_array:Array;
private var img_array:Array;
private var loadedImgCount:int;
private var isLine:Boolean;
private var pipesurl:String = "http://pipes.yahooapis.com/pipes/pipe.run?_id=4Hfb79Zo3BGT9IDkxAnzeQ&_render=json&urls=";
private var media:Namespace;
private var credit:Object;
private var credit_array:Array = [["http://www.matzmtok.com/wonderfl/checkmate/image/bush.png", " GEORGE W. BUSH", "http://www.whitehouse.gov/about/presidents/georgewbush/"], ["http://www.matzmtok.com/wonderfl/checkmate/image/obama.png", "Barack H. Obama", "http://www.whitehouse.gov/administration/president_obama/"], ["http://farm4.static.flickr.com/3154/2883492436_c962012edc.jpg", "Emily in the ball pool", "http://www.flickr.com/photos/gingerfuhrer/2883492436/"], ["http://farm1.static.flickr.com/181/431971314_4e6ede5188.jpg", "Polka Dotted Shirt Boy", "http://www.flickr.com/photos/foundphotoslj/431971314/"], ["http://mztm.heteml.jp/umhr/wonderfl/tumblr_koxl0xJLqx1qzm8kto1_500.jpg", "麻生内閣総理大臣記者会見", "http://www.kantei.go.jp/jp/asophoto/2009/04/10kaiken.html"]];
private var creditFixed_array:Array;
private var inputTf:TextField;
private var count:int;
private var photoCount0:int;
private var photoCount1:int;
private var creditTf:TextField;
private var backSprite:Sprite;
private var frontSprite:Sprite;
public function Main():void
{
addChild(layerFaces);
addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void { isLine = !isLine } );
inputTf = new TextField();
inputTf.x = 32;
inputTf.y = 445;
inputTf.border = true;
inputTf.borderColor = 0xFFFFFF;
inputTf.width = 366;
inputTf.height = 19;
inputTf.textColor = 0xFFFFFF;
inputTf.text = "girl tokyo";
inputTf.type = "input";
inputTf.filters = [new DropShadowFilter()];
addChild(inputTf)
var btnSp:Sprite = new Sprite();
btnSp.graphics.beginFill(0xFFFFFF, 0.8);
btnSp.graphics.drawRoundRect(400, 445, 32, 19, 8, 8);
btnSp.buttonMode = true;
addChild(btnSp);
btnSp.addEventListener(MouseEvent.CLICK, reStart );
start();
}
private function reStart(e:MouseEvent):void {
removeEventListener(Event.ENTER_FRAME,ENTER_FRAME);
while (layerFaces.numChildren) {
layerFaces.removeChildAt(0);
}
start();
}
public function start():void
{
//yahoopipes経由でFlckrの写真リストを取得
var myLoader:URLLoader = new URLLoader();
myLoader.addEventListener (Event.COMPLETE, onCompStep1);
myLoader.addEventListener(IOErrorEvent.IO_ERROR, IO_ERROR);
myLoader.load(new URLRequest("http://pipes.yahooapis.com/pipes/pipe.run?_id=Tkmh9Xn63RGd9RQo37Vd_w&_render=rss&num=40&q="+encodeURI(inputTf.text)));
}
public function IO_ERROR(e:IOErrorEvent):void {
e.target.removeEventListener (Event.COMPLETE, onCompStep1);
inputTf.text = "Yahoo Pipesとの接続がうまく行ってないみたい。また来てね。";
}
public function onCompStep1(e:Event = null, is2nd:Boolean = false):void {
trace("===")
var URLs:Array = [];
if (e) {
//写真リストの取得の場合は、XMLの内容を取得する。
var loader:URLLoader = e.target as URLLoader;
loader.removeEventListener(Event.COMPLETE, onCompStep1);
var xml:XML = new XML(loader.data);
media = new Namespace("http://search.yahoo.com/mrss/");
default xml namespace = media;
credit = { };
for ( var i:int = 0; i < xml.channel.item.length(); i++ ) {
if (Math.random() < 0.9) { continue };
var url:String = String(xml.channel.item[i].media::group.media::content.@url).replace("http://", "http://farm" + xml.channel.item[i].media::group.@farm + ".").replace("_m", "");
URLs.push(url);
credit[url] = [String(xml.channel.item[i].title), String(xml.channel.item[i].link)];
}
}
//とりあえず顔領域抽出できる確立の高い画像を追加。
for ( var j:int = 0; j < 5; j++ ) {
URLs.push(credit_array[j][0]);
credit[credit_array[j][0]] = [credit_array[j][1], credit_array[j][2]];
}
URLs.length = 4;
//yahooPipes経由でImagePipesの顔領域抽出
var myURLLoader:URLLoader = new URLLoader;
myURLLoader.addEventListener(Event.COMPLETE,onCompStep2);
myURLLoader.load( new URLRequest(pipesurl + encodeURIComponent(URLs.join(','))) );
}
private function onCompStep2(e:Event):void {
//顔領域抽出が有効なものが2つ以上あれば、
//その写真を読み込んで、次へ
//2つ未満ならやりなおし。
e.target.removeEventListener(Event.COMPLETE, onCompStep2);
var decoder:JSONDecoder = new JSONDecoder(e.target.data);
var json:Object = decoder.getValue();
var items:Array = json.value.items;
var loadedCount:int = 0;
loadedImgCount = 0;
img_array = [];
imgRectangle_array = [];
creditFixed_array = [];
faceRectangle_array = [];
for ( var i:int = 0; i < items.length; i++ ) {
if (items[i].rects && items[i].rects.length) {
trace("!!",items[i].url)
faceRectangle_array.push(new Rectangle(Number(items[i].rects[0].x), Number(items[i].rects[0].y), Number(items[i].rects[0].width), Number(items[i].rects[0].height)));
var myLoader:Loader = new Loader;
myLoader.name = String(loadedCount);
myLoader.load( new URLRequest(items[i].url),new LoaderContext(true));
myLoader.contentLoaderInfo.addEventListener (Event.COMPLETE,onCompStep3);
loadedCount ++;
}else {
trace("??",items[i].url)
}
}
if (loadedCount < 2) {
onCompStep1(null, true);
}
}
private function onCompStep3(e:Event):void {
loadedImgCount ++;
var num:int = e.target.loader.name;
e.target.loader.removeEventListener(Event.COMPLETE, onCompStep3);
var rect:Rectangle = new Rectangle();
rect.x = e.target.content.x+num*300;
rect.y = e.target.content.x;
rect.width = e.target.content.width;
rect.height = e.target.content.height;
img_array[num] = e.target.content;
imgRectangle_array[num] = rect;
creditFixed_array[num] = "<a href='"+credit[String(e.target.url)][1]+"'>"+credit[String(e.target.url)][0]+"</a>";
if (loadedImgCount == faceRectangle_array.length) {
drawImg();
};
}
private function drawImg():void {
backSprite = new Sprite();
layerFaces.addChild(backSprite);
frontSprite = new Sprite();
layerFaces.addChild(frontSprite);
creditTf = new TextField();
creditTf.width = 465;
creditTf.height = 21;
creditTf.textColor = 0xFFFFFF;
creditTf.htmlText = creditFixed_array[1];
creditTf.filters = [new DropShadowFilter()];
layerFaces.addChild(creditTf);
count = 0
photoCount0 = 0;
photoCount1 = 1;
addEventListener(Event.ENTER_FRAME, ENTER_FRAME);
}
private function ENTER_FRAME(e:Event = null):void {
count ++;
while (frontSprite.numChildren) {
frontSprite.removeChildAt(0);
}
while (backSprite.numChildren) {
backSprite.removeChildAt(0);
}
backSprite.addChild(morph(1-count/100,photoCount1,photoCount0));
frontSprite.addChild(morph(count/100,photoCount0,photoCount1));
frontSprite.alpha = (1-count/100);
if(count == 100){
photoCount0 = (photoCount0 + 1) % loadedImgCount;
photoCount1 = (photoCount1 + 1) % loadedImgCount;
creditTf.textColor = 0xFFFFFF;
creditTf.htmlText = creditFixed_array[photoCount1];
count = 0;
}
}
private function morph(num:Number,p0:int,p1:int):Sprite{
var wh_array:Array = [1, 1, 1, 1, 1, 1];
wh_array[0] = (1-num)+num*(faceRectangle_array[p1].x / faceRectangle_array[p0].x);
wh_array[1] = (1-num)+num*(faceRectangle_array[p1].width / faceRectangle_array[p0].width);
wh_array[2] = (1-num)+num*((imgRectangle_array[p1].width - faceRectangle_array[p1].x - faceRectangle_array[p1].width) / (imgRectangle_array[p0].width - faceRectangle_array[p0].x - faceRectangle_array[p0].width));
wh_array[3] = (1-num)+num*(faceRectangle_array[p1].y / faceRectangle_array[p0].y);
wh_array[4] = (1-num)+num*(faceRectangle_array[p1].height / faceRectangle_array[p0].height);
wh_array[5] = (1-num)+num*((imgRectangle_array[p1].height - faceRectangle_array[p1].y - faceRectangle_array[p1].height) / (imgRectangle_array[p0].height - faceRectangle_array[p0].y - faceRectangle_array[p0].height));
return polygonmesh(imgRectangle_array[p0], faceRectangle_array[p0], img_array[p0], wh_array);
}
private function polygonmesh(imgRect:Rectangle,faceRect:Rectangle,bmp:Bitmap,wh_array:Array):Sprite {
var mySprite:Sprite = new Sprite();
var myTexture:BitmapData = new BitmapData(imgRect.width, imgRect.height);
myTexture.draw(bmp,new Matrix(imgRect.width/bmp.width,0,0,imgRect.height/bmp.height),null,null,null);
var vertices:Vector.<Number> = new Vector.<Number>();
var indices:Vector.<int> = new Vector.<int>();
var uvtData:Vector.<Number> = new Vector.<Number>();
var tempRect:Rectangle = new Rectangle(0, 0, faceRect.x, faceRect.y);
var _x:Number = 0;
mySprite.addChild(drawTexture(tempRect, myTexture,[_x,0,wh_array[0],wh_array[3]]));
_x += wh_array[0] * tempRect.width;
tempRect = new Rectangle(faceRect.x, 0, faceRect.width, faceRect.y);
mySprite.addChild(drawTexture(tempRect, myTexture,[_x,0,wh_array[1],wh_array[3]]));
_x += wh_array[1] * tempRect.width;
tempRect = new Rectangle(faceRect.x+faceRect.width,0,myTexture.width-(faceRect.x+faceRect.width),faceRect.y);
mySprite.addChild(drawTexture(tempRect, myTexture,[_x,0,wh_array[2],wh_array[3]]));
var _y:Number = wh_array[3] * tempRect.height;
tempRect = new Rectangle(0,faceRect.y,faceRect.x,faceRect.height);
_x = 0;
mySprite.addChild(drawTexture(tempRect, myTexture,[_x,_y,wh_array[0],wh_array[4]]));
_x += wh_array[0] * tempRect.width;
tempRect = new Rectangle(faceRect.x,faceRect.y,faceRect.width,faceRect.height);
mySprite.addChild(drawTexture(tempRect, myTexture,[_x,_y,wh_array[1],wh_array[4]]));
_x += wh_array[1] * tempRect.width;
tempRect = new Rectangle(faceRect.x+faceRect.width,faceRect.y,myTexture.width-(faceRect.x+faceRect.width),faceRect.height);
mySprite.addChild(drawTexture(tempRect, myTexture,[_x,_y,wh_array[2],wh_array[4]]));
_y += wh_array[4] * tempRect.height;
_x = 0;
tempRect = new Rectangle(0,faceRect.y+faceRect.height,faceRect.x,myTexture.height-(faceRect.y+faceRect.height));
mySprite.addChild(drawTexture(tempRect, myTexture,[_x,_y,wh_array[0],wh_array[5]]));
_x += wh_array[0] * tempRect.width;
tempRect = new Rectangle(faceRect.x,faceRect.y+faceRect.height,faceRect.width,myTexture.height-(faceRect.y+faceRect.height));
mySprite.addChild(drawTexture(tempRect, myTexture,[_x,_y,wh_array[1],wh_array[5]]));
_x += wh_array[1] * tempRect.width;
tempRect = new Rectangle(faceRect.x+faceRect.width,faceRect.y+faceRect.height,myTexture.width-(faceRect.x+faceRect.width),myTexture.height-(faceRect.y+faceRect.height));
mySprite.addChild(drawTexture(tempRect, myTexture, [_x, _y, wh_array[2], wh_array[5]]));
_x += wh_array[2] * tempRect.width;
_y += wh_array[5] * tempRect.height;
mySprite.x = (465 - _x) / 2;
mySprite.y = (465 - _y) / 2;
function drawTexture(tempRect:Rectangle, myTexture:BitmapData, wh_ar:Array):Shape {
var textureRect:Rectangle = new Rectangle(tempRect.x / myTexture.width, tempRect.y / myTexture.height, tempRect.width / myTexture.width, tempRect.height / myTexture.height);
var mySh:Shape = new Shape();
var myGraphics:Graphics = mySh.graphics;
if(isLine){
myGraphics.lineStyle(1, 0xFF);
}
// 三角形の頂点座標を加える(第1引数)
vertices = new Vector.<Number>();
indices = new Vector.<int>();
uvtData = new Vector.<Number>();
vertices.push(wh_ar[0], wh_ar[1]); // 頂点0
vertices.push(wh_ar[0]+wh_ar[2]*tempRect.width, wh_ar[1]); // 頂点1
vertices.push(wh_ar[0], wh_ar[1]+wh_ar[3]*tempRect.height); // 頂点2
vertices.push(wh_ar[0] + wh_ar[2] * tempRect.width, wh_ar[1] + wh_ar[3] * tempRect.height); // 頂点3
// 三角形の頂点番号の組合わせを加える(第2引数
indices.push(0, 1, 2); // 左上半分: 頂点0-1-2
indices.push(1, 2, 3); // 右下半分: 頂点1-2-3
// テクスチャマッピングのuv座標を加える(第3引数)
uvtData.push(textureRect.x, textureRect.y); // 頂点0
uvtData.push(textureRect.x+textureRect.width, textureRect.y); // 頂点1
uvtData.push(textureRect.x, textureRect.y+textureRect.height); // 頂点2
uvtData.push(textureRect.x+textureRect.width, textureRect.y+textureRect.height); // 頂点3
myGraphics.beginBitmapFill(myTexture);
myGraphics.drawTriangles(vertices, indices, uvtData);
myGraphics.endFill();
return mySh;
}
return mySprite;
}
}
}