In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

genetic algorithm - make image with transparent polygon

1. mutate parent(add random polygon or delete, change color, alpha) - make child
2. compare with original image
3. if child's fitness is better than parent, child is parent.
4. go to 1

Reference - http://linesandcolors.com/2008/12/10/genetic-programming-evolution-of-mona-lisa/

p.s. : it takes a lot of time to see a good image..
/**
 * Copyright greentec ( http://wonderfl.net/user/greentec )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/gA9S
 */

package {
    import com.bit101.components.Label;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Graphics;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;    import flash.events.TimerEvent;
    import flash.geom.Point;
    import flash.net.URLRequest;
    import com.bit101.components.PushButton;
    import flash.utils.ByteArray;
    import flash.utils.getTimer;
    import flash.geom.ColorTransform;
    import flash.system.LoaderContext;
    import flash.geom.Matrix;

    public class FlashTest extends Sprite {
        
        public var imageLoad:URLRequest = new URLRequest("http://assets.wonderfl.net/images/related_images/a/a8/a8bf/a8bf5cfb82b059900c5b8432115e55c78448f816m");
        public var imageLoad_Sprite:Sprite;
        public var imageLoad_Loader:Loader;
        
        public var imageBitmapData:BitmapData;
        public var imageBitmap:Bitmap;
                
        public var imageWidth:int;
        public var imageHeight:int;
        
        public var defaultAlpha:Number = 0.1;
        public var defaultAlphaMax:Number = 0.6;
        public var defaultAlphaMin:Number = 0.1;
        
        public var testBitmapData:BitmapData;
        public var testBitmap:Bitmap;
        public var viewBitmapData:BitmapData;
        public var viewBitmap:Bitmap;
        
        public var genBitmapData:BitmapData;
        public var genBitmap:Bitmap;
        public var genSprite:Sprite;
        
        public var showingTestImage:Boolean = true;
        
        public var costArray:Array;
        public var genCostArray:Array;
        //public var genCostSortArray:Array;
        public var genSortArray:Array;
        public var populationArray:Array;
        public var childrenArray:Array;
        public var populationTriangleSize:uint = 10;//150;//1000;//1000개의 원 //40; //20개의 triangle
        public var circleMaxRadius:uint = 50;
        public var populationNum:uint = 2//10; //30개의 init poputation
        //public var iterationNum:uint = 50;
        
        public var popCost:uint;
        public var childCost:uint;
        
        public var IsDirty:Boolean = false;
        
        public var PlaneMax:int = 150;
        public var PlaneMin:int = 4;
        public var PointPerPlaneMin:int = 3;
        public var PointPerPlaneMax:int = 10;
        
        public var NewPlaneRate:Number = 0.2;
        public var NewPointRate:Number = 0.2;
        public var CloneRate:Number = 0.3;
        //public var NewColorRate:Number = 0.2;
        public var DelPlaneRate:Number = 0.2;
        public var DelPointRate:Number = 0.2;
        public var MovePointRate:Number = 0.2;
        public var NewRedRate:Number = 0.25;
        public var NewGreenRate:Number = 0.25;
        public var NewBlueRate:Number = 0.25;
        public var NewAlphaRate:Number = 0.25;
        
        public var scaleValue:int = 3;
        
        public var b_circle:Boolean = false;//true//false;//true;
        
        public var crossoverPointNum:uint = 1;
        public var mutationRate:Number = 0.2;
        public var eliteRate:Number = 0.5; //50%는 그대로 남는다.
        
        public var generation:uint = 0;
        //public var eliminationList:Array;
        //public var parentList:Array;
        
        public var getNewGenButton:PushButton;
        public var genLabel:Label;
        public var diffLabel:Label;
        public var matchLabel:Label;
        public var planeLabel:Label;
        public var validLabel:Label;
        
        public var validgen:uint = 0;
        
        public var timecheck:uint;
        
        public var loopFinished:Boolean = false;
        public var imageLoaded:Boolean = false;
        
        public var totalErr:uint;
        
        public function FlashTest() {
            // write as3 code here..
            Wonderfl.disable_capture();
            
            stage.frameRate = 60;
            stage.scaleMode = "noScale";
            
            imageLoad_Loader = new Loader();
            imageLoad_Sprite = new Sprite();
            
            
            genCostArray = [];
            
            
            
            imageLoad_Loader.contentLoaderInfo.addEventListener(Event.COMPLETE, testImageLoad);
            imageLoad_Loader.load(imageLoad, new LoaderContext(true));
            
        }
        
        private function testImageLoad(e:Event):void
        {
            //imageWidth = e.target.width;
            //imageHeight = e.target.height;
            imageWidth=88;
            imageHeight=103;
            
            genSprite = new Sprite();
            //testBitmapData = new BitmapData(int(imageWidth * scaleValue), int(imageHeight * scaleValue), true, 0xff000000);
            //testBitmap = new Bitmap(testBitmapData);
            //genSprite.addChild(testBitmap);
            testBitmapData = new BitmapData(imageWidth, imageHeight, true, 0xff000000);
            testBitmap = new Bitmap(testBitmapData);
            viewBitmapData = new BitmapData(int(imageWidth * scaleValue), int(imageHeight * scaleValue), true, 0xff000000);
            viewBitmap = new Bitmap(viewBitmapData);
            genSprite.addChild(testBitmap);
            genSprite.addChild(viewBitmap);
            addChild(genSprite);
            
            
            imageBitmapData = new BitmapData(imageWidth, imageHeight, true);
            imageBitmapData.draw(e.target.content, new Matrix(103 / e.target.width, 0, 0, 103 / e.target.width, -10));
            imageBitmap = new Bitmap(imageBitmapData);
            imageLoad_Sprite = new Sprite();
            imageLoad_Sprite.addChild(imageBitmap);
            
            if (showingTestImage == true)
            {
                addChild(imageLoad_Sprite);
            }
            
            init_cost(imageBitmapData, imageWidth, imageHeight);
            
            //if(use_imagePalette==true)
            //{
                //imagePalette = [];
                //imagePalette = ColourUtils.colourPalette( imageBitmapData, 128, 0.005 );
                //trace(imagePalette.length);
            //}
            
            imageLoaded = true;
            
            var i:int, j:int;
            totalErr = 0;
            for (i = 0; i < costArray.length; i += 1)
            {
                for (j = 0; j < costArray[i].length; j += 1)
                {
                    totalErr += costArray[i][j];
                }
                
            }
            
            
            genSprite.x = imageWidth;
            
            testBitmap.x = -imageWidth;
            testBitmap.y = imageHeight;
            //genSprite.scaleX = 3;
            //genSprite.scaleY = 3;
            
            
            
            
            init_population();
            
            timecheck = getTimer();
            //trace(timecheck);
            //loop_GA();
            
            get_popoulationimageBitmapData(populationArray, 1, false);
            popCost=calculate_cost();
            
            stage.addEventListener(Event.ENTER_FRAME, loop_GA);
        }
        
        private function init_cost(imageBitmapData:BitmapData, width:int, height:int ):void //불러들인 이미지의 color 값을 읽어들여 costArray에 저장한다
        {
            var i:int;
            var j:int;
            costArray = [];
            
            //genBitmapData = new BitmapData(width, height, true, 0x000000);//0xff0f1012);
            
            //genBitmapData.lock();
            
            for (i = 0; i < width; i+=1)
            {
                costArray[i] = new Array();
                for (j = 0; j < height; j+=1)
                {
                    var color:uint=imageBitmapData.getPixel32(i, j)
                    //costArray[i].push((color & 0xff0000) >> 16); //red
                    //costArray[i].push((color & 0x00ff00) >> 8); //green
                    //costArray[i].push(color & 0x0000ff); //blue
                    costArray[i].push((color >> 16) & 0xff);
                    costArray[i].push((color >> 8) & 0xff);
                    costArray[i].push(color & 0xff);
                    
                    
                    //costArray[i].push(imageBitmapData.getPixel32(i, j));
                    //genBitmapData.setPixel32(i,j,costArray[i][(costArray.length - 1)]);
                    
                }
            }
            
            //genBitmapData.unlock();
            
            
            var colorTra:ColorTransform = new ColorTransform(0, 0, 0, 1, 0, 0, 255);
            genLabel = new Label(this, 5, 24+300, "Generation : " + generation);
            diffLabel = new Label(this, 5, 36+300, "Population Difference");
            matchLabel = new Label(this, 5, 0+300, "Match : ");
            planeLabel = new Label(this, 5, 72+300, "Polygon : ");
            validLabel = new Label(this, 5, 84+300, "Valid : ");
            
            genLabel.transform.colorTransform = colorTra;
            diffLabel.transform.colorTransform = colorTra;
            planeLabel.transform.colorTransform = new ColorTransform(0, 0, 0, 1, 255, 128, 0);
            validLabel.transform.colorTransform = new ColorTransform(0, 0, 0, 1, 0, 128, 255);
            
            
        }
        
        private function init_population():void
        {
            var i:int;
            populationArray = new Array();
            
            for (i = 0; i < PlaneMin; i+=1)
            {
                //var plane:Plane = new Plane(imageWidth, imageHeight);
                populationArray.push(new Plane(imageWidth, imageHeight));
                //trace(populationArray[i].points_);
            }
            
            //trace(populationArray.length);
            
        }
        
        private function loop_GA(e:Event):void//(t:TimerEvent):void//(e:MouseEvent):void//(t:TimerEvent)
        {
            for (var j:int = 0; j < 10; j+=1)
            {    
                
                if (imageLoaded == true)
                {
                
                    generation += 1;
                    
                    var i:int=0;
                    
                    //genCostSortArray = [];
                    
                    childrenArray = [];
                    childrenArray = clone(populationArray);
                    
                    mutate();
                    
                    
                    //get_popoulationimageBitmapData(populationArray, 1, false);
                    //popCost=calculate_cost();
                    
                    get_popoulationimageBitmapData(childrenArray, 1, false);
                    childCost=calculate_cost();
                    
                    //trace(popCost, childCost);
                    
                    if (childCost < popCost)
                    {
                        popCost=childCost;
                        
                        drawElite();
                        populationArray = null;
                        populationArray = clone(childrenArray);
                        childrenArray = null;
                        //populationIsDrawn = true;
                        validgen += 1;
                        
                        printdiffLabel(childCost);
                        printmatchLabel(childCost);
                        printplaneLabel();
                        
                    }
                    else
                    {
                        
                        
                        printdiffLabel(popCost);
                        printmatchLabel(popCost);
                    }
                    
                    
                    printgenerationLabel();
                    printvalidLabel();
                    
                    
                    //timetick = new Timer(50);
                    //timetick.start();
                    //timetick.addEventListener(TimerEvent.TIMER_COMPLETE, loop_Rest);
                    
                    
                    //loopFinished = true;
                    
                    //timetick.start();
                    //timetick.addEventListener(TimerEvent.TIMER, loop_GA2);
                    
                    //test
                    //crossover();
                    //mutate();
                    
                    //getNewGenButton.addEventListener(MouseEvent.CLICK, loop_GA);
                    //addChild(getNewGenButton);
                    
                    
                    //trace(parentList.length, eliminationList.length, genCostSortArray.length);
                }
            }
        }
        
        
        
        private function get_popoulationimageBitmapData(list:Array, scaleValue:Number, visible:Boolean):void
        {
            
            var triangle:Sprite = new Sprite; 
            var g:Graphics = triangle.graphics;
            
            //testBitmapData = new BitmapData(imageWidth * scaleValue, imageHeight * scaleValue, true, 0xff000000);// , 0xff0f1012);
            if (visible == false)
            {
                testBitmapData.fillRect(testBitmapData.rect, 0xff000000);
                testBitmapData.lock();
            }
            else
            {
                viewBitmapData.fillRect(viewBitmapData.rect, 0xff000000);
                viewBitmapData.lock();
            }
            
            var j:int;
            var k:int;
            
            var color:uint;
            
            testBitmapData.lock();
            
            g.lineStyle(0, 0, 0);
            g.clear();
            for (j = 0; j < list.length; j+=1)
            {
                var plane:Object = list[j];
                
                
                color = (plane.red << 16) | (plane.green << 8) | plane.blue;
                
                g.beginFill(color, plane.alpha_);
                //trace(plane.alpha_)
                
                g.moveTo(plane.points_[0].x * scaleValue, plane.points_[0].y * scaleValue);
                
                for (k = 1; k < plane.points_.length; k += 1)
                {
                    g.lineTo(plane.points_[k].x * scaleValue, plane.points_[k].y * scaleValue);
                }
                g.lineTo(plane.points_[0].x * scaleValue, plane.points_[0].y * scaleValue);
                g.endFill();
                
                
                
                //trace(list.length);
                //trace(plane.points_);
                
            }
            
            if (visible == false)
            {
                testBitmapData.draw(triangle);
                testBitmapData.unlock();
            }
            else
            {
                viewBitmapData.draw(triangle);
                viewBitmapData.unlock();
            }
            
            //testBitmap = new Bitmap(testBitmapData);
            //genSprite.addChild(testBitmap);
            
        }
        
        private function calculate_cost():uint
        {
            
            //genCostSortArray = [];
            
            var diff:uint;
            var i:int;
            var j:int;
            var r:int, g:int, b:int;
            
            testBitmapData.lock();
            
            for (i = 0; i < imageWidth; i+=1)
            {
                for (j = 0; j < imageHeight; j+=1)
                {
                    var testcolor:uint = testBitmapData.getPixel32(i, j);
                    r = costArray[i][3 * j] - ((testcolor >> 16) & 0xff);
                    r = (r ^ (r >> 31)) - (r >> 31);
                    g = costArray[i][3 * j + 1] - ((testcolor >> 8) & 0xff);
                    g = (g ^ (g >> 31)) - (g >> 31);
                    b = costArray[i][3 * j + 2] - (testcolor & 0xff);
                    b = (b ^ (b >> 31)) - (b >> 31);
                    
                    diff += r + g + b;
                }
            }
            
            testBitmapData.unlock();
            
            return diff;
            
            //genCostSortArray.push(diff);
            //trace(diff);
            //genCostSortArray.push( { cost:diff, index:populationIndex } );
            
            //trace(genCostSortArray);            
            
            
        }
        
        private function mutate():void
        {
            //Delete Plane or Point
            var randPlane:int;
            IsDirty = false;
            
            if (IsDirty == false && Math.random() < DelPlaneRate)
            {
                if (childrenArray.length > PlaneMin)
                {
                    randPlane=int(Math.random()*childrenArray.length)
                    childrenArray.splice(randPlane, 1);
                    IsDirty = true;
                }
                
            }
            
            
            
            if (IsDirty == false && Math.random() < DelPointRate)
            {
                if (childrenArray[randPlane].points_.length > PointPerPlaneMin)
                {
                    randPlane = int(Math.random()*childrenArray.length)
                    childrenArray[randPlane].points_.splice(int(childrenArray[randPlane].points_.length * Math.random()), 1);
                    IsDirty = true;
                }
                
            }
            
            
            
            if (IsDirty == false && Math.random() < NewPlaneRate)
            {
                if (childrenArray.length < PlaneMax)
                {
                    var plane:Object;
                    
                    if (Math.random() < CloneRate)
                    {
                        randPlane = int(Math.random() * childrenArray.length);
                        plane = clone(childrenArray[randPlane]);
                        
                        if (Math.random() < NewRedRate)
                        {
                            plane.red = Math.random() * 255;
                        }
                        if (Math.random() < NewGreenRate)
                        {
                            plane.green = Math.random() * 255;
                        }
                        if (Math.random() < NewBlueRate)
                        {
                            plane.blue = Math.random() * 255;
                        }
                        if (Math.random() < NewAlphaRate)
                        {
                            plane.alpha_ = Math.random() * 0.1;
                        }
                    }
                    else
                    {
                        plane = new Plane(imageWidth, imageHeight);
                        
                        //childrenArray[childrenArray.length - 1].red = childrenArray[randPlane].red + Math.random() * 20 - 10;
                        //childrenArray[childrenArray.length - 1].green = childrenArray[randPlane].green + Math.random() * 20 - 10;
                        //childrenArray[childrenArray.length - 1].blue = childrenArray[randPlane].blue + Math.random() * 20 - 10;
                    
                    }
                    
                    childrenArray.push(plane);
                    IsDirty = true;
                }
                
            }
            
            
            
            if (IsDirty == false && Math.random() < MovePointRate)
            {
                randPlane = int(Math.random()*childrenArray.length)
                childrenArray[randPlane].points_[int(childrenArray[randPlane].points_.length * Math.random())] = new Point(Math.random()*imageWidth,Math.random()*imageHeight);                
                IsDirty = true;
            }
            
            
            
            //if (Math.random() < NewColorRate)
            //{
                //childrenArray[randPlane].setRandomColor();
            //}
            
            
            
            if (IsDirty == false && Math.random() < NewPointRate)
            {
                if (childrenArray[randPlane].points_.length < PointPerPlaneMax)
                {
                    randPlane = int(Math.random()*childrenArray.length)
                    childrenArray[randPlane].points_.push(new Point(Math.random() * imageWidth, Math.random() * imageHeight));
                    IsDirty = true;
                }
                
            }
            
            
            if (IsDirty == false && Math.random() < NewRedRate)
            {
                randPlane = int(Math.random() * childrenArray.length)
                childrenArray[randPlane].red = Math.random() * 255;
                IsDirty = true;
            }
            
            
            if (IsDirty == false && Math.random() < NewGreenRate)
            {
                randPlane = int(Math.random() * childrenArray.length)
                childrenArray[randPlane].green = Math.random() * 255;
                IsDirty = true;
            }
            
            
            if (IsDirty == false && Math.random() < NewBlueRate)
            {
                randPlane = int(Math.random() * childrenArray.length)
                childrenArray[randPlane].blue = Math.random() * 255;
                IsDirty = true;
            }
            
            
            if (IsDirty == false && Math.random() < NewAlphaRate)
            {
                randPlane = int(Math.random() * childrenArray.length)
                childrenArray[randPlane].alpha_ = Math.random() * 0.1;
                IsDirty = true;
            }
        }
        
        private function drawElite():void
        {
            //genSprite.removeChild(testBitmap);
            
            get_popoulationimageBitmapData(childrenArray, scaleValue, true);
            //get_popoulationimageBitmapData(genSortArray[0]);
            //trace("index : ", genCostSortArray[0].index, "cost : ", genCostSortArray[0].cost);
            
            
            //testBitmap = new Bitmap(testBitmapData);
            //genSprite.addChild(testBitmap);
            
        }
        
        private function printdiffLabel(diffScore:uint):void
        {
            var i:int;
            var str:String="";
            str += "Population Difference";
            str += "\n  " + diffScore;
            
            diffLabel.text = str;
        }
            
        private function printgenerationLabel():void
        {
            genLabel.text = "Generation : " + generation + " (" + String(int(generation/(getTimer()-timecheck)*100000)/100) +" gen/s)";
        }
        
        private function printmatchLabel(diffScore:uint):void
        {
            matchLabel.text = "Match : " + String(int((totalErr-diffScore)/totalErr * 100000)/1000)+" %";
        }
        
        private function printplaneLabel():void
        {
            planeLabel.text = "Polygon : " + String(populationArray.length);
        }
        
        private function printvalidLabel():void
        {
            validLabel.text = "Valid : " + String(int(validgen / generation * 10000) / 100) +"%";
        }
        
        static public function clone(source:Object):*{
            var byteArray:ByteArray = new ByteArray();
            byteArray.writeObject(source);
            byteArray.position = 0;
            return(byteArray.readObject());
        }
    }
}

Class  
{
    import flash.geom.Point;
    import flash.display.Sprite;
    /**
     * ...
     * @author ypc
     */
    class Plane extends Sprite
    {
        public var points_:Array=[];
        public var alpha_:Number;
        public var red:int;
        public var green:int;
        public var blue:int;
        
        public function Plane(width:Number,height:Number) 
        {
            setRandomColor();
            for (var j:int = 0; j < 3; j++)
            {
                this.points_.push(new Point(Math.random() * width, Math.random() * height));
            }
            
        }
        
        public function setRandomColor():void
        {
            //this.alpha_ = Math.random()*0.5+0.1;
            this.alpha_ = 0.1;
            this.red = Math.random() * 255;
            this.green = Math.random() * 255;
            this.blue = Math.random() * 255;
            
        }
        
        //public function addPoint(width:Number,height:Number):void
        //{
            //this.points_.push(new Point(Math.random() * width, Math.random() * height));
            //
        //}
        
    }

}