Geometrische Transformationen

LatinFavourite

Bekanntes Mitglied
Guten Abend,

ich beschäftige mich gerade mit der geometrischen Transformation und versuche zu verstehen, wie diese genau abläuft. Hierzu möchte ich nicht, wie bisher die Klasse in Java verwenden, sondern eine eigene schreiben. Hierzu habe ich mir überlegt, eine Klasse Vektor und eine Klasse Matrix zu schreiben.

Ich kann jedoch noch nicht den Zusammenhang zwischen der Klasse und dem eigentlichen Ablauf herstellen. Ich benötige hierfür soweit ich es verstanden habe, eine Transformationsmatrix, die das Startbild in das entstsprechende Zielbild transformiert. Muss ich hierzu in der Klasse Matrix auch eine Methode für das Berechnen einer inversen Mateix zur Verfügung stellen?

Für jegliche Hinweise wäre ich dankbar.
Liebe Grüße.
 

LatinFavourite

Bekanntes Mitglied
Ich melde mich nochmals zurück. Mithilfe des PixelGrabbers möchte ich nun die einzelnen Pixel des Bildes ermitteln und diese dann verändern. Wie bringe ich die ermittelten Daten anschließend in eine entsprechende Matrixform. Ich weiß gerade absolut nicht weiter. :(
 

Bug Fisher

Bekanntes Mitglied
Du bringst da was durcheinander: Jedes einzelne Pixel, jedes Tupel, wird mittels der Matrixmultiplikation transformiert.
 
Zuletzt bearbeitet:

arilou

Bekanntes Mitglied
Beispiel: Dein Bild habe 640x480 Pixel, jeder hat eine (x;y;z)-Koordinate, z.B. x=0..639, y=0..479, z=0
Du möchtest z.B. "das Bild rechts 'nach hinten drehen', und 'links nach vorne drehen'", also um eine Achse
g := (319;0;0) + m * (0;1;0)
drehen. Dann musst du für jeden Pixel dessen ursprünglichen Koordinaten mit der entsprechenden Drehmatrix multiplizieren, um herauszufinden, wo auf dem Bildschirm er tatsächlich gezeichnet werden soll.

(Im Prinzip braucht man noch 'ne weitere Multiplikation mit einer Abbildungsmatrix, aber das lass' ich jetzt mal unter den Tisch fallen, wir verwenden zum Zeichnen einfach die resultierenden (x';y')-Koordinaten und ignorieren z'...)
 

LatinFavourite

Bekanntes Mitglied
Guten Abend,

vielen Dank arilou für deine Erklärung. Benötige ich dann überhaupt noch den Pixel Grabber? Lassen sich die Pixel nicht mit zwei verschachtelten For-Schleifen ansprechen, sodass ich dann die entsprechenden Mutiplikationen durchführen kann.

Vielen Dank für eure Hilfe. Ihr seid super. :)
 
Zuletzt bearbeitet:

LatinFavourite

Bekanntes Mitglied
So habe ich die Klasse Matrix aufgebaut, jedoch scheinen meine Überlegungen falsch zu sein.

Java:
public class Matrix {
	
	public final int[][] data;
	
	public Matrix(int[][] array){
		data = array;

	}
	
	public int getColumnDimension(){
		 return data.length;
	}
	
	public int getRowDimension(){
		return data[0].length;
	}
	
	public String toString(){
		String ausgabe = "";
		for(int i=0; i<getRowDimension(); ++i){
			for(int j=0; j<getColumnDimension(); ++j){
				ausgabe += data[i][j] + ",";
			}
			ausgabe+= "\n";
		}
		return ausgabe;
	}
	
	public static Matrix multi(Matrix field){
		
		int r = field.getRowDimension();
		int c = field.getColumnDimension();
		
		
		int[][] transform = {{1,0,2}, {0,1,2},{0,0,1}};
		Matrix trans = new Matrix(transform);
		
		int[][] result = null;
		Matrix ergebnis;
		
		for(int i=0; i<r; ++i){
			for(int j=0; j<c; ++j){
				for(int k=0; k<r; ++k){
					//result[i][j] += trans.data[i][k] * field.data[k][j];
		
			}
		}
	}
		ergebnis = new Matrix(result);
		
		return ergebnis;
}

Ich hatte es mir so ähnlich vorgestellt.

Java:
public void getPixel(){
		int width = image.getWidth();
		int height = image.getHeight();
		int[][] pixel = new int[width][height];
		
		for(int i=0; i<width; ++i){
			for(int j=0; j<height; ++j){
				pixel[i][j] = image.getRGB(i, j);
			}
		}
		
		this.pixel = pixel;
		setPixel();
		
		
	}
	
	public void setPixel(){
		
		int width = image.getWidth();
		int height = image.getHeight();
		
		Matrix pix = new Matrix(pixel);
		Matrix ergebnis = Matrix.multi(pix);
 

arilou

Bekanntes Mitglied
Du solltest dir erst mal klarmachen, was du eigentlich willst.
  • Willst du das Bild im 3D-Raum transformieren, dann geht es um die Pixel-Koordinaten. Das versteht man auch i.A. unter "Geometrische Transformation" (also "verschieben", "(3D-)drehen", "verzerren" usw.).
  • Oder willst du den Bildinhalt verändern, z.B. weichzeichnen, schärfen, jedes-rote-Pixel-blau-machen, oderoderoder? Das heißt dann "Bildbearbeitung".
Je nachdem sind deine Daten entweder
  • die Pixel-Koordinaten
  • oder die Pixelfarbe.
Und die Daten sind dann Input für eine Berechnungsfunktion.

Im Moment hantierst du mit geometrischen Transformationen, die dafür da sind, das Bild (z.B. im 3D-Raum) zu behandeln: verschieben, zerren, drehen u.ä. Als Daten verwendest du aber die Farbwerte der Pixel, und das passt nunmal nicht.
Wir können aber nicht raten, welche Zielsetzung du hast, und ob die Rechnungmethode oder die Daten nun "falsch" sind.
 
Zuletzt bearbeitet:

LatinFavourite

Bekanntes Mitglied
Entschuldigung für die mögliche Verwirrung. Nein, natürlich möchte ich die Pixelkooridinaten erhalten. Ich war gestern selbst ein wenig verwirrt. Nachdem ich das Bild eingelesen, sowie die Höhe und Breite des Bildes ermittelt habe, möchte ich die Pixel innerhalb der Schleifen ansprechen. Wenn ich beispielsweise das gesamte Bild nach rechts verschieben möchte, so muss ich doch jedes einzelne Pixel nach rechts verschieben.
 

Thallius

Top Contributor
Mal was zum generellen Arbeiten mit Matrizen.

Die Matrix gibt Dir an welches Pixel wo hin muss damit deine Transformation erfolgt. Also nehmen wir mal an du gehst dort mit (1,1,1) rein und läßt einen Verschiebe-3-Nach-Rechts-Algorytmus darüber laufen, dann würde danach in der Matrix stehen (4,1,1).
Du must dann also den Wert (Die Farben) des Pixels bei (1,1,1) nehmen und in das neue Bild bei (4,1,1) schreiben. Wichtig dabei ist, dass Du ein neues Bild anlegst, da Du sonst natürlich Pixel des alten Bildes überschreibst bevor Du sie liest und das Ergebnis wäre quatsch.

Die Matrix transformiert Dir also nur die Koordinaten, das neu Zeichnen musst du schon selber machen.

Gruß

Claus
 
Zuletzt bearbeitet:

LatinFavourite

Bekanntes Mitglied
Schon einmal vielen Dank für eure Geduld. :)

Ok, dann werde ich heute erst einmal versuchen, die neuen Kenntnisse umzusetzen. Danke.

Ich habe mich gestern mit dem PixelGrabber auseinandergestzt und nun so etwas aufgebaut

Java:
public class PixelChanger extends JComponent {
	
	final int W = 500;
	final int H = 300;
	
	//Altes Bild
	Image m_Img1;
	
	//neues Bild
	Image m_Img;
	
	int[] m_Img1Pix = new int[W*H];
	int[] m_Pix = new int[W*H];
	MemoryImageSource m_ImgSrc;
	
	public PixelChanger(Image m_Img1){
		
		m_Img1.getScaledInstance(W, H, Image.SCALE_SMOOTH);
		this.m_Img1 = m_Img1;
		
		PixelGrabber grab1 = new PixelGrabber(m_Img1, 0, 0, W, H, m_Img1Pix, 0, W);
		
		try {
			grab1.grabPixels();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		m_ImgSrc = new MemoryImageSource(W, H, m_Pix, 0, W);
		m_ImgSrc.setAnimated(true);
		m_Img = createImage(m_ImgSrc);
	}

}
 
Zuletzt bearbeitet:

LatinFavourite

Bekanntes Mitglied
Guten Abend,

ich melde mich nun nochmals zurück. Zwar läuft die Translation inzwischen, jedoch kommt nicht der gewünschte Effekt zustande. Es werden wohl nur manche Pixel verschoben. Ich weiß langsam nicht mehr weiter.
Vielleicht kann mir jemand von euch noch helfen.

Hier ein Auszug des Programmes:

Java:
public class Vektor {
	
	public int x;
	public int y;
	public int z;
	
	public Vektor(int x, int y){
		this.x = x;
		this.y = y;
		this.z = 1;
	}
	
	public Vektor(int x, int y, int z){
		this.x = x;
		this.y = y;
		this.z = z;
	}
	
	public String toString(){
		return String.format("Vektor: (%d, %d, %d)", x, y, z);
	}
	
	public static Vektor multiply(Matrix A, Vektor v) {
	    
		   //                   V | v1
		   //                     | v2
		   //                     | v3
		  //                     | 1
		   //     -----------------------
		   //  A  a11 a12 a13  | c1
		   //     a21 a22 a23  | c2
		   //     a31 a32 a33  | c3   
		 
		    
		     double t1 = v.x*A.a11+v.y*A.a12+v.z*A.a13;
		     double t2 = v.x*A.a21+v.y*A.a22+v.z*A.a23;
		     double t3 = v.x*A.a31+v.y*A.a32+v.z*A.a33;
		     
		     

		//System.out.println("x: " + t1 + " y: " + t2 + " z: " + t3);
		
		return new Vektor((int)t1, (int)t2, (int)t3);
	 }  

}

Java:
public class Matrix{
	
	public double a11, a12, a13;
	public double a21, a22, a23;
	public double a31, a32, a33;
	
	public Matrix(){
		 a11=0; a12=0; a13=0;
	     a21=0; a22=0; a23=0;
	     a31=0; a32=0; a33=0;
		
	}
	
	public void setMatrix(int[] array){
		 a11 = array[0];
		 a12 = array[1];
		 a13 = array[2];
	     
		 a21 = array[3];
		 a22 = array[4];
		 a23 = array[5];
	     
		 a31 = array[6]; 
		 a32 = array[7];
		 a33 = array[8];
		
	}
}

Java:
import java.awt.*;
import java.awt.image.*;
import java.io.*;

import javax.imageio.*;
import javax.swing.*;

class Picture extends JFrame{
	
	int W;
	int H;
	Image img = null;
	MemoryImageSource M_img;
	PixelGrabber gnu;
	int[] Pixel;
	
	int sx; int sy;
	
	Picture(){
		
		
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);

		this.setSize(1000,600);
		this.setLocationRelativeTo(null);
		
		getPic();
		
		this.setVisible(true);
		W = img.getWidth(null);
		H = img.getHeight(null);
		Pixel = new int[W*H];
		
		trans();
		
	}
	
	public void trans(){
		

		gnu = new PixelGrabber(img, 0, 0, W, H, Pixel, 0, W);
		try {
			gnu.grabPixels();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		
		
		translate();
		
	}

	
	
	
	public void translate(){
		int[] trans = {1, 0, 20, 0, 1, 20, 0, 0, 1};
		
		Matrix A = new Matrix();
		
		A.setMatrix(trans);
		Vektor result = null;
		
		int newPixel[] = new int[5000000];
		
		int x = 0;
		int y = 0;
		
		for(int i=0; i<Pixel.length; ++i){
			x = i % W;
			y = i / H;
			
			Vektor vec = new Vektor(x, y);
			result = Vektor.multiply(A, vec);
			
			System.out.println("x*y " + x*y);
			System.out.println("W*H: " + W*H);
			
			if(x*y < W*H){
			newPixel[result.x*result.y] = Pixel[x*y];
			}
				
	}
		
		produceImage(newPixel);
		
		
	}
	
	
	public void produceImage(int[] field){
		
		M_img = new MemoryImageSource(W,H,field,0,W);
		M_img.setAnimated(true);
		M_img.newPixels();
		img = createImage(M_img);
		repaint();
	}
	
	public void getPic(){
		
		BufferedImage image = null;
		
		JFileChooser Choose = new JFileChooser();
		
		Choose.setFileSelectionMode(JFileChooser.FILES_ONLY);
			
		int selection = Choose.showOpenDialog(null);
		
		if(selection==0){
							
				try {
					img = ImageIO.read(Choose.getSelectedFile());
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				repaint();
	
		}
		validate();
		
		add(new JComponent(){
			public void paintComponent(Graphics g){
				
				Dimension size = getSize();
				revalidate();

				g.drawImage(img, 0, 0, size.width,size.height, null);
				g.dispose();
		
			}
		});

		
	}
		
}

public class Transform {public static void main(String[] args) 
	{new Picture();}}
 

Thallius

Top Contributor
Du kannst nicht einfach immer auf x*y testen. Auch die Schleife über W*H und dann x und y mit % und / zu erstellen ist Mist.

Mach zwei Schleifen. Die äussere über y=0;y<Height;y++ und die innere über x=0;x<Width;x++.
Dann transformierst Du den entsprechenden Vector(x,y) und das Ergebnis must du dann auf x und y testen. Sprich:

if(ErgebnisX>=0 && ErgebnisX <=Width && ErgebnisY>=0 && ErgebnisY <=Height)
dann erstelle neues Pixel an y*width+x.
ansonsten ist das neue Pixel ausserhalb des sichtbaren Bereichs und kann ignoriert werden.


Gruß

Claus
 
Zuletzt bearbeitet:

LatinFavourite

Bekanntes Mitglied
Guten Abend,

Thallius, du bist fantastisch, einen herzlichen Dank. Es läuft jetzt ohne Probleme und zugleich noch deutlich schneller als vorher. Ich hätte nicht erwartet, hier solch eine super Unterstützung zu bekommen. Also nochmals vielen Dank. Aber aus welchem Grund läuft es nun so viel schneller, zudem sind nun diese merkwürdigen Pixellücken verschwunden. :)
 

Thallius

Top Contributor
Du must dich einfach mal in so einen dummen Computer hinein versetzen:)

Jede neue Rechnung kostet Zeit. Multiplikationen und Divisionen sind besonders teuer. Wenn du also in einer Schleife, die über millionen von Pixeln geht jede Menge verschienden Berechnungen machst, dann wird es langsam. Bei deiner Version hast du pro Schleifendurchlauf eine Division, eine Modulo-Division und 2 Multiplikationen gemacht. In meiner Schleife gibt es lediglich eine Multiplikation. Dadurch wird es einfach viel schneller.

Gruss

Claus

P.S. Der grüne Daumen ist übriges zum bedanken da ;)
 
Zuletzt bearbeitet:

LatinFavourite

Bekanntes Mitglied
Das ist verständlich. :) Das habe ich vorhin bereits bemerkt und an dich natürlich sofort ein Top vergeben.

Eine kleine Frage habe ich noch. Wenn ich nun bespielsweise eine Skalierung durchführen möchte. so entstehen ja natürlich Lücken. Dies soll ja durch Verwendung von inversen Matrizen verhindert werden. Dies soll bei der Skalierung dann einfach mihilfe des Kehrwertes möglich sein. Bei mir entsteht dann aber ein weißes Bild.
Lieben Gruß
 
Zuletzt bearbeitet:

arilou

Bekanntes Mitglied
Eine kleine Frage habe ich noch. Wenn ich nun bespielsweise eine Skalierung durchführen möchte. so entstehen ja natürlich Lücken. Dies soll ja durch Verwendung von inversen Matrizen verhindert werden. Dies soll bei der Skalierung dann einfach mihilfe des Kehrwertes möglich sein. Bei mir entsteht dann aber ein weißes Bild.
Keine Ahnung, was du mit "Lücken" meinst?
Skalierung
  • Verkleinern: Wenn du ein Bild aus z.B. 640x480 skalierst mit {50%;50%}, und nachher wieder nur ganzzahlige x;y-Koordinaten möglich sind, hat das Zielbild eben nur noch 320x240 Pixel.
  • Vergrößern: Wenn du es mit {200%;200%} vergrößerst und das "Zielbild" aus 1280x960 Pixeln bestehen soll, bleiben in x-Richtung immer ein schwarzer Punkt dazwischen, und in Y-Richtung immer eine schwarze Leerezeile dazwischen.
Allenfalls im 2. Fall entstehen "Lücken"; für deren "füllen" gibt's verschiedene Methoden in der Bildbearbeitung (welche du mit "Verwenden inverser Matrizen" meinst, weis ich nicht).
Auf jeden Fall kannst du bestenfalls interpolieren, da die Zwischen-Information nunmal nicht da ist.
 
Zuletzt bearbeitet:

LatinFavourite

Bekanntes Mitglied
Ich habe es inzwischen geschafft, es mithilfe der inversen Matrix umzusetzen. Der Ansatz ist, dass nicht von der Ursprungskoordinate gerechnet wird, sondern es muss von der Zielkoordinate aus erfragt werden, welche Ursprungskoordinate auf diese abgebildet wird. Die Zielkoordinate wird also durch die Transformationmatrix geteilt. Um dies umzusetzen, wird mit dem multiplikativen Inversen mutlipliziert. Bei der Skalierung ist es beispielsweise dann in der Matrix nicht der Wert sx und sy, sondern 1/sx und 1/sy.

Bei mehreren Operationen hintereinander, wird das Bild aber leider immer wieder in den Anfangszustand versetzt. Das muss ich noch beheben. Lieben Gruß
 
Zuletzt bearbeitet:

Thallius

Top Contributor
Du must halt unterscheiden ob du hoch- oder runter-skalierst. Je nachdem must du entweder vom Source oder vom Destination Pixel ausgehen.

Gruß

Claus
 

ceving

Aktives Mitglied

Ja die homogenen Koordinaten haben mich zu meiner Schulzeit auch vor ein paar Verständnisprobleme gestellt. Witziger Weise konnte mir damals meine Mathe-Lehrerin nicht weiterhelfen. Ende der 80er Jahre gab es in der c't eine Artikelserien, die über mehrere Monate ging und die Bildtransformationen erklärt hat. Dort wurden auch die homogenen Koordinaten dargestellt. Leider reicht das Online-Archiv nicht mehr so weit zurück. Aber evtl. gibt es die Jahrgänge noch in irgendwelchen Büchereien oder bei Heise direkt. Die Serie ist sehr lesenswert. Das war die Zeit als es die ersten Grafikkarten gab, die mehr als 16 Farben darstellen konnten. Mit Dithering konnte man richtige 3D-Bilder und Animationen berechnen. ;-) Die Implementation war damals aber in Turbo-Pascal.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M geometrische Suche Allgemeine Java-Themen 8

Ähnliche Java Themen

Neue Themen


Oben