# Bestimmen ob Bereich im Bild eher Schwarz oder Weiss ist?



## sirbender (1. Okt 2010)

Hi,

ich habe ein schwarz-weiss BufferedImage. Wie kann ich bestimmen ob der Bereich x,y,w,h (100,150,10,10) eher weiss oder schwarz ist? Pixel zaehlen? Wie komme ich an die Farben ran?

Geht das auch mit farbigen Bildern? Kann ich irgendwie entscheiden ob das Quadrat im Bild eher 'hell' oder 'dunkel' ist?

Danke,
sb


----------



## Tomate_Salat (1. Okt 2010)

Ich habe soetwas ähnliches wie du willst mal geschrieben.

Wenn ichs richtig im kopf habe, brauchst du nur das Graphics(2D) objekt aus dem Bild und über das [c]getRaster()[/c] kannst du die Bildinformationen in ein Array laden (oder dir den RGB-Wert zurückgeben lassen. Ich habe ein array mit der größe 4 genommen: rot, grün, blau, alpha). 

Die Helligkeit ist ganz einfach. Du nimmst den höchsten Wert von den ersten 3 (alpha interessiert nicht) und daraus bekommst du die helligkeit. (Ein Graustufenbild kannst du dann einfach erstellen, indem du den rot,grün und blau wert auf den höchsten Wert setzt, der vorkommt. Beispiel: r:0 g:120: b:150. Dann ist der Blauanteil am höchsten und du setzt dann alles auf 150 (alpha habe ich immer auf 255 gesetzt))

Daraus ein komplettes schwarz ODER weis bild zu machen ist eigentl. auch nicht schwer. Du nimmst dein Graustufenbild und setzt eine Grenze: alles unter 100 z.B. ist 0 alles darüber ist 255. Schon hast du ein schwarz/weis bild.

Damit habe ich überraschend gute Ergebnisse erziehlt.

MFG

Tomate_Salat


----------



## sirbender (2. Okt 2010)

Danke! Kann ich mit der gleichen Vorgehensweise ueber getRaster() Blurring erreichen?


----------



## Tomate_Salat (2. Okt 2010)

Simple antwort: ja. mit getRaster() bekommst du die Bildinformationen und kannst diese verändern (die Pixel halt). Wie du jz blurring damit realisierst kann ich dir nicht sagen, weil ich es noch nie versucht habe (vllt gibts dafür aber auch bereits eine Methode? Ka). 

Filter Effekte diese Seite habe ich mal überflogen, vllt hilft diese. Sind zwar glaub c++-Beispiele aber vllhilft es trotzdem

MFG

Tomate_Salat


----------



## Ralf Pongratz (4. Okt 2010)

Tomate_Salat hat gesagt.:


> Die Helligkeit ist ganz einfach. Du nimmst den höchsten Wert von den ersten 3 (alpha interessiert nicht) und daraus bekommst du die helligkeit. (Ein Graustufenbild kannst du dann einfach erstellen, indem du den rot,grün und blau wert auf den höchsten Wert setzt, der vorkommt. Beispiel: r:0 g:120: b:150. Dann ist der Blauanteil am höchsten und du setzt dann alles auf 150 (alpha habe ich immer auf 255 gesetzt))



Das ist so leider nicht richtig. Ein Pixel (255,0,0) wäre somit als Grauwert heller als (254,254,254), was aber nicht der Fall ist. Die korrekte Umrechnung findet sich hier: YUV-Farbmodell ? Wikipedia.
Der Grauwert Y = 0,299 * R + 0,587 * G + 0,114 * B. Der Grund für diese unterschiedlichen Faktoren liegt darin, dass unser Auge für die Farben unterschiedlich empfindlich ist.

Ralf


----------



## Ralf Pongratz (4. Okt 2010)

sirbender hat gesagt.:


> Danke! Kann ich mit der gleichen Vorgehensweise ueber getRaster() Blurring erreichen?



Ich habe in einer meiner Anwendungen folgendermaßen ein Blurring realisiert (eine gute Anleitung findet sich in dem Buch "Filthy Rich Clients"):

[Java]
int filterwidth = ... // Je größer der Wert, desto stärker der Filter.
BufferedImage image = ... // Dein Bild, das Du filtern willst.
// Warum der Filter in zwei einzelne Filter unterteilt wird, lies bitte in dem angegebenen Buch nach. Die Wirkung ist die gleiche wie in einem Durchgang, es geht aber schneller.
image = getGaussianBlurFilter(filterwidth, true).filter(image, null);
image = getGaussianBlurFilter(filterwidth, false).filter(image, null);

public static ConvolveOp getGaussianBlurFilter(int radius, boolean horizontal) {
		if (radius < 1) {
			throw new IllegalArgumentException("Radius must be >= 1");
		}

		int size = radius * 2 + 1;
		float[] data = new float[size];
		float sigma = radius / 3.0f;
		float twoSigmaSquare = 2.0f * sigma * sigma;
		float sigmaRoot = (float)
		Math.sqrt(twoSigmaSquare * Math.PI);
		float total = 0.0f;
		for (int i = -radius; i <= radius; i++) {
			float distance = i * i;
			int index = i + radius;
			data[index] = (float) Math.exp(-distance / twoSigmaSquare) / sigmaRoot;
			total += data[index];
		}
		for (int i = 0; i < data.length; i++) {
			data_ /= total;
		}
		Kernel kernel = null;
		if (horizontal) {
			kernel = new Kernel(size, 1, data);
		} else {
			kernel = new Kernel(1, size, data);
		}
		return new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
	}
[/Java]

Ralf_


----------



## Landei (4. Okt 2010)

Ralf Pongratz hat gesagt.:


> Das ist so leider nicht richtig. Ein Pixel (255,0,0) wäre somit als Grauwert heller als (254,254,254), was aber nicht der Fall ist. Die korrekte Umrechnung findet sich hier: YUV-Farbmodell ? Wikipedia.
> Der Grauwert Y = 0,299 * R + 0,587 * G + 0,114 * B. Der Grund für diese unterschiedlichen Faktoren liegt darin, dass unser Auge für die Farben unterschiedlich empfindlich ist.
> 
> Ralf



Für das Umrechnen kann man Color.RGBtoHSB nehmen.


----------



## Tomate_Salat (4. Okt 2010)

Ralf Pongratz hat gesagt.:


> Das ist so leider nicht richtig. Ein Pixel (255,0,0) wäre somit als Grauwert heller als (254,254,254), was aber nicht der Fall ist. Die korrekte Umrechnung findet sich hier: YUV-Farbmodell ? Wikipedia.
> Der Grauwert Y = 0,299 * R + 0,587 * G + 0,114 * B. Der Grund für diese unterschiedlichen Faktoren liegt darin, dass unser Auge für die Farben unterschiedlich empfindlich ist.
> 
> Ralf



Für meine Zwecke hat das bis jz super gereicht^^. Werde es mir das aber mal genauer anschauen. Dein Beispiel kann ich nicht nachvollziehen, vllt hab ich aber gerade auch eine falsche Vorstellung von 255,0,0 und 254,254,254. 

Wobei ich nicht glaube, dass das bei meinem vorhaben große auswirkungen hat. Da ich in meinem Projekt das ganze zur einfachen Konturerkennung nutze und diese eh im (eigen entwickelten) Editor nachgearbeitet werden müssen

MFG

Tomate_Salat


----------



## Ralf Pongratz (4. Okt 2010)

Tomate_Salat hat gesagt.:


> Für meine Zwecke hat das bis jz super gereicht^^. Werde es mir das aber mal genauer anschauen. Dein Beispiel kann ich nicht nachvollziehen, vllt hab ich aber gerade auch eine falsche Vorstellung von 255,0,0 und 254,254,254.
> 
> Wobei ich nicht glaube, dass das bei meinem vorhaben große auswirkungen hat. Da ich in meinem Projekt das ganze zur einfachen Konturerkennung nutze und diese eh im (eigen entwickelten) Editor nachgearbeitet werden müssen



Ein Pixel mit der Farbe (255,0,0) ist ein sattes Rot, (254,254,254) hingegen ist fast weiß (ohne Vergleichsmöglichkeit würde man den Unterschied zu weiß nicht merken). Optisch würde jeder sagen, dass der rote Pixel dunkler ist als der fast weiße. Aber nach Deiner Methode würde der erste als heller detektiert werden.

Zum Tragen kommt der Unterschied in der Umrechnung dann, wenn die Pixel des Bildes sehr große Variationen in den Farbkanälen haben, d. h. bei einem Teil der Pixel ist der eine, bei einem anderen Teil ein anderer Farbkanal dominant.

Ralf


----------



## sirbender (4. Okt 2010)

Konturerkennung? Du meinst in Vektoren umwandeln also tracen? Ist das Programm erhaeltlich?



Tomate_Salat hat gesagt.:


> Für meine Zwecke hat das bis jz super gereicht^^. Werde es mir das aber mal genauer anschauen. Dein Beispiel kann ich nicht nachvollziehen, vllt hab ich aber gerade auch eine falsche Vorstellung von 255,0,0 und 254,254,254.
> 
> Wobei ich nicht glaube, dass das bei meinem vorhaben große auswirkungen hat. Da ich in meinem Projekt das ganze zur einfachen Konturerkennung nutze und diese eh im (eigen entwickelten) Editor nachgearbeitet werden müssen
> 
> ...


----------



## sirbender (4. Okt 2010)

Ich wuerde gerne folgenden Code fuer mein Blur verwenden:

001 float ninth = 1.0f / 9.0f;
002 float[] blurKernel = {
003     ninth, ninth, ninth,
004     ninth, ninth, ninth,
005     ninth, ninth, ninth
006 };
007 BufferedImageOp blur = new ConvolveOp(new Kernel(3, 3, blurKernel));

Das Problem ist nur...wie verstaerke ich den Blur-Effekt? Muss ich das Blur mehrmals anwenden bzw. den Kernel vergroessern?


----------



## Ralf Pongratz (5. Okt 2010)

sirbender hat gesagt.:


> Das Problem ist nur...wie verstaerke ich den Blur-Effekt? Muss ich das Blur mehrmals anwenden bzw. den Kernel vergroessern?



Du vergrößerst den Kernel. Dabei aber beachten, dass die Summe der Einträge 1 ergibt. 
Es gibt allerdings den Nachteil, dass der Rand, der nicht mit bearbeitet wird, größer wird. Also eventuell das zu filternde Bild in ein größeres Bild einbetten, filtern und dann wieder ausschneiden.
Du kannst natürlich auch den Blur mehrfach anwenden. Schau einfach, was für Dich das Beste Ergebnis gibt.

Dein Kernel ist übrigens separierbar, d. h. Du kannst ihn in zwei 1x3-Kernel aufteilen. Siehe dazu mein Beispiel. Dies spart Rechenoperationen und ist sinnvoll, wenn die Filterung schnell erfolgen soll.

Ralf


----------



## Tomate_Salat (5. Okt 2010)

sirbender hat gesagt.:


> Konturerkennung? Du meinst in Vektoren umwandeln also tracen? Ist das Programm erhaeltlich?



Nein. In ein Polygon um genau zu sein und der Prototyp (Editor) ist noch in Entwicklung. Er wird als Modeleditor später verfügbar sein. Ich will irgendwann mal mit Spieleentwicklung anfangen und dafür wird der Editor dann später gebraucht werden. Dieser soll auch für andere Spiele die ich mal vorhabe zu entwickeln (zuminest habe ichs mal vor ) genutzt werden. 

MFG

Tomate_Salat


----------



## Landei (5. Okt 2010)

sirbender hat gesagt.:


> Ich wuerde gerne folgenden Code fuer mein Blur verwenden:
> 
> 001 float ninth = 1.0f / 9.0f;
> 002 float[] blurKernel = {
> ...



Den Kernel vergrößern. Für ein gutes Ergebnis mit einem größeren Kernel solltest du allerdings in der Mitte größere und am Rand kleinere Werte verwenden (Summe sollte 1 sein, sonst verändert sich die durchschnittliche Helligkeit). Üblicherweise verwendet man dafür ein Gauß-Verteilung. Schau mal hier:
Java Programming [Archive] - filters mean 5x5 and gaussian 5x5


----------

