commit 2b6277cef2043016076e2aaaa59486b55e9ed507 Author: Alexander Kimmig Date: Fri Oct 20 16:07:01 2023 +0200 Initial sharing of project diff --git a/ChartDirector_s.jar b/ChartDirector_s.jar new file mode 100644 index 0000000..1f782d7 Binary files /dev/null and b/ChartDirector_s.jar differ diff --git a/Image.java b/Image.java new file mode 100644 index 0000000..3be578c --- /dev/null +++ b/Image.java @@ -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 der einzelnen Pixelwerte + * @throws Exception + */ + public static ArrayList readFile(String filename) throws Exception { + ArrayList 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 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 data, ArrayList quants) throws Exception { + ArrayList q = new ArrayList<>(); + + // Mappe punkte auf quantifizierte Punkte + for (RGB p : data) { + q.add(Quant.findNearest(quants, p)); + } + + // schreibe Datei + writeFile(input, target, q); + } +} diff --git a/Quant.java b/Quant.java new file mode 100644 index 0000000..1e83522 --- /dev/null +++ b/Quant.java @@ -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 ipoints = Image.readFile("./input.jpg"); + + ArrayList 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 mit den Quantenpunkten + * @throws Exception falls Datei nicht existiert + */ + public static ArrayList findQuants(int count, int epoch, ArrayList ipoints) throws Exception { + ArrayList 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 ipoints, ArrayList 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 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 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 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 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; + } +} diff --git a/README.TXT b/README.TXT new file mode 100644 index 0000000..0ad193f --- /dev/null +++ b/README.TXT @@ -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: diff --git a/RGB.java b/RGB.java new file mode 100644 index 0000000..a1b2e5d --- /dev/null +++ b/RGB.java @@ -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); + } +} diff --git a/Window.java b/Window.java new file mode 100644 index 0000000..0512d86 --- /dev/null +++ b/Window.java @@ -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 image; + private ArrayList orig; + private ArrayList 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 result = new ArrayList(); + + File d = new File("./inputs/"); + File[] list = d.listFiles(); + for(int i=0; i(); + 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(); + } +} diff --git a/inputs/ara.jpg b/inputs/ara.jpg new file mode 100644 index 0000000..bd9f244 Binary files /dev/null and b/inputs/ara.jpg differ diff --git a/inputs/gras.jpg b/inputs/gras.jpg new file mode 100644 index 0000000..ad92e5d Binary files /dev/null and b/inputs/gras.jpg differ diff --git a/inputs/jaguar.jpg b/inputs/jaguar.jpg new file mode 100644 index 0000000..1d65c7d Binary files /dev/null and b/inputs/jaguar.jpg differ diff --git a/inputs/jaguar_klein.jpg b/inputs/jaguar_klein.jpg new file mode 100644 index 0000000..dcf6d39 Binary files /dev/null and b/inputs/jaguar_klein.jpg differ diff --git a/inputs/kaiman.jpg b/inputs/kaiman.jpg new file mode 100644 index 0000000..a93d0c9 Binary files /dev/null and b/inputs/kaiman.jpg differ diff --git a/inputs/sonnenaufgang.jpg b/inputs/sonnenaufgang.jpg new file mode 100644 index 0000000..3b23992 Binary files /dev/null and b/inputs/sonnenaufgang.jpg differ diff --git a/outputs/ara32.jpg b/outputs/ara32.jpg new file mode 100644 index 0000000..09e27cc Binary files /dev/null and b/outputs/ara32.jpg differ diff --git a/outputs/gras32.jpg b/outputs/gras32.jpg new file mode 100644 index 0000000..171a812 Binary files /dev/null and b/outputs/gras32.jpg differ diff --git a/outputs/gras64.jpg b/outputs/gras64.jpg new file mode 100644 index 0000000..f977147 Binary files /dev/null and b/outputs/gras64.jpg differ diff --git a/outputs/jaguar16-2.jpg b/outputs/jaguar16-2.jpg new file mode 100644 index 0000000..4ee0762 Binary files /dev/null and b/outputs/jaguar16-2.jpg differ diff --git a/outputs/jaguar16.jpg b/outputs/jaguar16.jpg new file mode 100644 index 0000000..e0ebe7a Binary files /dev/null and b/outputs/jaguar16.jpg differ diff --git a/outputs/jaguar2.jpg b/outputs/jaguar2.jpg new file mode 100644 index 0000000..4740acd Binary files /dev/null and b/outputs/jaguar2.jpg differ diff --git a/outputs/jaguar3.jpg b/outputs/jaguar3.jpg new file mode 100644 index 0000000..9e7c210 Binary files /dev/null and b/outputs/jaguar3.jpg differ diff --git a/outputs/jaguar4.jpg b/outputs/jaguar4.jpg new file mode 100644 index 0000000..2c64f24 Binary files /dev/null and b/outputs/jaguar4.jpg differ diff --git a/outputs/jaguar5.jpg b/outputs/jaguar5.jpg new file mode 100644 index 0000000..169c762 Binary files /dev/null and b/outputs/jaguar5.jpg differ diff --git a/outputs/jaguar6.jpg b/outputs/jaguar6.jpg new file mode 100644 index 0000000..c804173 Binary files /dev/null and b/outputs/jaguar6.jpg differ diff --git a/outputs/jaguar64.jpg b/outputs/jaguar64.jpg new file mode 100644 index 0000000..e58cc8f Binary files /dev/null and b/outputs/jaguar64.jpg differ diff --git a/outputs/kaiman32-2.jpg b/outputs/kaiman32-2.jpg new file mode 100644 index 0000000..ab1face Binary files /dev/null and b/outputs/kaiman32-2.jpg differ diff --git a/outputs/kaiman32-3.jpg b/outputs/kaiman32-3.jpg new file mode 100644 index 0000000..5525cbc Binary files /dev/null and b/outputs/kaiman32-3.jpg differ diff --git a/outputs/kaiman32.jpg b/outputs/kaiman32.jpg new file mode 100644 index 0000000..527d4e6 Binary files /dev/null and b/outputs/kaiman32.jpg differ diff --git a/outputs/output.jpg b/outputs/output.jpg new file mode 100644 index 0000000..1a68b82 Binary files /dev/null and b/outputs/output.jpg differ diff --git a/outputs/output_groß32.jpg b/outputs/output_groß32.jpg new file mode 100644 index 0000000..53a34f7 Binary files /dev/null and b/outputs/output_groß32.jpg differ diff --git a/outputs/sonne.jpg b/outputs/sonne.jpg new file mode 100644 index 0000000..df7a9d3 Binary files /dev/null and b/outputs/sonne.jpg differ diff --git a/outputs/sonnenaufgang256.jpg b/outputs/sonnenaufgang256.jpg new file mode 100644 index 0000000..65bd59a Binary files /dev/null and b/outputs/sonnenaufgang256.jpg differ diff --git a/package.bluej b/package.bluej new file mode 100644 index 0000000..f4b2b9a --- /dev/null +++ b/package.bluej @@ -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