動きのある部分にパーティクル作成

動きのある部分にパーティクルを作成してみました。
こんな感じ
http://moeten.info/flex/20081004_OpenCanpasDemo2/bin-release/main.html

ほんとはお台場のソニーのメディアージュ(だったかな?)にあるビデオのエフェクトみたいなのを作りたいんだけど、やっぱまだまだ技術が足りない(@_@;)
作り方の簡単な説明。

手順

1.画像をマイフレームキャプチャ

nowbd.draw( myFlv , mat );

2.キャプチャ画像のエッジを取り出す

//エッジの抽出
var Con:ConvolutionFilter = new ConvolutionFilter(3,3);
Con.matrix = new Array(
             0, -1, 0,
            -1,  4, -1,
             0, -1, 0
        );
//Con.bias = 255;
nowbd.applyFilter( nowbd , nowbd.rect , new Point() , Con );

3.古い画像との差分を求める

bdArr[j-dnum].draw( bdArr[j] , null , null , "difference" );
bdArr[j-dnum].threshold(  bdArr[j-dnum] , bdArr[j-dnum].rect ,
            new Point() , ">" , 0xff333333 , 0xffffffff , 0xffffffff );

4.変化量の大きい部分にパーティクルを設置

for( var x:int = 0 ; x < myImage.width ; x +=step ){
    for( var y:int = 0 ; y < myImage.height ; y +=step ){
        if( bdArr[j-dnum].getPixel(x,y)==0xffffff ){
            if( Math.random() > 0.9 ){
                makeParticle(x,y);
            }
        }
    }
}

パーティクルは桜パーティクルを使ってます。
すべてのソースコードはこちら

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="left"
    paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5"
    backgroundAlpha="1" backgroundColor="0xffccff"
    creationComplete="init()"
     viewSourceURL="srcview/index.html">
<mx:Script>
<![CDATA[
private function init():void{
    setCamera();
//  カメラを反転させておく
//    myFlv.scaleX = -1;
//    myFlv.x = - myFlv.width;
//    myFlv.source = "01.flv";
}
//カメラ
private var timer:Timer = new Timer( 24 );
private function setCamera():void{
    var camera:Camera = Camera.getCamera();
    if( camera != null ){
        myFlv.attachCamera( camera );
    }else{
        myFlv.source = "01.flv";
    }
    timer.addEventListener( TimerEvent.TIMER , myTick );
    timer.start();
}
//差分をゲット
private var nowbd:BitmapData = new BitmapData( 320 , 240 );
private var bdArr:Array = new Array();
private var j:int = 0;
private var dnum:int = 5;
private function myTick( e:TimerEvent ):void{
    var mat:Matrix = new Matrix();
//    mat.scale(-1,1);
//    mat.tx = 320;
    nowbd.draw( myFlv , mat );
//    nowbd.applyFilter( nowbd , nowbd.rect , new Point() , myBlur );
    //エッジの抽出
    var Con:ConvolutionFilter = new ConvolutionFilter(3,3);
    Con.matrix = new Array(
                             0, -1, 0,
                            -1,  4, -1,
                             0, -1, 0
                            );
//    Con.bias = 255;
    nowbd.applyFilter( nowbd , nowbd.rect , new Point() , Con );
    //コピー。こうするとちらつきがなくなる
    bdArr[j] = nowbd.clone();
    //画像の差分を取得する
    if( bdArr.length > dnum ){
        bdArr[j-dnum].draw( bdArr[j] , null , null , "difference" );
        bdArr[j-dnum].threshold(  bdArr[j-dnum] , bdArr[j-dnum].rect ,
                                    new Point() , ">" , 0xff333333 , 0xffffffff , 0xffffffff );
        //myImage.source = new Bitmap( bdArr[j] );
        //変化のあった部分のみパーティクル作成
        setSakura();
        bdArr[j-dnum].dispose();
    }
    j++;
}
//変化のあった部分のみパーティクル作成
[Embed(source='sakura.png')]private var flower:Class;
[Embed(source='star.png')]  private var star:Class;
[Embed(source='heart.png')] private var heart:Class;
private var step:int = 20;
private function setSakura():void{
    for( var x:int = 0 ; x < myImage.width ; x +=step ){
        for( var y:int = 0 ; y < myImage.height ; y +=step ){
            if( bdArr[j-dnum].getPixel(x,y)==0xffffff ){
                if( Math.random() > 0.9 ){
                    makeParticle(x,y);
                }
            }
        }
    }
}
private var _vol:Number;
private var _drag:Number;
private var _shrink:Number;
private var _gravity:Number;
private var _fade:Number;
private var _wind:Number;
private var xVelArr:Array   = new Array();
private var yVelArr:Array   = new Array();
private var rotArr:Array    = new Array();
private var cnt:int         = 0;
private function makeParticle(x:Number,y:Number):void{
    _vol     = p_vol.value;
    _drag    = p_drag.value;
    _shrink  = p_shrink.value;
    _gravity = p_gravity.value;
    _fade    = p_fade.value;
    _wind    = p_wind.value;
    for (var i:uint = 0; i < 2; i++){
        var pt:Point = getNearPoint( new Point( x , y ) );
        var mc:Bitmap;
        if( typeBox.selectedIndex == 0 ){
            mc = new flower();
        }else if( typeBox.selectedIndex == 1 ){
            mc = new star();
        }else if( typeBox.selectedIndex == 2 ){
            mc = new heart();
        }
        mc.x    = pt.x;
        mc.y    = pt.y;
        mc.alpha = Math.random()*1;
        mc.name = "" + cnt;
        xVelArr[cnt] = getRandRange( -5, 5);
        yVelArr[cnt] = getRandRange( -5, 5);
        rotArr[cnt]  = getRandRange( -20, 20);
        mc.addEventListener(Event.ENTER_FRAME, function(e:Event):void{
            var m:Bitmap = e.target as Bitmap;
            m.filters = [gf];
            if ( m.alpha > 0){
                var c:int     = int( m.name );
                m.x          += xVelArr[c] + _wind * 10;
                m.y          += yVelArr[c];
                xVelArr[c]   *= _drag;
                yVelArr[c]   *= _drag;
                m.scaleX     *= _shrink;
                m.scaleY     *= _shrink;
                yVelArr[cnt] += _gravity;
                m.alpha      -= _fade;
                m.rotation   += rotArr[c];
            }else{
                m.removeEventListener(Event.ENTER_FRAME, arguments.callee);
                myCover.removeChild(m);
                m = null;
            }
        });
        cnt ++;
        myCover.addChild( mc );
    }
}
private function getRandRange(min:Number, max:Number):Number{
    var randomNum:Number = (Math.random() * (max - min )) + min;
    return randomNum;
}
private function getNearPoint(pt1:Point):Point{
    var len:uint   = Math.round(Math.random() * 10);
    var angle:uint = Math.round(Math.random() * 2 * Math.PI);
    var pt2:Point  = Point.polar(len, angle);
    pt2.offset( pt1.x, pt1.y );
    return pt2;
}
[Bindable]
private var typeArr:Array = new Array(
        {"label":"桜",     "type":"sakura", "vol":3,"drag":0.9,"shrink":0.95,"gravity":-0.2,"fade":0.02,"wind":-0.2},
        {"label":"星",     "type":"star",   "vol":3,"drag":0,  "shrink":0.95,"gravity":0,   "fade":0.02,"wind":0},
        {"label":"ハート","type":"heart",  "vol":3,"drag":0,  "shrink":1.05,"gravity":-2,  "fade":0.06,"wind":0}
    );
private function setType():void{
    var n:int = typeBox.selectedIndex;
    p_vol.value     = typeArr[n].vol;
    p_drag.value    = typeArr[n].drag;
    p_shrink.value  = typeArr[n].shrink;
    p_gravity.value = typeArr[n].gravity;
    p_fade.value    = typeArr[n].fade;
    p_wind.value    = typeArr[n].wind;
}
]]>
</mx:Script>
<mx:GlowFilter id="gf" blurX="16" blurY="16" color="0xffccff" />
<mx:BlurFilter id="myBlur" blurX="8" blurY="8" />
<mx:Canvas width="100%" height="100%" horizontalScrollPolicy="off" verticalScrollPolicy="off">
    <mx:Image id="myImage" width="320" height="240" visible="false" y="240"/>
    <mx:VideoDisplay id="myFlv" width="320" height="240"
        scaleX="{this.width/320}" scaleY="{this.height/240}" visible="true"/>
    <mx:Image id="myCover" width="320" height="240"
        scaleX="{this.width/320}" scaleY="{this.height/240}"/>
    <mx:VBox backgroundAlpha="0.5" backgroundColor="0xffffff" horizontalAlign="left"
        cornerRadius="5" borderColor="0xcccccc" borderStyle="solid" borderThickness="3"
        paddingBottom="5" paddingLeft="5" paddingRight="5" paddingTop="5"
        left="5" top="5"
        >
    <mx:ToggleButtonBar id="typeBox" labelField="label" itemClick="setType()"
        selectedIndex="0" width="100%" dataProvider="{typeArr}"/>
        <mx:HSlider id="p_vol"     labels="{['vol '+p_vol.value]}"     minimum="0" maximum="10" value="3" snapInterval="1"/>
        <mx:HSlider id="p_drag"    labels="{['drag'+p_drag.value]}"    minimum="0" maximum="2" value="0.9" snapInterval="0.01"/>
        <mx:HSlider id="p_shrink"  labels="{['shrink'+p_shrink.value]}"  minimum="0" maximum="2" value="0.95" snapInterval="0.01"/>
        <mx:HSlider id="p_gravity" labels="{['gravity'+p_gravity.value]}" minimum="-2" maximum="2" value="-0.2" snapInterval="0.01"/>
        <mx:HSlider id="p_fade"    labels="{['fade'+p_fade.value]}"    minimum="0" maximum="2" value="0.02" snapInterval="0.01"/>
        <mx:HSlider id="p_wind"    labels="{['wind'+p_wind.value]}"    minimum="-2" maximum="2" value="-0.2" snapInterval="0.01"/>
    </mx:VBox>
</mx:Canvas>
</mx:Application>