v1.1 noch ohne Kommentare

master
Alexander Kimmig 2023-10-27 17:41:33 +02:00
parent 35378ef3fe
commit 1a0376ec61
6 changed files with 436 additions and 10 deletions

View File

@ -33,14 +33,29 @@ public class Image
return points; return points;
} }
/**
* Liest eine JPG-Bilddatei ein und gibt diese als ArrayList von RGB-Objekten zurück
*
* @param filename Dateiname die eingelesen werden soll
* @return BufferedImage
* @throws Exception
*/
public static BufferedImage loadFile(String filename) throws Exception {
ArrayList<RGB> points = new ArrayList<>();
File file= new File(filename);
return ImageIO.read(file);
}
/** /**
* Schreibt die RGB-Daten in eine Datei * Schreibt die RGB-Daten in eine Datei
* *
* @param input Dateiname der ursprünglichen Datei (wird für Dimensionen gebraucht) * @param input Dateiname der ursprünglichen Datei (wird für Dimensionen gebraucht)
* @param output Dateiname der neuen Datei * @param output Dateiname der neuen Datei
* @param data RGB-Daten der einzelnen Pixel * @param data RGB-Daten der einzelnen Pixel
* @return BufferedImage
*/ */
public static void writeFile(String input, String output, ArrayList<RGB> data) throws Exception { public static BufferedImage writeFile(String input, String output, ArrayList<RGB> data) throws Exception {
File file = new File(input); File file = new File(input);
BufferedImage img = ImageIO.read(file); BufferedImage img = ImageIO.read(file);
@ -54,8 +69,12 @@ public class Image
} }
} }
File f = new File(output); if (output != "") {
ImageIO.write(img, "jpg", f); File f = new File(output);
ImageIO.write(img, "jpg", f);
}
return img;
} }
/** /**
@ -66,8 +85,9 @@ public class Image
* @param output Dateiname der neuen Datei * @param output Dateiname der neuen Datei
* @param data RGB-Daten der einzelnen Pixel * @param data RGB-Daten der einzelnen Pixel
* @param quants Quantifizierungs-Punkte * @param quants Quantifizierungs-Punkte
* @return BufferedImage
*/ */
public static void writeFile(String input, String target, ArrayList<RGB> data, ArrayList<RGB> quants) throws Exception { public static BufferedImage writeFile(String input, String target, ArrayList<RGB> data, ArrayList<RGB> quants) throws Exception {
ArrayList<RGB> q = new ArrayList<>(); ArrayList<RGB> q = new ArrayList<>();
// Mappe punkte auf quantifizierte Punkte // Mappe punkte auf quantifizierte Punkte
@ -76,6 +96,6 @@ public class Image
} }
// schreibe Datei // schreibe Datei
writeFile(input, target, q); return writeFile(input, target, q);
} }
} }

399
OGL_Window.java Normal file
View File

@ -0,0 +1,399 @@
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.GLAutoDrawable;
import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import javax.swing.JFrame;
import java.awt.Color;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.io.File;
import java.util.Collections;
import java.awt.image.BufferedImage;
public class OGL_Window implements GLEventListener, KeyListener, ActionListener {
private int imgHeight = 200;
private JFrame frame;
private JPanel drawPanel;
private JPanel drawImg;
private JPanel drawQImg;
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;
private final GLCanvas glcanvas;
private ArrayList<RGB> image;
private ArrayList<RGB> orig;
private ArrayList<RGB> quants;
private BufferedImage img;
private BufferedImage qimg;
private int azimut = 25;
private int rot = 45;
@Override
public void display(GLAutoDrawable drawable) {
final GL2 gl = drawable.getGL().getGL2();
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT | GL2.GL_STENCIL_BUFFER_BIT);
final GLU glu = GLU.createGLU(gl);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
double w = this.drawPanel.getWidth();
double h = this.drawPanel.getHeight();
glu.gluPerspective(45,w/h,0.1,100);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
glu.gluLookAt(
0,0,3,
0,0,0,
0,1,0
);
gl.glRotatef(this.azimut,1,0,0);
gl.glRotatef(-this.rot,0,1,0);
gl.glLineWidth(5);
gl.glBegin(GL2.GL_LINES);
gl.glColor4f(0,0,0,1);
gl.glVertex3f(0,0,0);
gl.glColor4f(1,0,0,1);
gl.glVertex3f(1,0,0);
gl.glColor4f(0,0,0,1);
gl.glVertex3f(0,0,0);
gl.glColor4f(0,1,0,1);
gl.glVertex3f(0,1,0);
gl.glColor4f(0,0,0,1);
gl.glVertex3f(0,0,0);
gl.glColor4f(0,0,1,1);
gl.glVertex3f(0,0,1);
gl.glEnd();
gl.glEnable(GL2.GL_BLEND);
gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
gl.glPointSize(8);
gl.glBegin(GL2.GL_POINTS);
for (RGB p : this.image) {
gl.glColor4f(((float)(p.r))/256/4,((float)(p.g))/256/4,((float)(p.b))/256/4,0.15f);
gl.glVertex3f(
((float)(p.r))/256,
((float)(p.g))/256,
((float)(p.b))/256
);
}
gl.glEnd();
gl.glPointSize(20);
gl.glBegin(GL2.GL_POINTS);
for (RGB p : this.quants) {
gl.glColor4f(((float)(p.r))/256,((float)(p.g))/256,((float)(p.b))/256,1f);
gl.glVertex3f(
((float)(p.r))/256,
((float)(p.g))/256,
((float)(p.b))/256
);
}
gl.glEnd();
gl.glPointSize(20);
gl.glBegin(GL2.GL_POINTS);
gl.glColor4ub((byte)0,(byte)0,(byte)0,(byte)255);
gl.glVertex3f(0,0,0);
gl.glEnd();
}
@Override
public void dispose(GLAutoDrawable arg0) {}
@Override
public void init(GLAutoDrawable drawable) {}
@Override
public void reshape(GLAutoDrawable drawable, int arg1, int arg2, int arg3, int arg4) {}
@Override
public void keyPressed(KeyEvent e) {}
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
this.rot += 15;
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
this.rot -= 15;
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
this.azimut -= 15;
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
this.azimut += 15;
} else {
return;
}
this.glcanvas.repaint();
}
private OGL_Window() {
this.image = new ArrayList<>();
this.orig = new ArrayList<>();
this.quants = new ArrayList<>();
//getting the capabilities object of GL2 profile
final GLProfile profile = GLProfile.get(GLProfile.GL2);
GLCapabilities capabilities = new GLCapabilities(profile);
capabilities.setBackgroundOpaque(false);
// The canvas
glcanvas = new GLCanvas(capabilities);
glcanvas.addGLEventListener(this);
glcanvas.setSize(500, 500);
glcanvas.setBackground(new Color(220, 220, 220));
glcanvas.addKeyListener(this);
OGL_Window that = this;
//creating frame
frame = new JFrame("RGB Quantisierer");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
frame.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
int width = (int)that.frame.getSize().getWidth();
int height = (int)that.frame.getSize().getHeight() - 160 - that.imgHeight;
that.glcanvas.setSize(width, height);
that.drawPanel.setSize(new Dimension(width, height));
}
});
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
drawPanel = new JPanel();
JPanel view = new JPanel();
JPanel steps = new JPanel();
JPanel config = new JPanel();
JPanel images = new JPanel();
mainPanel.add(drawPanel);
mainPanel.add(view);
mainPanel.add(steps);
mainPanel.add(config);
mainPanel.add(images);
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);
drawImg = new JPanel();
drawImg.setPreferredSize(new Dimension(this.imgHeight + 50,this.imgHeight + 10));
drawQImg = new JPanel();
drawQImg.setPreferredSize(new Dimension(this.imgHeight + 50,this.imgHeight + 10));
images.add(drawImg);
images.add(drawQImg);
frame.add(mainPanel);
drawPanel.add(glcanvas);
frame.pack();
frame.setVisible(true);
}
/**
* Button-Reaktivität
*
* @param e ActionEvent
*/
public void actionPerformed(ActionEvent e) {
/**
* Pfeilbuttons: Ändern der Ansicht
*/
if (e.getSource() == this.vr) this.rot = (this.rot + 345) % 360;
if (e.getSource() == this.vl) this.rot = (this.rot + 15) % 360;
if (e.getSource() == this.vu) this.azimut = (this.azimut + 345) % 360;
if (e.getSource() == this.vd) this.azimut = (this.azimut + 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());
this.img = Image.loadFile("./inputs/" + (String)this.s_input.getSelectedItem());
this.image = new ArrayList<>();
for (RGB p : this.orig) {
// kopiere die originalen Daten, damit die Liste später gemischt werden kann
this.image.add(p);
}
this.drawImage(this.img, this.drawImg);
} 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));
}
try {
BufferedImage i = Image.writeFile("./inputs/" + (String)this.s_input.getSelectedItem(), "", this.orig, this.quants);
this.drawImage(i, this.drawQImg);
} catch (Exception ex) {}
}
/**
* Epoche durchlaufen
*/
if (e.getSource() == this.b_epoc) {
Quant.doEpoch(this.image, this.quants);
try {
BufferedImage i = Image.writeFile("./inputs/" + (String)this.s_input.getSelectedItem(), "", this.orig, this.quants);
this.drawImage(i, this.drawQImg);
} catch (Exception ex) {}
}
/**
* Nicht bewegte Punkte versetzen
*/
if (e.getSource() == this.b_reset) {
Quant.resetQuants(this.quants);
try {
BufferedImage i = Image.writeFile("./inputs/" + (String)this.s_input.getSelectedItem(), "", this.orig, this.quants);
this.drawImage(i, this.drawQImg);
} catch (Exception ex) {}
}
/**
* 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.glcanvas.repaint();
}
private void drawImage(BufferedImage i, JPanel p) {
int w = i.getWidth();
int h = i.getHeight();
if (w > h) {
h = h * this.imgHeight / w;
w = this.imgHeight;
} else {
w = w * this.imgHeight / h;
h = this.imgHeight;
}
JLabel img = new JLabel(new ImageIcon(i.getScaledInstance(w,h,1)));
img.setPreferredSize(new Dimension(this.imgHeight, this.imgHeight));
p.removeAll();
p.add(img);
p.revalidate();
}
/**
* 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);
}
public static void main() throws Exception {
new OGL_Window();
}
}

View File

@ -4,16 +4,19 @@ PROJEKTZWECK: Liest ein Bild aus einer JPG-Datei ein und stellt die
Anschließend werden zufallsverteilte Punkte den Originaldaten Anschließend werden zufallsverteilte Punkte den Originaldaten
angenähert um abschließend das Bild auf diese Farben reduziert angenähert um abschließend das Bild auf diese Farben reduziert
wieder abzuspeichern. wieder abzuspeichern.
VERSION oder DATUM: 1.0.1 (26.10.2023) VERSION oder DATUM: 1.1 (27.10.2023)
WIE IST DAS PROJEKT ZU STARTEN: Instanz der Klasse Window anlegen WIE IST DAS PROJEKT ZU STARTEN: OGL_Window -> main()-Methode starten
AUTOR: Alexander Kimmig (a.kimmig@dhg-rw.de) AUTOR: Alexander Kimmig (a.kimmig@dhg-rw.de)
BENUTZERHINWEISE: Die ChartDirector_s.jar muss in den BlueJ-Einstellungen BENUTZERHINWEISE: Die ChartDirector_s.jar muss in den BlueJ-Einstellungen
als externe Benutzerbibliothek eingebunden werden. als externe Benutzerbibliothek eingebunden werden.
(Quelle: https://www.advsofteng.com/doc/cdjava.htm) (Quelle: https://www.advsofteng.com/doc/cdjava.htm)
CHANGELOG: CHANGELOG:
* Version 1.1 (27.10.2023)
* umgestellt auf OpenGL, manuelles Rendering
*
* Version 1.0.1 (26.10.2023) * Version 1.0.1 (26.10.2023)
* Möglichkeit, das Fenster in kleinerer Auflösung anzuzeigen * Möglichkeit, das Fenster in kleinerer Auflösung anzuzeigen
* Möglichkeit, die Punktwolke farbig anzuzeigen * Möglichkeit, die Punktwolke farbig anzuzeigen
-> Achtung: sehr langsam, nur mit kleinem Bild möglich! -> Achtung: sehr langsam, nur mit kleinem Bild möglich!
* Version 1.0 (20.10.2023) * Version 1.0 (20.10.2023)

View File

@ -1,3 +1,7 @@
/**
* BITTE NICHT MEHR NUTZEN -> stattdessen OGL_Window verwenden!
*/
import ChartDirector.*; import ChartDirector.*;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;

BIN
inputs/gras_gross.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 KiB

BIN
outputs/output4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB