Java Frage von Programmierneuling RGB+Maske

Dr.Kaya

Cadet 2nd Year
Registriert
Nov. 2010
Beiträge
19
Hallo,

und zwar sollen wir für die Uni ein Programm schreiben welches ein Bild einliest,
ein Negativ erstellt, ein Graustufenbild daraus macht ,anschließend über dieses
eine Maske laufen lässt und die rgb Werte danach "normiert" (also auf den Wertebereich [0,255] bringt).

Die Maske soll so ausschaun:
Code:
				 1  1  1
		maske =          0  0  0
				-1 -1 -1

int[][] maske = {{1,0,-1},{1,0,-1},{1,0,-1}};

Soweit so gut und bis zu der Maske hab ich auch keine Probleme, aber dort haperts gewaltig.
Ich bekomme einfach nicht das Bild raus, das raus kommen soll.

links das Negativ, in der Mitte nach der Maske, rechts das Orginal


Eigentlich sollte ein Bild raus kommen, das nur grau ist und auch nurnoch die konturen
sollten zu erkennen sein... schaut irgendwie nicht so aus =(

Die Methode bekommt das Bild als 2D-Array übergeben und gibt diese auch so aus.
Das Graustufenbild habe ich getestet und das schaut soweit in ordnung aus, also muss
es irgendwie an diesem Stück liegen
Code:
// Maske wird auf das Graustufenbild angewendet
 	public int[][]wendeMaskeAn (int[][] pixels,int[][] pixels2,int[][] matrix){
		
		for (int i = 1; i < hoehe-1; i++) {
			for (int j = 1; j < breite-1; j++) {
				int sum = 0;
				
				for (int m = 0; m < 3; m++) {
					for (int n = 0; n < 3; n++) {
						sum+= (pixels[i + m -1][j + n -1]&255)*matrix[m][n];
					}
				}
				pixels2[i][j] = (sum << 16) + (sum << 8) + sum;
			}
		}
		return pixels2;
	}
 	
 	// Normiert Werte auf [0;255]
 	public int[][]normieren (int[][] pixels){
 		
		for (int i = 0; i < hoehe; i++) {
			for (int j = 0; j < breite; j++) {
				
				int rgb = pixels[j][i];
				int r = (rgb >> 16) & 255;
				int g = (rgb >> 8) & 255;
				int b = rgb & 255;
					
				if(r>255){
					r=255;
				}
				if(r<0){
					r=0;
				}
				if(b>255){
					r=255;
				}
				if(b<0){
					r=0;
				}
				if(g>255){
					r=255;
				}
				if(g<0){
					r=0;
				}
			}
		}
		return pixels;
 	}

Beim normieren bekomme ich auch nachdem ich gestern Nacht noch ewig rumgetüftelt habe
und nicht mehr genau weiss was ich alles geändert habe diesen fehler:
Code:
gelöst

Ich hoffe ihr könnt mir helfen, ich hab keine Ahnung was meine Fehler sind.
Falls ich etwas zu ungenau erklärt habe sagt mir einfach bescheid.

Grüße Kaya
 
Zuletzt bearbeitet:
Eine "ArrayIndexOutOfBoundsException" tritt immer dann auf, wenn du versuchst, auf ein Element eines Arrays zuzugreifen, das es nicht gibt. In der Funktion normieren() kommt da nur eine Zeile als Fehlerquelle in Frage, nämlich:

Code:
int rgb = pixels[j][i];

Mein erster Verdacht: Bist du sicher, daß du nicht die Indizes vertauscht hast - also daß es nicht "pixels[j]" heißen sollte?

Edit: Noch was - du hast beim Normieren offenbar einen Copy-Paste-Fehler:

Code:
				if(b>255){
					r=255;
				}
				if(b<0){
					r=0;
				}
				if(g>255){
					r=255;
				}
				if(g<0){
					r=0;
				}

Du müßtest da jeweils die Variablen b bzw. g setzen, nicht r :)

Edit 2: Und nach dem Normieren solltest du die angepaßten Werte auch wieder in das Array pixels zurückschreiben. So, wie's jetzt da steht, rechnet die Funktion zwar, zurückgeliefert wird aber das unveränderte Eingabe-Array.
 
Zuletzt bearbeitet:
Ja, das wars. danke!
nun läuft das normieren wieder, aber das bild schaut immernoch überhaupt nicht so aus
wie es ausschaun soll...

da ne Idee ?

Grüße Kaya
 
Zuletzt bearbeitet:
Hast du meine Edits noch gesehen, oder warst du so flott, daß die schon zu spät kamen? ;)
 
Code:
 	// Normiert Werte auf [0;255]
 	public int[][]normieren (int[][] pixels){
 		
		for (int i = 1; i < hoehe; i++) {
			for (int j = 1; j < breite; j++) {
				
				int rgb = pixels[i][j];
				int r = (rgb >> 16) & 255;
				int g = (rgb >> 8) & 255;
				int b = rgb & 255;
					
				if(r>255){
					r=255;
				}
				if(r<0){
					r=0;
				}
				if(b>255){
					b=255;
				}
				if(b<0){
					b=0;
				}
				if(g>255){
					g=255;
				}
				if(g<0){
					g=0;
				}
				pixels[i][j] = (r << 16) + (g << 8) + b;
			}
		}
		return pixels;
 	}

ja da hast du recht,danke. Vllt sollte man so spät nicht mehr an einem Programm rumpfuschen :D
damit dürfte normieren dann wohl einigermaßen fehlerfrei sein. Danke!

auch noch ne idee für die Maske ?
 
Nicht wirklich, dafür kenne ich den Algorithmus, der da eingesetzt werden soll, zu wenig (eigentlich gar nicht ^^). Das Einzige, was mir beim Draufschauen so einfällt, ist, daß du die Maske vielleicht seitenverkehrt anwendest. Wenn das nicht der Fall ist, weiß ich auch nicht weiter.
 
Code:
// Berechnet die Grauwerte des Bildes
	public int[][]berechneGrauwertBild (int[][] pixels,int[][] pixels2){
		
		for (int j = 0; j < hoehe; j++) {
			for (int i = 0; i < breite; i++) {
			int rgb = pixels[j][i];
			int r = (rgb >> 16) & 255;
			int g = (rgb >> 8) & 255;
			int b = rgb & 255;
			int grau = (77 * r + 151 * g + 28 * b) / 256;
			pixels2[j][i] = grau;
			}
		}
		return pixels2;
	}
	
	// Wandelt die berechnetetn Grauwerte in RGB Werte um
	public int[][]wandleGrauwertnachRGBFormat (int[][] pixels){
				
		for (int j = 0; j < hoehe; j++) {
			for (int i = 0; i < breite; i++) {
				int grau = pixels[j][i];
				pixels[j][i] = (grau << 16) + (grau << 8) + grau;
			}
		}
		return pixels;

hier mal noch die Umwandlung des normalen Bildes in ien Grauwert Bild,
vllt hilft das ja irgendwie...
Ergänzung ()

*push*
vllt fällt ja doch noch wem was ein
 
Hallo,
meine Programmierzeit ist zwar schon etwas her, aber vielleicht hilfts:

- So wie deine Maske und die Verwendung in der Schleife in wendeMaskeAn aussieht, wird hier schon was falsches berechnet. Probier doch mal
int[][] maske = {{1,1,1},{0,0,0},{-1,-1,-1}};

- du schreibst dass die Maske auf das Graustufenbild angewendet wird. Dann ist die Verwendung von nur einem Subpixel-Wert in wendeMaskeAn auch ok (ansonsten müsste man das für r,g und b getrennt machen). Allerdings: den errechneten Wert (sum), also von einem Subpixel, wendest du jetzt auf r,g und b an, ohne VORHER zu normieren! Mach einfach in der Schleife nach der Berechnung von sum
Code:
if(sum>255){sum=255;}
if(sum<0){sum=0;}
pixels2[i][j] = (sum << 16) + (sum << 8) + sum;

und das war's schon mit dem Normieren (bei einem Graustufenbild)! Die Abfragen in der normieren-Funktion an sich sind sowieso überflüssig (und falsch), da du schon mit der Bit-Beschneidung (Wert & 255) alles relevante abschneidest (aus z.B. Wert 256 nur die letzten 8 bits wird 0 statt 255 normiert).

Hoffe geholfen zu haben
 
Danke für die Hilfe erstmal,
also wir sollen das normieren in einer extra methode machen,
ich würde das auch anders machen :D

soweit bin ich nun:
Code:
	// Maske wird auf das Graustufenbild angewendet
 	public int[][]wendeMaskeAn (int[][] pixels,int[][] pixels2,int[][] matrix){
		
		for (int j = 1; j < hoehe-1; j++) {
			for (int i = 1; i < breite-1; i++) {
				int sum = 0;
				
				for (int m = 0; m < 3; m++) {
					for (int n = 0; n < 3; n++) {
						sum+= (pixels[j + m -1][i + n -1]&255)*matrix[m][n];
					}
				}
				pixels2[j][i] = (sum << 16) + (sum << 8) + sum;
			}
		}
		return pixels2;
	}
 	
 	// Normiert Werte auf [0;255]
 	public int[][]normieren (int[][] pixels){
 		
 		// minimum/maximum wird gesucht
 		int abMax = pixels[0][0]&255;
		int abMin = pixels[0][0]&255;
		double maxMult = 0;
		double minMult = 0;
		
		for (int j = 1; j < hoehe-1; j++) {
			for (int i = 1; i < breite-1; i++) {
			
			int rgb = pixels[j][i]&255;
				
			if(abMax<rgb){
				abMax = rgb;
				}
			if(abMin>rgb){
				abMin = rgb;
				}
			}
		}
		
		abMin=Math.abs(abMin)+127;
		abMax=abMax-127;
		maxMult=127/abMax;
		minMult=127/abMin;
		// der Abstand zu 127 wird normiert
		for (int j = 1; j < hoehe-1; j++) {
			for (int i = 1; i < breite-1; i++) {
				
				double rgb = pixels[j][i]&255;
				int rgbInt = 0;
				
				if (rgb>127){
					rgb=rgb*maxMult;
					rgbInt=(int)Math.round(rgb);
				}
				if (rgb<127){
					if (rgb<0){
						rgb=rgb*-minMult;
						rgbInt=(int)Math.round(rgb);
					}else{
						rgb=rgb*minMult;
						rgbInt=(int)Math.round(rgb);
					}
				}
				pixels[j][i] = (rgbInt << 16) + (rgbInt << 8) + rgbInt;
			}
		}
		return pixels;
 	}

Wir sollen das normieren machen indem wir den maximalwert und den minimalwert herraus finden und dann das intervall [min;max] auf [0;255] normieren...

Das bild kommt immernoch falsch raus =(

 
Zuletzt bearbeitet:
Dr.Kaya schrieb:
Wir sollen das normieren machen indem wir den maximalwert und den minimalwert herraus finden und dann das intervall [min;max] auf [0;255] normieren...

Ahso, na dann ist es mit dem einfachen "Abschneiden" oben/unten wirklich nicht getan. Dann musst du also alle neu errechneten Werte in der Normierung verwenden (machst du auch). Allerdings: in der wendeMaskeAn ist immer noch
pixels2[j] = (sum << 16) + (sum << 8) + sum;
Damit machst du dir dein Ergebnis kaputt! Stell dir vor sum ist 256, was kommt dann bei deinem Pixel raus? Mach einfach
pixels2[j] = sum;
Ohne r,g,b zuzuweisen, das darfst du erst NACH der Normierung! Mit den Zwischenwerten des pixels2[][]-"Bild" machst du dann die Normierung. Und nimm den errechneten Wert so wie er ist, nicht nur die letzten 8 Bits (lass also die & 255) weg), sonst macht es keinen Sinn. Also
Code:
int abMax = pixels[0][0];
int abMin = pixels[0][0];
...
int rgb = pixels[j][i];
...
double rgb = pixels[j][i];
Der Witz soll ja sein dass ein max. Wert von z.B. 300 auf 255 normiert wird, indem ein Faktor errechnet wird (hier: maxMult), so dass 300*maxMult=255. Und wenn du den Wert vorher mit deiner Bit-Manipulation abschneidest, kommt halt Unsinn raus.
Sicherheitshalber kann man (da Runden immer so eine Sache ist) noch schreiben:
Code:
...
if (rgbInt>255) rgbInt=255;
if (rgbInt<0) rgbInt=0;
pixels[j][i] = (rgbInt << 16) + (rgbInt << 8) + rgbInt;

Was kommt jetzt für ein Bild raus?
 
auch die von dir vorgeschlagenen Änderungen haben leider nicht geholfen,
das Bild ist nun rein schwarz... ich glaub ich kapitulier einfach, wirds diesmal halt nicht volle Punktzahl ^^
 
Na wer wird denn so schnell aufgeben :D
Es kann eigentlich nur an der Normierung liegen. Grad noch mal angeschaut was du da machst... naja ;)
Code:
		abMin=Math.abs(abMin)+127;
		abMax=abMax-127;
		maxMult=127/abMax;
		minMult=127/abMin;
Vor allem das abs() kann hier gar nicht stimmen.

Mal auf dem Papier betrachtet:
- Du bekommst irgendwelche Werte aus einem gewissen Bereich, sagen wir mal -50 (abMin) bis 500 (abMax). Du willst aber Werte von 0 bis 255
- also: Minimum ist unter 0=>alle Werte +50, ergibt einen Bereich 0 bis 550 (wenn Minimum über 0 bzw. allgemein: alle Werte minus abMin, um auf 0 zu kommen)
- jetzt ist 550 zu groß, also alle Werte um Faktor verkleinern: 255/550 (~0,464)
- ergibt die hübsche Formel: SubPixel[neu]=(SubPixel[alt]-abmin)*255/(abMax-abMin)
Test: -50 - (-50) * 255/(500 - (-50)) = 0 * 0,464 = 0 passt
500 - (-50) * 255/(500 - (-50)) = 550 * 0,464 = 255 passt
die Mitte des ursprünglichen Bereichs: (500 + (-50))/2= 225
225- (-50) * 255/(500 - (-50)) = 275 * 0,464=127,5 das passt doch auch!

Zusammenfassend:
- abMin und abMax ermitteln (ok, sieht richtig aus)
- dann für jedes Subpixel (untere Schleife deiner Normierung):
Code:
rgbInt=(pixels[j][i]-abMin)*255/(abMax-abMin);
pixels[j][i] = (rgbInt << 16) + (rgbInt << 8) + rgbInt;

Rest (max/minMult, Unterscheidung größer/kleiner 127) kann alles weg! Jetzt muss es aber klappen! :cool_alt:
 
Zuletzt bearbeitet:
Zurück
Oben