Author: tn
Date: Mon Dec  9 22:34:28 2013
New Revision: 1549696

URL: http://svn.apache.org/r1549696
Log:
Add ImageEvolution example for genetics package.

Added:
    
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/ImageEvolutionExample.java
   (with props)
    
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/Polygon.java
   (with props)
    
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/PolygonChromosome.java
   (with props)
    
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/RandomPolygonMutation.java
   (with props)

Added: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/ImageEvolutionExample.java
URL: 
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/ImageEvolutionExample.java?rev=1549696&view=auto
==============================================================================
--- 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/ImageEvolutionExample.java
 (added)
+++ 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/ImageEvolutionExample.java
 Mon Dec  9 22:34:28 2013
@@ -0,0 +1,205 @@
+package org.apache.commons.math3.userguide.genetics;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+
+import org.apache.commons.math3.genetics.Chromosome;
+import org.apache.commons.math3.genetics.ElitisticListPopulation;
+import org.apache.commons.math3.genetics.GeneticAlgorithm;
+import org.apache.commons.math3.genetics.Population;
+import org.apache.commons.math3.genetics.TournamentSelection;
+import org.apache.commons.math3.genetics.UniformCrossover;
+
+/**
+ * Based on http://www.nihilogic.dk/labs/evolving-images/
+ */
+@SuppressWarnings("serial")
+public class ImageEvolutionExample extends JComponent {
+
+    public static final int   POPULATION_SIZE  = 40;
+    public static final int   TOURNAMENT_ARITY = 2;
+    public static final float MUTATION_RATE    = 0.02f;
+    public static final float MUTATION_CHANGE  = 0.1f;
+
+    public static final int POLYGON_LENGTH = 6;
+    public static final int POLYGON_COUNT = 100;
+
+    private GeneticAlgorithm ga;
+    private Population currentPopulation;
+    private Chromosome bestFit;
+
+    private Thread internalThread;
+    private volatile boolean noStopRequested;
+
+    private BufferedImage ref;
+    private BufferedImage buf;
+    
+    private ImagePainter painter;
+
+    public ImageEvolutionExample() throws Exception {
+        super();
+        setLayout(new FlowLayout());
+
+        Box bar = Box.createHorizontalBox();
+
+        ref = ImageIO.read(new File("resources/canvas_small.png"));
+
+        JLabel picLabel = new JLabel(new ImageIcon(ref));
+        bar.add(picLabel);
+
+        painter = new ImagePainter(ref);
+        bar.add(painter);
+
+        buf = new BufferedImage(ref.getWidth(), ref.getHeight(), 
BufferedImage.TYPE_INT_ARGB);
+        
+        // TODO: improve this
+        PolygonChromosome.setRefImage(ref);
+        PolygonChromosome.setTestImage(buf);
+
+        add(bar);
+
+        JButton startButton = new JButton("Start");
+        startButton.setActionCommand("start");
+        add(startButton);
+
+        startButton.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                if (isAlive()) {
+                    stopRequest();
+                } else {
+                    startEvolution();
+                }
+            }
+        });
+
+        // initialize a new genetic algorithm
+        ga = new GeneticAlgorithm(new UniformCrossover<Polygon>(0.5), 1.0,
+                                  new RandomPolygonMutation(MUTATION_RATE, 
MUTATION_CHANGE), 1.0,
+                                  new TournamentSelection(TOURNAMENT_ARITY));
+
+        // initial population
+        currentPopulation = getInitialPopulation();
+        bestFit = currentPopulation.getFittestChromosome();
+    }
+
+    private Population getInitialPopulation() {
+        List<Chromosome> popList = new LinkedList<Chromosome>();
+        for (int i = 0; i < POPULATION_SIZE; i++) {
+            popList.add(PolygonChromosome.randomChromosome(POLYGON_LENGTH, 
POLYGON_COUNT));
+        }
+        return new ElitisticListPopulation(popList, popList.size(), 0.25);
+    }
+
+    public boolean isAlive() {
+        return internalThread != null && internalThread.isAlive();
+    }
+
+    public void stopRequest() {
+        noStopRequested = false;
+        internalThread.interrupt();
+        internalThread = null;
+    }
+
+    public void startEvolution() {
+        noStopRequested = true;
+        Runnable r = new Runnable() {
+            public void run() {
+                try {
+                    double lastBestFit = Double.MIN_VALUE;
+                    int evolution = 0;
+                    while (noStopRequested) {
+                        currentPopulation = 
ga.nextGeneration(currentPopulation);
+
+                        System.out.println("generation: " + evolution++ + ": " 
+ bestFit.toString());
+                        bestFit = currentPopulation.getFittestChromosome();
+
+                        if (lastBestFit > bestFit.getFitness()) {
+                            System.out.println("gotcha");
+                        }
+                        lastBestFit = bestFit.getFitness();
+                        painter.repaint();
+                    }
+                } catch (Exception x) {
+                    // in case ANY exception slips through
+                    x.printStackTrace();
+                }
+            }
+        };
+
+        internalThread = new Thread(r);
+        internalThread.start();
+    }
+
+    private static void createAndShowGUI() throws Exception {
+        // Create and set up the window.
+        JFrame frame = new JFrame("Image Evolution Example");
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        frame.getContentPane().add(new ImageEvolutionExample());
+
+        // Display the window.
+        frame.pack();
+        frame.setSize(new Dimension(500, 300));
+        frame.setVisible(true);
+    }
+
+    public static void main(String[] args) {
+        // Schedule a job for the event-dispatching thread:
+        // creating and showing this application's GUI.
+        javax.swing.SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                try {
+                    createAndShowGUI();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+
+    private class ImagePainter extends Component {
+        BufferedImage ref;
+
+        public ImagePainter(final BufferedImage ref) {
+            this.ref = ref;
+        }
+
+        public Dimension getPreferredSize() {
+            return new Dimension(ref.getWidth(), ref.getHeight());
+        }
+
+        @Override
+        public Dimension getMinimumSize() {
+            return getPreferredSize();
+        }
+
+        @Override
+        public Dimension getMaximumSize() {
+            return getPreferredSize();
+        }
+
+        public void paint(Graphics g) {
+            PolygonChromosome chromosome = (PolygonChromosome) bestFit;
+            chromosome.draw((Graphics2D) g, ref.getWidth(), ref.getHeight());
+        }
+
+    }
+
+}

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/ImageEvolutionExample.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/ImageEvolutionExample.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision HeadURL

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/ImageEvolutionExample.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/Polygon.java
URL: 
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/Polygon.java?rev=1549696&view=auto
==============================================================================
--- 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/Polygon.java
 (added)
+++ 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/Polygon.java
 Mon Dec  9 22:34:28 2013
@@ -0,0 +1,61 @@
+package org.apache.commons.math3.userguide.genetics;
+
+import org.apache.commons.math3.genetics.GeneticAlgorithm;
+import org.apache.commons.math3.random.RandomGenerator;
+import org.apache.commons.math3.util.FastMath;
+
+public class Polygon {
+
+    // the polygon in packed representation:
+    // index | data
+    //    0  | red component
+    //    1  | green component
+    //    2  | blue component
+    //    3  | alpha channel
+    //   
+    protected float[] data;
+
+    public static Polygon randomPolygon(int length) {
+        final int polygonSize = 4 + 2 * length;
+
+        final RandomGenerator random = GeneticAlgorithm.getRandomGenerator();
+        
+        Polygon p = new Polygon();
+        p.data = new float[polygonSize];
+
+        p.data[0] = random.nextFloat(); // r
+        p.data[1] = random.nextFloat(); // g
+        p.data[2] = random.nextFloat(); // b
+        p.data[3] = FastMath.max(0.2f, random.nextFloat() * 
random.nextFloat()); // a
+        
+        float px = random.nextFloat();
+        float py = random.nextFloat();
+        
+        for (int k = 0; k < length; k++) {
+            p.data[4 + 2*k] = px + (random.nextFloat() - 0.5f);
+            p.data[5 + 2*k] = py + (random.nextFloat() - 0.5f);
+        }
+        return p;
+    }
+
+    public Polygon mutate(float mutationRate, float mutationAmount) {
+        Polygon mutated = new Polygon();
+        int size = data.length;
+        mutated.data = new float[size];
+        for (int i = 0; i < size; i++) {
+            float val = this.data[i];
+            if (GeneticAlgorithm.getRandomGenerator().nextFloat() < 
mutationRate) {
+                val += GeneticAlgorithm.getRandomGenerator().nextFloat() * 
mutationAmount * 2 - mutationAmount;
+                
+                if (val < 0f) {
+                    val = 0f;
+                } else if (val > 1f) {
+                    val = 1f;
+                }
+            }
+            mutated.data[i] = val;
+        }
+        return mutated;
+    }    
+
+}

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/Polygon.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/Polygon.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision HeadURL

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/Polygon.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/PolygonChromosome.java
URL: 
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/PolygonChromosome.java?rev=1549696&view=auto
==============================================================================
--- 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/PolygonChromosome.java
 (added)
+++ 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/PolygonChromosome.java
 Mon Dec  9 22:34:28 2013
@@ -0,0 +1,116 @@
+package org.apache.commons.math3.userguide.genetics;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.GeneralPath;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math3.genetics.AbstractListChromosome;
+import org.apache.commons.math3.genetics.Chromosome;
+import org.apache.commons.math3.genetics.InvalidRepresentationException;
+
+public class PolygonChromosome extends AbstractListChromosome<Polygon> {
+
+    private static BufferedImage refImage;
+    private static BufferedImage testImage;
+
+    public static void setRefImage(BufferedImage ref) {
+        refImage = ref;
+    }
+
+    public static void setTestImage(BufferedImage image) {
+        testImage = image;
+    }
+
+    public PolygonChromosome(List<Polygon> representation) {
+        super(representation);
+    }
+
+    @Override
+    protected void checkValidity(List<Polygon> chromosomeRepresentation) 
throws InvalidRepresentationException {
+        // do nothing
+    }
+
+    @Override
+    public AbstractListChromosome<Polygon> 
newFixedLengthChromosome(List<Polygon> chromosomeRepresentation) {
+        return new PolygonChromosome(chromosomeRepresentation);
+    }
+
+    public List<Polygon> getPolygonRepresentation() {
+        return getRepresentation();
+    }
+
+    public double fitness() {
+
+        Graphics2D g2 = testImage.createGraphics();
+        
+        int width = testImage.getWidth();
+        int height = testImage.getHeight();
+
+        draw(g2, width, height);
+        g2.dispose();
+
+        int[] refPixels = refImage.getData().getPixels(0, 0, 
refImage.getWidth(), refImage.getHeight(), (int[]) null);
+        int[] pixels = testImage.getData().getPixels(0, 0, 
testImage.getWidth(), testImage.getHeight(), (int[]) null);
+
+        int diff = 0;
+        int p = width * height * 4 - 1;
+        int idx = 0;
+
+        do {
+            if (idx++ % 4 != 0) {
+                int dp = pixels[p] - refPixels[p];
+                if (dp < 0) {
+                    diff -= dp;
+                } else {
+                    diff += dp;
+                }
+            }
+        } while(--p > 0);
+
+        return (1.0 - diff / (width * height * 3.0 * 256));
+    }
+
+    public void draw(Graphics2D g, int width, int height) {
+        g.setBackground(Color.RED);
+        g.clearRect(0, 0, width, height);
+
+        //if (true) return;
+        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
RenderingHints.VALUE_ANTIALIAS_ON);
+        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
+
+        List<Polygon> polygons = getPolygonRepresentation();
+        for (Polygon p : polygons) {
+            g.setColor(new Color(p.data[0], p.data[1], p.data[2], p.data[3]));
+
+            GeneralPath path = new GeneralPath();
+            path.moveTo(p.data[4] * width, p.data[5] * height);
+            
+            int polygonLength = (p.data.length - 4) / 2;
+            for (int j = 1; j < polygonLength; j++) {
+                path.lineTo(p.data[4 + j * 2] * width, p.data[5 + j * 2] * 
height);
+            }
+            path.closePath();
+
+            g.fill(path);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return String.format("(f=%s)", getFitness());
+    }
+    
+    public static Chromosome randomChromosome(int polygonLength, int 
polygonCount) {
+        List<Polygon> list = new ArrayList<Polygon>(polygonCount);
+        for (int j = 0; j < polygonCount; j++) {
+            list.add(Polygon.randomPolygon(polygonLength));
+        }
+        return new PolygonChromosome(list);
+    }
+
+}

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/PolygonChromosome.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/PolygonChromosome.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision HeadURL

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/PolygonChromosome.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/RandomPolygonMutation.java
URL: 
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/RandomPolygonMutation.java?rev=1549696&view=auto
==============================================================================
--- 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/RandomPolygonMutation.java
 (added)
+++ 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/RandomPolygonMutation.java
 Mon Dec  9 22:34:28 2013
@@ -0,0 +1,33 @@
+package org.apache.commons.math3.userguide.genetics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math3.genetics.Chromosome;
+import org.apache.commons.math3.genetics.MutationPolicy;
+
+public class RandomPolygonMutation implements MutationPolicy {
+    
+    private float mutationRate;
+    private float mutationAmount;
+    
+    public RandomPolygonMutation(float mutationRate, float mutationAmount) {
+        this.mutationRate = mutationRate;
+        this.mutationAmount = mutationAmount;
+    }
+
+    public Chromosome mutate(Chromosome chromosome) {
+        if (!(chromosome instanceof PolygonChromosome)) {
+            throw new IllegalArgumentException();
+        }
+
+        PolygonChromosome polygons = (PolygonChromosome) chromosome;
+        List<Polygon> repr = polygons.getPolygonRepresentation();
+
+        List<Polygon> newRepr = new ArrayList<Polygon>(repr.size());
+        for (Polygon p : repr) {
+            newRepr.add(p.mutate(mutationRate, mutationAmount));
+        }
+        return new PolygonChromosome(newRepr);
+    }
+}

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/RandomPolygonMutation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/RandomPolygonMutation.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision HeadURL

Propchange: 
commons/proper/math/trunk/src/userguide/java/org/apache/commons/math3/userguide/genetics/RandomPolygonMutation.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain


Reply via email to