1. Rodrigo di Lorenzo Lopes
  2. Image Analyzer

Commits

Rodrigo Lorenzo  committed be840ad

initial commit

  • Participants
  • Branches master

Comments (0)

Files changed (6)

File .classpath

View file
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

File .gitignore

View file
+bin/

File .project

View file
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>image-search</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

File .settings/org.eclipse.jdt.core.prefs

View file
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6

File eyes.jpg

Added
New image

File src/ImageAnalyzer.java

View file
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.imageio.ImageIO;
+
+public class ImageAnalyzer {
+    private static final int DISTANCE = 50;
+    private static final int MAX_LEVELS = 8;
+    private static final int range = 12;
+    
+    static class Pair {
+        public Pair(Color color2, int weight) {
+            this.color = color2;
+            this.weight = weight;
+        }
+
+        int weight;
+        Color color;
+
+        @Override
+        public String toString() {
+            return color.toString() + ":" + weight;
+        }
+    }
+
+    private static BufferedWriter bufferedWriter;
+
+    public static void main(String[] args) throws IOException {
+        ImageAnalyzer analyzer = new ImageAnalyzer();
+        Map<Color, Pair> map = analyzer.getHistogram("veronika_zemanova_pyslocke_lab.gif");
+//        Map<Color, Pair> map = analyzer.getHistogram("analucia.jpg");
+        File file = new File("output.html");
+        bufferedWriter = new BufferedWriter(new FileWriter(file));
+        bufferedWriter.write("<html>\n<head>\n<style type=\"text/css\">\n.color_block {height: 100px; border-style:solid; border-width:1px; float: left; margin: 5px}\n</style>\n</head>\n");
+        bufferedWriter.write("<body>\n");
+        map = createBinMap(map);
+        Collection<Pair> pairs = new ArrayList<ImageAnalyzer.Pair>(map.values());
+//        pairs = joinClusters((List<Pair>) pairs);
+        printCluster(pairs);
+        bufferedWriter.write("</body>\n</html>");        
+        bufferedWriter.close();
+    }
+
+    static class Cluster implements Comparable<Cluster> {
+        public Cluster(Pair par1, Pair par2) {
+            this.par1 = par1;
+            this.par2 = par2;
+        }
+
+        Pair par1, par2;
+        Float distance = null;
+
+        float getDistance() {
+            if (distance == null) {
+                float[] p = getComponents(par1.color);
+                float[] q = getComponents(par2.color);
+                distance = distance(p, q);
+            }
+            return distance;
+        }
+
+        @Override
+        public int compareTo(Cluster cluster) {
+            return Float.compare(this.getDistance(), cluster.getDistance());
+        }
+
+        @Override
+        public String toString() {
+            return 
+//                    par1.toString() + ":" + par2.toString() + " - " + 
+                    Float.toString(getDistance());
+        }
+
+        public void destroy() {
+//            distance =null;
+            par1 = null;
+            par2 = null;
+        }
+    }
+
+    private static Collection<Pair> joinClusters(List<Pair> values) {
+        Set<Pair> pairs = new HashSet<Pair>(); // todos os vértices
+        TreeSet<Cluster> clusters = new TreeSet<Cluster>(); // todos as arestas
+        Map<Pair, List<Cluster>> map = new HashMap<Pair, List<Cluster>>();
+        for (int i = 0; i < values.size(); i++) {
+            pairs.add(values.get(i));
+            for (int j = i + 1; j < values.size(); j++) {
+                addNewCluster(clusters, map, values.get(i), values.get(j));
+            }
+        }
+        values.clear();
+        // pega a menor aresta
+        Cluster cluster = clusters.first();
+        float distance = cluster.getDistance();
+        while (distance < DISTANCE) {
+//            System.out.println("clusters:" + clusters.size() + "; pairs:" + pairs.size() + "; map:" +  map.size());
+//            System.out.println(cluster);
+//            if (distance > 100){
+//                System.out.println("Warning");
+//            }
+            clusters.pollFirst(); // remove a aresta
+            // cria novo vértice com o ponto médio da aresta
+            Pair newPair = createMedianPoint(cluster.par1, cluster.par2);
+//            System.out.println("new pair:" + newPair);
+            // remove vértices anteriores
+            pairs.remove(cluster.par1);
+            pairs.remove(cluster.par2);
+
+            for (Pair pair : pairs) {
+                addNewCluster(clusters, map, newPair, pair);
+            }
+            // remove todas as areastas dos vértices removidos
+            removeClustersFromPair(clusters, map, cluster.par1);
+            removeClustersFromPair(clusters, map, cluster.par2);            
+            pairs.add(newPair);
+            cluster = clusters.first();
+            distance = cluster.getDistance();
+        }
+        return pairs;
+    }
+
+    private static void removeClustersFromPair(TreeSet<Cluster> clusters, Map<Pair, List<Cluster>> map, Pair pair) {
+        List<Cluster> list = map.get(pair);
+        if (list == null)
+                return;
+        for (Cluster removeCluster : list) {
+            clusters.remove(removeCluster);
+        }
+        list.clear();
+        map.remove(pair);
+    }
+
+    private static void addNewCluster(TreeSet<Cluster> clusters, Map<Pair, List<Cluster>> map, Pair newPair, Pair pair) {
+        Cluster newCluster = new Cluster(newPair, pair);
+        clusters.add(newCluster);
+        // relaciona a aresta com o vértice
+        addListToMap(map, newPair, newCluster);
+        addListToMap(map, pair, newCluster);
+    }
+
+    private static void addListToMap(Map<Pair, List<Cluster>> map, Pair par1, Cluster cluster) {
+        List<Cluster> list = (List<Cluster>) map.get(par1);
+        if (list == null) {
+            list = new ArrayList<ImageAnalyzer.Cluster>();
+            map.put(par1, list);
+        }
+        list.add(cluster);
+    }
+
+    private static Map<Color, Pair> createBinMap(Map<Color, Pair> histogram) {
+        HashMap<Color, Pair> result = new HashMap<Color, Pair>();
+        for (Color color : histogram.keySet()) {
+            Color roundedColor = new Color(color.getRed() / range * range, color.getGreen() / range * range, color.getBlue() / range * range);
+            addColour(result, roundedColor, histogram.get(color));
+        }
+        return result;
+    }
+
+    private static Map<Color, Pair>[] multiMaps(Map<Color, Pair> histogram) {
+        Map<Color, Pair>[] result = new Map[MAX_LEVELS];
+        for (int level = 0; level < MAX_LEVELS; level++) {
+            result[level] = new HashMap<Color, Pair>();
+        }
+
+        for (Color color : histogram.keySet()) {
+            int div = 1;
+            for (int level = 0; level < MAX_LEVELS; level++) {
+                Map<Color, Pair> map = result[level];
+                int range = 256 / div;
+                Color roundedColor = new Color(color.getRed() / range * range, color.getGreen() / range * range, color.getBlue() / range * range);
+                addColour(map, roundedColor, histogram.get(color));
+                div = div << 1;
+            }
+        }
+        return result;
+    }
+
+    private static void printCluster(Collection<Pair> collection) throws IOException {
+        List<Pair> coloursList = new ArrayList<Pair>();
+        coloursList.addAll(collection);
+        Collections.sort(coloursList, new Comparator<Pair>() {
+
+            public int compare(Pair o1, Pair o2) {
+                return o2.weight - o1.weight;
+            }
+        });
+        int i = 0;
+        double weight = 0;
+        for (Pair colour : coloursList) {
+            weight += colour.weight;
+            if (++i > 20)
+                break;
+        }
+        i = 0;
+        for (Pair colour : coloursList) {
+            int reason = (int) (colour.weight / weight * 1500);
+            bufferedWriter.write("<div class=\"color_block\" style=\"background:" + toHex(colour.color) + " width:" + reason + "px; \">");
+            System.out.println(colour.color + ":" + colour.weight);
+            bufferedWriter.write("</div>\n");
+            // if (++i > 20) break;
+        }
+    }
+
+    private static String toHex(Color color) {
+        return "#" + Integer.toHexString(color.getRed()) + Integer.toHexString(color.getGreen()) + Integer.toHexString(color.getBlue()) + ";";
+
+    }
+
+    public Map<Color, Pair> getHistogram(String filename) throws IOException {
+        File file = new File(filename);
+        final BufferedImage image = ImageIO.read(file);
+        final Map<Color, Pair> colours = new HashMap<Color, Pair>();
+
+        for (int x = 0; x < image.getWidth(); x++) {
+            for (int y = 0; y < image.getHeight(); y++) {
+                addColour(colours, new Color(image.getRGB(x, y)));
+            }
+        }
+        return colours;
+
+    }
+
+    private static void addColour(Map<Color, Pair> colours, Color color, Pair input) {
+        Pair pair = colours.get(color);
+        if (pair == null) {
+            colours.put(color, input);
+            return;
+        }
+        colours.put(color, createMedianPoint(pair, input));
+    }
+
+    private static Pair createMedianPoint(Pair pair, Pair input) {
+        float[] p = getComponents(pair.color);
+        float[] q = getComponents(input.color);
+        float[] vector = createVector(p, q);
+        float per = input.weight / (float) (pair.weight + input.weight);
+        return new Pair(createColor(sumVectors(p, vectorResize(vector, per))), pair.weight + input.weight);
+    }
+
+    private static Color createColor(float[] p) {
+        return new Color((int) Math.round(p[0]), (int) Math.round(p[1]), (int) Math.round(p[2]));
+    }
+
+    private static float[] sumVectors(float[] p, float[] q) {
+        float[] result = new float[p.length];
+        for (int i = 0; i < p.length; i++) {
+            result[i] = p[i] + q[i];
+        }
+        return result;
+    }
+
+    private static float[] vectorResize(float[] p, float per) {
+        float[] result = new float[p.length];
+        for (int i = 0; i < p.length; i++) {
+            result[i] = p[i] * per;
+        }
+        return result;
+    }
+
+    private static float distance(float[] p, float[] q) {
+        float deltaR = q[0]- p[0];
+        float deltaG = q[1]- p[1];
+        float deltaB = q[2]- p[2];
+        float redmedian =  (q[0] + p[0])/2;
+        return (float) Math.sqrt((2 + redmedian/256)* deltaR * deltaR  + 4 *  deltaG * deltaG + (2 + (255- redmedian)/256)* deltaB * deltaB);
+    }
+
+    private static float[] createVector(float[] p, float[] q) {
+        float[] result = new float[p.length];
+        for (int i = 0; i < p.length; i++) {
+            result[i] = q[i] - p[i];
+        }
+        return result;
+    }
+
+    private static float[] getComponents(Color color) {
+        return new float[] { color.getRed(), color.getGreen(), color.getBlue() };
+    }
+
+    private static void addColour(Map<Color, Pair> colours, Color color) {
+        addColour(colours, color, new Pair(color, 1));
+    }
+}