views:

85

answers:

5

I'm a Flash(AS3) newbie and this is just a little experiment of mine.

I'm trying to morph image captured through a webcam. The webcam snapshot part is already working but I still have no clue on how to do the morphing part. Can anyone point me to a tutorial (or kindly post code sample) on how to achieve image morphing using flash actionscript 3?

An example of morphing I'm trying to achieve can be found here. Thanks.

A: 

Well, there are few open source projects which do this thing. javamorph sounds quite interesting. Its open source, so you can have a look at the source and try it out.

bhups
+1  A: 

You can achieve the effect with a DisplacementMapFilter

maxmc
the displacement filter is the best option. can be complicated though
Glycerine
A: 

You can look for example at delaunay triangulation todo you morphing.

Here an example of morphing in AS3 with source code

and another good delaunay triangulation class here

Patrick
A: 

After a few free weekends (and weekdays) I'm glad to share what I got so far. Needs more improvement, i know. Young people get lazy too :P. You can download the source here. Garb it while its still there because the domain will expire soon haha. But I'll try to keep the site up I just hope to get more projects these coming months :D.

Thank you guys for your help.

bronson
A: 

A few years ago I needed something similar. Luckily Grant Skinner already developed camgoo.

I still have my quick and dirty port from then. Note: You will need a MovieClip in the library with the image you want to morph, linked as Img and a brush MovieClip linked as Brush. Easiest way to get started is to grab the symbols from the original as2 source on Grant Skinner's website, place them in an as3 document and witht he Morph class in place, just try something like addChild(new Morph());

The code is not optimized at all, it's a pretty quick and literal port. actionscript-3 features aren't used at they're best:

package  
{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.filters.*;

    /**
     * @author Grant Skiner - original code: http://incomplet.gskinner.com/index2.html#camgoo
     * @author port - George Profenza
     */
    public class Morph extends Sprite
    {
        private var rect:Rectangle;
        private var mapBmp:BitmapData;
        private var blurredMapBmp:BitmapData;
        private var blurF:BlurFilter;
        private var pt:Point;
        private var dispMapF:DisplacementMapFilter;
        // holder for transient values (ex. during drag, animation)
        private var tmp:Object;

        private var mapHolder:MovieClip;
        private var debugBitmap:Bitmap;
        private var img:MovieClip;
        private var brush:MovieClip;
        private var isAnimating:Boolean = false;
        private var btn:Sprite;
        private var btn2:Sprite;

        public function Morph() 
        {
            init();
        }

        private function init():void
        {
            trace('init');

            img = new Img();
            addChild(img);
            brush = new Brush();
            brush.scaleX = brush.scaleY = .75;
            addChild(brush);

            mapHolder = new MovieClip();
            addChild(mapHolder);
            debugBitmap = new Bitmap(new BitmapData(img.width, img.height, false, 0x808080));
            debugBitmap.alpha = 0;
            mapHolder.addChild(debugBitmap);

            rect = new Rectangle(0,0,Math.floor(img.width),Math.floor(img.height));
            pt = new Point(0,0);

            // set up bitmaps:
            mapBmp = new BitmapData(rect.width,rect.height,false,0x808080);
            blurredMapBmp = mapBmp.clone();

            // set up filters:
            blurF = new BlurFilter(8,8,2);
            dispMapF = new DisplacementMapFilter(blurredMapBmp, pt,BitmapDataChannel.RED, BitmapDataChannel.GREEN, 100, 100, DisplacementMapFilterMode.CLAMP);

            brush.visible = false;
            this.addEventListener(MouseEvent.MOUSE_DOWN, startGoo);

            btn = new Sprite();
            btn.graphics.beginFill(0);
            btn.graphics.drawRect(0, 0, 50, 50);
            btn.graphics.endFill();
            btn.visible = false;
            addChild(btn);
            btn.addEventListener(MouseEvent.CLICK, onAnimClick);
            btn2 = new Sprite();
            btn2.graphics.beginFill(0);
            btn2.graphics.drawRect(0, 0, 50, 50);
            btn2.graphics.endFill();
            btn2.y = btn.height + 5;
            btn2.visible = false;
            addChild(btn2);
            btn2.addEventListener(MouseEvent.CLICK, endAnimate);
        }

        private function onAnimClick(e:MouseEvent):void 
        {
            isAnimating = true;
            animateGoo();
        }

        private function startGoo(e:MouseEvent):void{
            tmp = { oldx:mouseX, oldy:mouseY };
            this.addEventListener(MouseEvent.MOUSE_UP, endGoo);
            this.addEventListener(MouseEvent.MOUSE_MOVE, gooify);
        }

        private function endGoo(e:MouseEvent):void{
            tmp = null;
            this.removeEventListener(MouseEvent.MOUSE_UP, endGoo);
            this.removeEventListener(MouseEvent.MOUSE_MOVE, gooify);
        }

        private function clearGoo():void {
            mapBmp.fillRect(rect,0x808080);
            blurredMapBmp.fillRect(rect,0x808080);
            applyMap();
        }

        private function gooify(e:MouseEvent):void{
            var dx:Number = mouseX-tmp.oldx;
            var dy:Number = mouseY-tmp.oldy;
            tmp = {oldx:mouseX,oldy:mouseY};

            brush.rotation = (Math.atan2(dy, dx)) * 180 / Math.PI;
            brush.x = mouseX;
            brush.y = mouseY;

            var g:Number = 0x80+Math.min(0x79,Math.max(-0x80,  -dx*2  ));
            var b:Number = 0x80+Math.min(0x79,Math.max(-0x80,  -dy*2  ));
            var ct:ColorTransform = new ColorTransform(0,0,0,1,0x80,g,b,0);

            mapBmp.draw(brush,brush.transform.matrix,ct,BlendMode.HARDLIGHT);
            applyMap();
        }

        private function applyMap() {

            blurredMapBmp.applyFilter(mapBmp, rect, pt, blurF);
            img.filters = [dispMapF];
        }

        private function animateGoo():void {
            removeEventListener(MouseEvent.MOUSE_DOWN, startGoo);
            addEventListener(MouseEvent.MOUSE_DOWN, endAnimate);
            addEventListener(Event.ENTER_FRAME, animate);
            tmp = {count:100,dir:-4,scale:dispMapF.scaleX}
        }

        private function animate(e:Event):void {
            tmp.count+=tmp.dir;
            if (tmp.count >= 100 || tmp.count <= 0) { tmp.dir *= -1; }
            dispMapF.scaleX = dispMapF.scaleY = tmp.count / 100 * tmp.scale;
            applyMap();
        }

        private function endAnimate(e:MouseEvent):void {
            isAnimating = false;
            removeEventListener(MouseEvent.MOUSE_DOWN, endAnimate);
            removeEventListener(Event.ENTER_FRAME, animate);
            addEventListener(MouseEvent.MOUSE_DOWN, startGoo);
            tmp = null;
            dispMapF = new DisplacementMapFilter(blurredMapBmp, pt,BitmapDataChannel.RED, BitmapDataChannel.GREEN, 100, 100, DisplacementMapFilterMode.CLAMP);
            applyMap();
        }

        public function set anim(value:Boolean):void {
            value ? btn.dispatchEvent(new MouseEvent(MouseEvent.CLICK)) : btn2.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
            isAnimating = value;
        }

        public function get anim():Boolean {
            return isAnimating;
        }
    }

}
George Profenza
Thanks mate. Ported the same code from gskinner as2 camgoo to my as3 "custom-made" distortion. works like a charm :D.
bronson