Initial sharing of project
|  | @ -0,0 +1,81 @@ | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.io.File; | ||||||
|  | import java.awt.Color; | ||||||
|  | import java.awt.image.BufferedImage; | ||||||
|  | import javax.imageio.ImageIO; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Beschreiben Sie hier die Klasse Image. | ||||||
|  |  *  | ||||||
|  |  * @author Alexander Kimmig  | ||||||
|  |  * @version 1.0 | ||||||
|  |  */ | ||||||
|  | public class Image | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Liest eine JPG-Bilddatei ein und gibt diese als ArrayList von RGB-Objekten zurück | ||||||
|  |      *  | ||||||
|  |      * @param filename Dateiname die eingelesen werden soll | ||||||
|  |      * @return ArrayList<RGB> der einzelnen Pixelwerte | ||||||
|  |      * @throws Exception | ||||||
|  |      */ | ||||||
|  |     public static ArrayList<RGB> readFile(String filename) throws Exception { | ||||||
|  |         ArrayList<RGB> points = new ArrayList<>(); | ||||||
|  |          | ||||||
|  |         File file= new File(filename); | ||||||
|  |         BufferedImage img = ImageIO.read(file); | ||||||
|  |         for (int y = 0; y < img.getHeight(); y++) { | ||||||
|  |             for (int x = 0; x < img.getWidth(); x++) { | ||||||
|  |                 points.add(new RGB(img.getRGB(x,y))); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return points; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Schreibt die RGB-Daten in eine Datei | ||||||
|  |      *  | ||||||
|  |      * @param input Dateiname der ursprünglichen Datei (wird für Dimensionen gebraucht) | ||||||
|  |      * @param output Dateiname der neuen Datei | ||||||
|  |      * @param data RGB-Daten der einzelnen Pixel | ||||||
|  |      */ | ||||||
|  |     public static void writeFile(String input, String output, ArrayList<RGB> data) throws Exception { | ||||||
|  |         File file = new File(input); | ||||||
|  |         BufferedImage img = ImageIO.read(file); | ||||||
|  |          | ||||||
|  |         int w = img.getWidth(); | ||||||
|  |         int y = 0, x = 0; | ||||||
|  |         for (RGB p : data) { | ||||||
|  |             img.setRGB(x, y, p.toInt()); | ||||||
|  |             if (++x >= w) { | ||||||
|  |                 x = 0; | ||||||
|  |                 ++y; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         File f = new File(output); | ||||||
|  |         ImageIO.write(img, "jpg", f); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Schreibt die RGB-Daten in eine Datei anhand der Quantifizierungs-Punkte | ||||||
|  |      * Jeder Pixel bekommt die Farbe des nächstliegenden Quantifizierungs-Punktes. | ||||||
|  |      *  | ||||||
|  |      * @param input Dateiname der ursprünglichen Datei (wird für Dimensionen gebraucht) | ||||||
|  |      * @param output Dateiname der neuen Datei | ||||||
|  |      * @param data RGB-Daten der einzelnen Pixel | ||||||
|  |      * @param quants Quantifizierungs-Punkte | ||||||
|  |      */ | ||||||
|  |     public static void writeFile(String input, String target, ArrayList<RGB> data, ArrayList<RGB> quants) throws Exception { | ||||||
|  |         ArrayList<RGB> q = new ArrayList<>(); | ||||||
|  |          | ||||||
|  |         // Mappe punkte auf quantifizierte Punkte
 | ||||||
|  |         for (RGB p : data) { | ||||||
|  |             q.add(Quant.findNearest(quants, p)); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // schreibe Datei
 | ||||||
|  |         writeFile(input, target, q); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,200 @@ | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.Collections; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Funktionen, um quantifizierungs-Punkte zu finden | ||||||
|  |  *  | ||||||
|  |  * @author Alexander Kimmig | ||||||
|  |  * @version 1.0 | ||||||
|  |  */ | ||||||
|  | public class Quant | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Führt eine vollständige RGB-Qunatfizierung durch, Lädt die Datei | ||||||
|  |      * input.jpg im Projektordner und speichert das Ergebnis in output.jpg | ||||||
|  |      *  | ||||||
|  |      * @param count Anzahl, wie viele Quantifizierungs-Punkte gefunden werden solle | ||||||
|  |      * @param epoch Anzahl, wie viele Epochen durchlaufen werden sollen | ||||||
|  |      * @throws Exception falls Datei nicht existiert | ||||||
|  |      */ | ||||||
|  |     public static void quantize(int count, int epoch) throws Exception { | ||||||
|  |         ArrayList<RGB> ipoints = Image.readFile("./input.jpg"); | ||||||
|  | 
 | ||||||
|  |         ArrayList<RGB> quants = findQuants(count, epoch, ipoints); | ||||||
|  | 
 | ||||||
|  |         for (int i = 0; i < ipoints.size(); i++) { | ||||||
|  |             RGB p = ipoints.get(i); | ||||||
|  |             RGB t = findNearest(quants, p); | ||||||
|  |             p.r = t.r; | ||||||
|  |             p.g = t.g; | ||||||
|  |             p.b = t.b; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         Image.writeFile("./input.jpg", "./output.jpg", ipoints); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Findet Quantenpunkte | ||||||
|  |      *  | ||||||
|  |      * @param count Anzahl, wie viele Quantifizierungs-Punkte gefunden werden solle | ||||||
|  |      * @param epoch Anzahl, wie viele Epochen durchlaufen werden sollen | ||||||
|  |      * @param ipoints RGB-Datenpunkte des Bildes | ||||||
|  |      *  | ||||||
|  |      * @return ArrayList<RGB> mit den Quantenpunkten  | ||||||
|  |      * @throws Exception falls Datei nicht existiert | ||||||
|  |      */ | ||||||
|  |     public static ArrayList<RGB> findQuants(int count, int epoch, ArrayList<RGB> ipoints) throws Exception { | ||||||
|  |         ArrayList<RGB> qpoints = new ArrayList<>(); | ||||||
|  |          | ||||||
|  |         // Füge neue, zufällige Punkte hinzu
 | ||||||
|  |         for (int i = 0; i < count; i++) { | ||||||
|  |             qpoints.add(new RGB(true)); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         for (int i = 0; i < epoch; i++) { | ||||||
|  |             // Epoche durchlaufen
 | ||||||
|  |             doEpoch(ipoints, qpoints); | ||||||
|  |             // nich bewegte Quantenpunkte versetzen
 | ||||||
|  |             if (i < epoch-1) resetQuants(qpoints); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return qpoints; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Epoche durchlaufen | ||||||
|  |      *  | ||||||
|  |      * @param ipoints RGB-Bildpunkte | ||||||
|  |      * @param qpoints bisherige Quantenpunkte -> werden direkt verändert | ||||||
|  |      */ | ||||||
|  |     public static void doEpoch(ArrayList<RGB> ipoints, ArrayList<RGB> qpoints) { | ||||||
|  |         /* | ||||||
|  |          * WICHTIG: Bildpunkte mischen, da ansonsten die Punkte linear durchgegangen werden. | ||||||
|  |          * Bei großen Flächen am Ende (rechts unten) werden sonst viele Quantenpunkte in diesen | ||||||
|  |          * Bereich gezogen | ||||||
|  |          *  | ||||||
|  |          * Ausprobieren: deaktivieren und das Beispielbild "sonnenaufgang" | ||||||
|  |          */ | ||||||
|  |         Collections.shuffle(ipoints); | ||||||
|  |          | ||||||
|  |         /* | ||||||
|  |          * Eine Epoche: alle Bildpunkte einmal durchlaufen | ||||||
|  |          */ | ||||||
|  |         for (RGB t : ipoints) { | ||||||
|  |             // jeweils den nächstliegenden Quantenpunkt finden
 | ||||||
|  |             RGB q = findNearest(qpoints, t); | ||||||
|  |              | ||||||
|  |             // gegangener Weg speichern
 | ||||||
|  |             q.walk += t.diff2(q); | ||||||
|  |             q.count++; | ||||||
|  |              | ||||||
|  |             // den Punkt verschieben
 | ||||||
|  |             q.r = (q.r + t.r) / 2; | ||||||
|  |             q.g = (q.g + t.g) / 2; | ||||||
|  |             q.b = (q.b + t.b) / 2; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         for (RGB tmp : qpoints) { | ||||||
|  |             // falls Punkt verschoben: berechne mittlere gegangene Weglänge
 | ||||||
|  |             if (tmp.count > 0) { | ||||||
|  |                 tmp.walk = Math.max(1, tmp.walk / tmp.count); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Versetzt die Quantenpunkte, die im letzten Schritt nicht versetzt wurden, d.h. | ||||||
|  |      * diejenigen, die zu weit von der Punktwolke entfernt sind. | ||||||
|  |      *  | ||||||
|  |      * Hierfür setze diejenigen, die nicht gegangen sind in die Nähe derjeniger Punkte, | ||||||
|  |      * die besonders weit gelaufen sind (da dort ggf. underfitted) | ||||||
|  |      *  | ||||||
|  |      * @param qpoints Quantenpunkte | ||||||
|  |      * @return int wie viele Punkte wurden versetzt | ||||||
|  |      */ | ||||||
|  |     public static int resetQuants(ArrayList<RGB> qpoints) { | ||||||
|  |         int reset = 0; | ||||||
|  |         for (int i = 0; i < qpoints.size(); i++) { | ||||||
|  |             // finde denjenigen Punkt, der am wenigsten gelaufen ist
 | ||||||
|  |             RGB min = findMinWalk(qpoints); | ||||||
|  |             // wenn es keinen gibt oder dieser auch weit gelaufen ist, dann breche ab
 | ||||||
|  |             if (min == null || min.walk > 5) break; | ||||||
|  |              | ||||||
|  |             // finde denjenigen, der am weitesten gelaufen ist (dessen Bereich underfitted ist)
 | ||||||
|  |             RGB max = findMaxWalk(qpoints); | ||||||
|  |             // breche ab, falls dieser insgesamt auch sehr wenig gelaufen ist
 | ||||||
|  |             if (max.walk < 25) break; | ||||||
|  |              | ||||||
|  |             // passe den Wert an, damit dieser beim nächsten Schleifendurchlauf nicht mehr direkt gefunden wird
 | ||||||
|  |             max.walk -= 36; | ||||||
|  |              | ||||||
|  |             // setze den Nichtläufer zum Weitläufer
 | ||||||
|  |             min.setTo(max); | ||||||
|  |             // und variiere dessen Positionen um maximal ±5
 | ||||||
|  |             min.jitter(5); | ||||||
|  |             // walk = -1 -> nicht mehr weiter in diesem Durchlauf betrachten (nicht mehr als Minimum finden)
 | ||||||
|  |             min.walk = -1; | ||||||
|  |             // zähle die Anzahl der versetzten Punkte
 | ||||||
|  |             reset++; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // setze gelaufene Wege aller Punkte zurück
 | ||||||
|  |         for (RGB q : qpoints) { | ||||||
|  |             q.walk = q.count = 0; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return reset; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Finde denjenigen Punkt in der Liste, der am wenigsten weit gelaufen ist | ||||||
|  |      *  | ||||||
|  |      * @param quants Punktliste | ||||||
|  |      * @return RGB der Punkt, der am wenigsten gelaufen ist oder null | ||||||
|  |      */ | ||||||
|  |     private static RGB findMinWalk(ArrayList<RGB> quants) { | ||||||
|  |         RGB min = null; | ||||||
|  |         for (RGB tmp : quants) { | ||||||
|  |             if (tmp.walk >= 0 && (min == null || tmp.walk < min.walk)) { | ||||||
|  |                 min = tmp; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return min; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Finde denjenigen Punkt in der Liste, der am weitesten gelaufen ist | ||||||
|  |      *  | ||||||
|  |      * @param quants Punktliste | ||||||
|  |      * @return RGB der Punkt, der am weitesten gelaufen ist | ||||||
|  |      */ | ||||||
|  |     private static RGB findMaxWalk(ArrayList<RGB> quants) { | ||||||
|  |         RGB max = quants.get(0); | ||||||
|  |         for (RGB q : quants) { | ||||||
|  |             if (q.walk > max.walk) max = q; | ||||||
|  |         } | ||||||
|  |         return max; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Finde den Punkt in der Liste der die kürzeste Distanz zum Zielpunkt hat | ||||||
|  |      *  | ||||||
|  |      * @param points Liste der Punkte | ||||||
|  |      * @param target Zielpunkt | ||||||
|  |      * @return RGB Punkt mit kürzestem Abstand | ||||||
|  |      */ | ||||||
|  |     public static RGB findNearest(ArrayList<RGB> points, RGB target) { | ||||||
|  |         RGB nearest = points.get(0); | ||||||
|  |         int mind = target.diff2(nearest); | ||||||
|  |          | ||||||
|  |         for (RGB p : points) { | ||||||
|  |             int d = target.diff2(p); | ||||||
|  |             if (d < mind) { | ||||||
|  |                 nearest = p; | ||||||
|  |                 mind = d; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         return nearest; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | ------------------------------------------------------------------------ | ||||||
|  | Dies ist die README-Datei des Projekts. Hier sollten Sie Ihr Projekt | ||||||
|  | beschreiben. | ||||||
|  | Erzählen Sie dem Leser (jemand, der nichts über dieses Projekt weiss), | ||||||
|  | alles, was er/sie wissen muss. Üblicherweise sollte der Kommentar  | ||||||
|  | zumindest die folgenden Angaben umfassen: | ||||||
|  | ------------------------------------------------------------------------ | ||||||
|  | 
 | ||||||
|  | PROJEKTBEZEICHNUNG: | ||||||
|  | PROJEKTZWECK: | ||||||
|  | VERSION oder DATUM: | ||||||
|  | WIE IST DAS PROJEKT ZU STARTEN: | ||||||
|  | AUTOR(EN): | ||||||
|  | BENUTZERHINWEISE: | ||||||
|  | @ -0,0 +1,161 @@ | ||||||
|  | import java.awt.Color; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Repräsentiert einen Punkt im RGB-Raum | ||||||
|  |  *  | ||||||
|  |  * @author Alexander Kimmig  | ||||||
|  |  * @version 1.0 | ||||||
|  |  */ | ||||||
|  | public class RGB | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Rot-Anteil 0-255 | ||||||
|  |      */ | ||||||
|  |     public int r; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Grün-Anteil 0-255 | ||||||
|  |      */ | ||||||
|  |     public int g; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Blau-Anteil 0-255 | ||||||
|  |      */ | ||||||
|  |     public int b; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Wie weit ist der Punkt in der letzten Epoche gelaufen | ||||||
|  |      */ | ||||||
|  |     public int walk; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Wie oft ist der Punkt in der letzten Epoche gelaufen | ||||||
|  |      */ | ||||||
|  |     public int count; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Konstruktor | ||||||
|  |      *  | ||||||
|  |      * @param random Punkt zufällig setzen | ||||||
|  |      */ | ||||||
|  |     public RGB(boolean random) { | ||||||
|  |         this(0, 0, 0); | ||||||
|  |          | ||||||
|  |         if (random) this.setRandom(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Konstruktor | ||||||
|  |      *  | ||||||
|  |      * @param c ein awt.Color-Wert | ||||||
|  |      */ | ||||||
|  |     public RGB(Color c) { | ||||||
|  |         this(c.getRed(), c.getGreen(), c.getBlue()); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Konstruktor | ||||||
|  |      *  | ||||||
|  |      * @param c ein int-Wert 0xRRGGBB | ||||||
|  |      */ | ||||||
|  |     public RGB(int c) { | ||||||
|  |         this(c >> 16 & 0xFF, c >> 8 & 0xFF, c & 0xFF); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Konstruktor | ||||||
|  |      *  | ||||||
|  |      * @param r Rot-Anteil 0-255 | ||||||
|  |      * @param g Grün-Anteil 0-255 | ||||||
|  |      * @param b Blau-Anteil 0-255 | ||||||
|  |      */ | ||||||
|  |     public RGB(int r, int g, int b) { | ||||||
|  |         this.r = Math.min(255, Math.max(0, r)); | ||||||
|  |         this.g = Math.min(255, Math.max(0, g)); | ||||||
|  |         this.b = Math.min(255, Math.max(0, b)); | ||||||
|  |          | ||||||
|  |         this.walk = 0; | ||||||
|  |         this.count = 0; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Kopier-Konstruktor | ||||||
|  |      */ | ||||||
|  |     public RGB(RGB copy) { | ||||||
|  |         this(copy.r, copy.g, copy.b); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Ausgabe als String | ||||||
|  |      *  | ||||||
|  |      * @return String: "R, G, B" | ||||||
|  |      */ | ||||||
|  |     public String toString() { | ||||||
|  |         return this.r + "," + this.g + "," + this.b; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Ausgabe als awt.Color | ||||||
|  |      *  | ||||||
|  |      * @return awt.Color | ||||||
|  |      */ | ||||||
|  |     public Color toColor() { | ||||||
|  |         return new Color(this.r, this.g, this.b); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Ausgabe als int | ||||||
|  |      */ | ||||||
|  |     public int toInt() { | ||||||
|  |         return (this.r << 16) + (this.g << 8) + (this.b); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Setze zufällige Koordinaten | ||||||
|  |      */ | ||||||
|  |     public void setRandom() { | ||||||
|  |         this.r = (int)(Math.random() * 256); | ||||||
|  |         this.g = (int)(Math.random() * 256); | ||||||
|  |         this.b = (int)(Math.random() * 256); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Setze Koordinaten | ||||||
|  |      */ | ||||||
|  |     public void setTo(RGB p) { | ||||||
|  |         this.r = p.r; | ||||||
|  |         this.g = p.g; | ||||||
|  |         this.b = p.b; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Variiere Koordinaten ±max | ||||||
|  |      *  | ||||||
|  |      * @param max maximale verschiebung pro Achse | ||||||
|  |      */ | ||||||
|  |     public void jitter(int max) { | ||||||
|  |         this.r = Math.min(255, Math.max(0, this.r + ((int)(Math.random() * max * 2 - max)))); | ||||||
|  |         this.g = Math.min(255, Math.max(0, this.g + ((int)(Math.random() * max * 2 - max)))); | ||||||
|  |         this.b = Math.min(255, Math.max(0, this.b + ((int)(Math.random() * max * 2 - max)))); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Berechne den quadratischen Abstand zweier Punkte | ||||||
|  |      *  | ||||||
|  |      * @param a erster Punkt | ||||||
|  |      * @param b zweiter Punkt | ||||||
|  |      */ | ||||||
|  |     public static int diff2(RGB a, RGB b) { | ||||||
|  |         int dr = a.r - b.r; | ||||||
|  |         int dg = a.g - b.g; | ||||||
|  |         int db = a.b - b.b; | ||||||
|  |         return dr*dr + dg*dg + db*db; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Berechne den quadratischen Abstand zu einem anderen Punkt | ||||||
|  |      */ | ||||||
|  |     public int diff2(RGB b) { | ||||||
|  |         return RGB.diff2(this, b); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,251 @@ | ||||||
|  | import ChartDirector.*; | ||||||
|  | import javax.swing.*; | ||||||
|  | import java.awt.*; | ||||||
|  | import java.awt.event.*; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.io.File; | ||||||
|  | import java.util.Collections; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Zeigt das Fenster an mit allen Komponenten | ||||||
|  |  *  | ||||||
|  |  * @author Alexander Kimmig  | ||||||
|  |  * @version 1.0 | ||||||
|  |  */ | ||||||
|  | public class Window implements ActionListener | ||||||
|  | { | ||||||
|  |     private JFrame frame; | ||||||
|  |     private JPanel drawPanel; | ||||||
|  |      | ||||||
|  |     private ArrayList<RGB> image; | ||||||
|  |     private ArrayList<RGB> orig; | ||||||
|  |     private ArrayList<RGB> quants; | ||||||
|  |      | ||||||
|  |     private int alpha = 25; | ||||||
|  |     private int beta = 45; | ||||||
|  |      | ||||||
|  |     private JButton vl; | ||||||
|  |     private JButton vr; | ||||||
|  |     private JButton vu; | ||||||
|  |     private JButton vd; | ||||||
|  |      | ||||||
|  |     private JButton b_load; | ||||||
|  |     private JButton b_gen; | ||||||
|  |     private JButton b_epoc; | ||||||
|  |     private JButton b_reset; | ||||||
|  |     private JButton b_save; | ||||||
|  | 
 | ||||||
|  |     private JComboBox s_input; | ||||||
|  |     private JTextField t_anz; | ||||||
|  |     private JTextField t_output; | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Konstruktor: legt JFrame und alle Panels/Buttons an | ||||||
|  |      */ | ||||||
|  |     public Window() | ||||||
|  |     { | ||||||
|  |         frame = new JFrame(); | ||||||
|  |         frame.addWindowListener(new WindowAdapter() { | ||||||
|  |             public void windowClosing(WindowEvent e) { System.exit(0); } | ||||||
|  |         }); | ||||||
|  |          | ||||||
|  |         JPanel mainPanel = new JPanel(); | ||||||
|  |         mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); | ||||||
|  |          | ||||||
|  |         drawPanel = new JPanel(); | ||||||
|  |         drawPanel.setPreferredSize(new Dimension(1000, 1000)); | ||||||
|  |         drawPanel.setBackground(new Color(0xFFFFFF)); | ||||||
|  |         JPanel view = new JPanel(); | ||||||
|  |         JPanel steps = new JPanel(); | ||||||
|  |         JPanel config = new JPanel(); | ||||||
|  | 
 | ||||||
|  |         mainPanel.add(drawPanel); | ||||||
|  |         mainPanel.add(view); | ||||||
|  |         mainPanel.add(steps); | ||||||
|  |         mainPanel.add(config); | ||||||
|  |          | ||||||
|  |         vl = new JButton("<"); | ||||||
|  |         vl.addActionListener(this); | ||||||
|  |         view.add(vl); | ||||||
|  |         vr = new JButton(">"); | ||||||
|  |         vr.addActionListener(this); | ||||||
|  |         view.add(vr); | ||||||
|  |         vu = new JButton("^"); | ||||||
|  |         vu.addActionListener(this); | ||||||
|  |         view.add(vu); | ||||||
|  |         vd = new JButton("v"); | ||||||
|  |         vd.addActionListener(this); | ||||||
|  |         view.add(vd); | ||||||
|  |          | ||||||
|  |         b_load = new JButton("Datei laden"); | ||||||
|  |         b_load.addActionListener(this); | ||||||
|  |         steps.add(b_load); | ||||||
|  |          | ||||||
|  |         b_gen = new JButton("Zufällige Punkte erzeugen"); | ||||||
|  |         b_gen.addActionListener(this); | ||||||
|  |         steps.add(b_gen); | ||||||
|  | 
 | ||||||
|  |         b_epoc = new JButton("Epoche durchspielen"); | ||||||
|  |         b_epoc.addActionListener(this); | ||||||
|  |         steps.add(b_epoc); | ||||||
|  | 
 | ||||||
|  |         b_reset = new JButton("Punkte versetzen"); | ||||||
|  |         b_reset.addActionListener(this); | ||||||
|  |         steps.add(b_reset); | ||||||
|  |          | ||||||
|  |         b_save = new JButton("Datei speichern"); | ||||||
|  |         b_save.addActionListener(this); | ||||||
|  |         steps.add(b_save); | ||||||
|  |          | ||||||
|  |         config.add(new JLabel("Input:")); | ||||||
|  |         s_input = new JComboBox(getJPGs()); | ||||||
|  |         config.add(s_input); | ||||||
|  | 
 | ||||||
|  |         config.add(new JLabel("Anzahl Punkte:")); | ||||||
|  |         t_anz = new JTextField("32"); | ||||||
|  |         t_anz.setPreferredSize(new Dimension(100,20)); | ||||||
|  |         config.add(t_anz); | ||||||
|  | 
 | ||||||
|  |         config.add(new JLabel("Output:")); | ||||||
|  |         t_output = new JTextField("output.jpg"); | ||||||
|  |         t_output.setPreferredSize(new Dimension(100,20)); | ||||||
|  |         config.add(t_output); | ||||||
|  | 
 | ||||||
|  |         frame.add(mainPanel); | ||||||
|  | 
 | ||||||
|  |         frame.pack(); | ||||||
|  |         frame.setVisible(true); | ||||||
|  |          | ||||||
|  |         this.image = new ArrayList<>(); | ||||||
|  |         this.quants = new ArrayList<>(); | ||||||
|  |          | ||||||
|  |         this.plot(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * plottet die Punkte in ein 3D-Scatter-Plot und zeigt dieses an | ||||||
|  |      */ | ||||||
|  |     public void plot() | ||||||
|  |     { | ||||||
|  |         ChartViewer viewer = new ChartViewer(); | ||||||
|  |          | ||||||
|  |         // Einstellungen setzen
 | ||||||
|  |         ThreeDScatterChart c = new ThreeDScatterChart(1000, 1000); | ||||||
|  |         c.setPlotRegion(500, 480, 600, 600, 450); | ||||||
|  |         c.xAxis().setTitle("R", "Arial Bold", 10); | ||||||
|  |         c.yAxis().setTitle("G", "Arial Bold", 10); | ||||||
|  |         c.zAxis().setTitle("B", "Arial Bold", 10); | ||||||
|  |         c.xAxis().setDateScale(0, 255); | ||||||
|  |         c.yAxis().setDateScale(0, 255); | ||||||
|  |         c.zAxis().setDateScale(0, 255); | ||||||
|  |         c.setViewAngle(alpha, beta); | ||||||
|  |          | ||||||
|  |         // Bildpunkte
 | ||||||
|  |         double[] x = new double[image.size()]; | ||||||
|  |         double[] y = new double[image.size()]; | ||||||
|  |         double[] z = new double[image.size()]; | ||||||
|  |         for (int i = 0; i < image.size(); i++) { | ||||||
|  |             x[i] = image.get(i).r; | ||||||
|  |             y[i] = image.get(i).g; | ||||||
|  |             z[i] = image.get(i).b; | ||||||
|  |         } | ||||||
|  |         //               Koordinaten    Form        Größe  Farbe ARGB  Rahmen ARGB
 | ||||||
|  |         c.addScatterGroup(x,y,z, "", Chart.CircleShape, 5, 0xE0FF0000, 0xFF000000); | ||||||
|  |          | ||||||
|  |         // Quantenpunkte
 | ||||||
|  |         x = new double[quants.size()]; | ||||||
|  |         y = new double[quants.size()]; | ||||||
|  |         z = new double[quants.size()]; | ||||||
|  |         for (int i = 0; i < quants.size(); i++) { | ||||||
|  |             x[i] = quants.get(i).r; | ||||||
|  |             y[i] = quants.get(i).g; | ||||||
|  |             z[i] = quants.get(i).b; | ||||||
|  |         } | ||||||
|  |         c.addScatterGroup(x,y,z, "", Chart.CircleShape, 12); | ||||||
|  |          | ||||||
|  |         viewer.setChart(c); | ||||||
|  |          | ||||||
|  |         drawPanel.removeAll(); | ||||||
|  |         drawPanel.add(viewer); | ||||||
|  |          | ||||||
|  |         frame.pack(); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Lies die vorhandenen JPG-Dateien aus dem Ordner inputs aus | ||||||
|  |      *  | ||||||
|  |      * @return String[] Dateinamen | ||||||
|  |      */ | ||||||
|  |     private String[] getJPGs() { | ||||||
|  |         ArrayList<String> result = new ArrayList<String>(); | ||||||
|  |          | ||||||
|  |         File d = new File("./inputs/"); | ||||||
|  |         File[] list = d.listFiles(); | ||||||
|  |         for(int i=0; i<list.length; i++) { | ||||||
|  |             String n = list[i].getName(); | ||||||
|  |             // nur JPG-Bilder
 | ||||||
|  |             if (n.matches(".*\\.[jJ][pP][eE]?[gG]$")) { | ||||||
|  |                 result.add(n); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         String[] ret = new String[result.size()]; | ||||||
|  |         return result.toArray(ret); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Button-Reaktivität | ||||||
|  |      *  | ||||||
|  |      * @param e ActionEvent | ||||||
|  |      */ | ||||||
|  |     public void actionPerformed(ActionEvent e) { | ||||||
|  |         /** | ||||||
|  |          * Pfeilbuttons: Ändern der Ansicht | ||||||
|  |          */ | ||||||
|  |         if (e.getSource() == this.vr) beta = (beta + 345) % 360; | ||||||
|  |         if (e.getSource() == this.vl) beta = (beta + 15) % 360; | ||||||
|  |         if (e.getSource() == this.vu) alpha = (alpha + 345) % 360; | ||||||
|  |         if (e.getSource() == this.vd) alpha = (alpha + 15) % 360; | ||||||
|  |          | ||||||
|  |         /** | ||||||
|  |          * Datei laden und RGB-Daten in ArrayList speichern | ||||||
|  |          */ | ||||||
|  |         if (e.getSource() == this.b_load) { | ||||||
|  |             try { | ||||||
|  |                 this.orig = Image.readFile("./inputs/" + (String)this.s_input.getSelectedItem()); | ||||||
|  |                 for (RGB p : this.orig) { | ||||||
|  |                     // kopiere die originalen Daten, damit die Liste später gemischt werden kann
 | ||||||
|  |                     this.image.add(p); | ||||||
|  |                 } | ||||||
|  |             } catch (Exception ex) {} | ||||||
|  |         } | ||||||
|  |         /** | ||||||
|  |          * Zufällige Punkte erzeugen | ||||||
|  |          */ | ||||||
|  |         if (e.getSource() == this.b_gen) { | ||||||
|  |             this.quants = new ArrayList<>(); | ||||||
|  |             for (int i = 0; i < Integer.parseInt(this.t_anz.getText()); i++) { | ||||||
|  |                 this.quants.add(new RGB(true)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         /** | ||||||
|  |          * Epoche durchlaufen | ||||||
|  |          */ | ||||||
|  |         if (e.getSource() == this.b_epoc) Quant.doEpoch(this.image, this.quants); | ||||||
|  |         /** | ||||||
|  |          * Nicht bewegte Punkte versetzen | ||||||
|  |          */ | ||||||
|  |         if (e.getSource() == this.b_reset) Quant.resetQuants(this.quants); | ||||||
|  |         /** | ||||||
|  |          * quantifiziertes Bild speichern | ||||||
|  |          */ | ||||||
|  |         if (e.getSource() == this.b_save) { | ||||||
|  |             try { | ||||||
|  |                 Image.writeFile("./inputs/" + (String)this.s_input.getSelectedItem(), "./outputs/" + this.t_output.getText(), this.orig, this.quants); | ||||||
|  |             } catch (Exception ex) {} | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // neue Anzeige rendern
 | ||||||
|  |         this.plot(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| After Width: | Height: | Size: 145 KiB | 
| After Width: | Height: | Size: 72 KiB | 
| After Width: | Height: | Size: 204 KiB | 
| After Width: | Height: | Size: 16 KiB | 
| After Width: | Height: | Size: 122 KiB | 
| After Width: | Height: | Size: 43 KiB | 
| After Width: | Height: | Size: 63 KiB | 
| After Width: | Height: | Size: 30 KiB | 
| After Width: | Height: | Size: 30 KiB | 
| After Width: | Height: | Size: 88 KiB | 
| After Width: | Height: | Size: 88 KiB | 
| After Width: | Height: | Size: 45 KiB | 
| After Width: | Height: | Size: 64 KiB | 
| After Width: | Height: | Size: 62 KiB | 
| After Width: | Height: | Size: 70 KiB | 
| After Width: | Height: | Size: 78 KiB | 
| After Width: | Height: | Size: 86 KiB | 
| After Width: | Height: | Size: 56 KiB | 
| After Width: | Height: | Size: 57 KiB | 
| After Width: | Height: | Size: 47 KiB | 
| After Width: | Height: | Size: 54 KiB | 
| After Width: | Height: | Size: 1.4 MiB | 
| After Width: | Height: | Size: 15 KiB | 
| After Width: | Height: | Size: 12 KiB | 
|  | @ -0,0 +1,74 @@ | ||||||
|  | #BlueJ package file | ||||||
|  | dependency1.from=Image | ||||||
|  | dependency1.to=RGB | ||||||
|  | dependency1.type=UsesDependency | ||||||
|  | dependency2.from=Image | ||||||
|  | dependency2.to=Quant | ||||||
|  | dependency2.type=UsesDependency | ||||||
|  | dependency3.from=Quant | ||||||
|  | dependency3.to=RGB | ||||||
|  | dependency3.type=UsesDependency | ||||||
|  | dependency4.from=Quant | ||||||
|  | dependency4.to=Image | ||||||
|  | dependency4.type=UsesDependency | ||||||
|  | dependency5.from=Window | ||||||
|  | dependency5.to=RGB | ||||||
|  | dependency5.type=UsesDependency | ||||||
|  | dependency6.from=Window | ||||||
|  | dependency6.to=Image | ||||||
|  | dependency6.type=UsesDependency | ||||||
|  | dependency7.from=Window | ||||||
|  | dependency7.to=Quant | ||||||
|  | dependency7.type=UsesDependency | ||||||
|  | editor.fx.0.height=0 | ||||||
|  | editor.fx.0.width=0 | ||||||
|  | editor.fx.0.x=0 | ||||||
|  | editor.fx.0.y=0 | ||||||
|  | objectbench.height=100 | ||||||
|  | objectbench.width=595 | ||||||
|  | package.divider.horizontal=0.599601593625498 | ||||||
|  | package.divider.vertical=0.8102836879432624 | ||||||
|  | package.editor.height=450 | ||||||
|  | package.editor.width=885 | ||||||
|  | package.editor.x=0 | ||||||
|  | package.editor.y=25 | ||||||
|  | package.frame.height=628 | ||||||
|  | package.frame.width=1024 | ||||||
|  | package.numDependencies=7 | ||||||
|  | package.numTargets=4 | ||||||
|  | package.showExtends=true | ||||||
|  | package.showUses=true | ||||||
|  | project.charset=UTF-8 | ||||||
|  | readme.height=60 | ||||||
|  | readme.name=@README | ||||||
|  | readme.width=48 | ||||||
|  | readme.x=10 | ||||||
|  | readme.y=10 | ||||||
|  | target1.height=70 | ||||||
|  | target1.name=Window | ||||||
|  | target1.showInterface=false | ||||||
|  | target1.type=ClassTarget | ||||||
|  | target1.width=120 | ||||||
|  | target1.x=150 | ||||||
|  | target1.y=280 | ||||||
|  | target2.height=70 | ||||||
|  | target2.name=Image | ||||||
|  | target2.showInterface=false | ||||||
|  | target2.type=ClassTarget | ||||||
|  | target2.width=120 | ||||||
|  | target2.x=320 | ||||||
|  | target2.y=190 | ||||||
|  | target3.height=70 | ||||||
|  | target3.name=RGB | ||||||
|  | target3.showInterface=false | ||||||
|  | target3.type=ClassTarget | ||||||
|  | target3.width=120 | ||||||
|  | target3.x=320 | ||||||
|  | target3.y=10 | ||||||
|  | target4.height=70 | ||||||
|  | target4.name=Quant | ||||||
|  | target4.showInterface=false | ||||||
|  | target4.type=ClassTarget | ||||||
|  | target4.width=120 | ||||||
|  | target4.x=460 | ||||||
|  | target4.y=100 | ||||||