Pixel in Binärbildern zu Konturen zusammenfassen

Status
Nicht offen für weitere Antworten.

schimmelpilz

Mitglied
Hallo,

dies ist mein erster Post in diesem Forum, habe mir schon viele Threads vorher durchgelesen, aber leider keine brauchbare Antwort für mein Problem gefunden. Nun hoffe ich hier auf die Hilfe eines anderen ???:L

Erstmal zur Ausgangssituation:
Ich habe ein Bild mit nur Vordergrund- und Hintergrundpixeln. Die weißen Pixel sind der Hintergrund, die schwarzen der Vordergrund. Die Vordergrundpixel bilden stark ausgedünnte Konturen, die nur ein Pixel breit sind. Ich möchte nun diese Konturstücke finden und in Listen abspeichern, um diese anschließend zu analysieren. Dazu verfolge ich folgenden Ansatz:
1. Ich durchlaufe das Bild mit zwei for-Schleifen und suche nach einem Vordergrundpixel.
2. Ist dies gefunden hangel ich mich von diesem Pixel über seine Nachbarpixel solange vorwärts, bis ich eins gefunden habe, das nur einen Nachbarn hat. Also den Anfang eines Konturstücks darstellt.
3. Nun möchte ich von dort die komplette Kontur ablaufen und jedes Vordergrundpixel in einer Liste ablegen, bis ich das andere Ende der Kontur erreicht habe. Dann speicher ich dieses Konturstück wiederum in einer Liste, die alle Konturstücken des Bildes verwaltet.

Der bisherige Quell-Code dazu:
Die Klasse ByteProcessor ist eine Klasse aus dem Package von ImageJ, muss aber hier nicht weiterbeachtet werden.
Code:
public class ContourFinder 
{
	static final int BLACK = 0;
	int width;
	int height;
	int tempU;
	int tempV;
	//Liste gefüllt mit Konturen
	Contour contour;
	List<Contour> contourList = new ArrayList<Contour>();
	//stellt den ByteProcessor zur Verfügung
	ByteProcessor byteProcessor;
	
	public ContourFinder(ByteProcessor byteProcessor)
	{
		this.byteProcessor = byteProcessor;
	}
	
	//*****************************************************************************
	//Methode zum Finden und Abspeichern einer Kontur
	public void findContour()
	{
		width = byteProcessor.getWidth();
		height = byteProcessor.getHeight();
		for (int u = 0; u <= width; u++)
		{
			for (int v = 0; v <= height; v++)
			{
				if (byteProcessor.getPixel(u, v) == BLACK) 
				{
					//sucht dann Anfang einer Kontur
					if (countBlackNeighbours(u, v) == 1)
					{
						followContour(u, v);
					}
				}
			}	
		}
	}
	
	//*****************************************************************************
	//überprüft die Nachbarpixel nach dem Wert 'BLACK' und gibt deren Anzahl zurück
	private int countBlackNeighbours(int u, int v) 
	{
		int numberOfNeighbours = 0;
		for (int i = u-1; i <= u+1; i++) 
		{
			for (int j = v-1; j <= v+1; j++) 
			{
				//der Pixel muss Schwarz sein, darf nicht er selbst sein, d.h. nicht 
				//in der Mitte liegen und muss innerhalb der Bildbereichs liegen
				if (byteProcessor.getPixel(i, j) == BLACK 
						&& !(i == u && j == v)
						&& !(i < 0 || i > width-1 || j < 0 || j > height-1)) 
				{	
					numberOfNeighbours++;
				}
			}
		}
		return numberOfNeighbours;
	}
	
	//*****************************************************************************
	//folgt einer Kontur solange bis ihr Ende erreicht ist und speichert dabei jeden
	//Pixel der Kontur in einer Liste ab
	private void followContour(int u, int v) 
	{
		contour = new Contour();
		do
		{
			for (int i = u-1; i <= u+1; i++) 
			{
				for (int j = v-1; j <= v+1; j++) 
				{
					//der Pixel muss Schwarz sein, darf nicht besucht sein
					//und muss innerhalb der Bildbereichs liegen
					if (byteProcessor.getPixel(i, j) == BLACK 
							//hier müsste noch geprüft werden ob der Pixel schon in einer Liste abgelegt ist
							&& !(i == u && j == v)
							&& !(i < 0 || i > width || j < 0 || j > height))
					{
						pixel = new Pixel(i, j);
						pixel.visited = true;
						pixel.numberOfNeighbours = countBlackNeighbours(i, j);
						contour.pixelList.add(pixel);
						//Zwischenspeicherung der Koordinaten des letzten VG-Pixels
						tempU = i;
						tempV = j;
					}
				}
			}
			u = tempU;
			v = tempV;
			
			//byteProcessor.putPixel(pixel.posX, pixel.posY, 200);
		} 
		while(countBlackNeighbours(u, v) > 1);

		//speichert die komplette Pixelliste in der Konturliste
		contourList.add(contour);
	}
Code:
//zur Verwaltung der Konturen aus Bildpunkten
class Contour
{
	List<Pixel> pixelList;
	int length;
	
	Contour() 
	{
		pixelList = new ArrayList<Pixel>();
		length = pixelList.size();
	}
Code:
class Pixel 
{
	int posX;
	int posY;
	int numberOfNeighbours;
	boolean visited;
	
	Pixel() {
		//parameterloser Konstrukter
	}
	
	Pixel(int posX, int posY)
	{
		this.posX = posX;
		this.posY = posY;
	}
}

Vielleicht kann mir hierbei jemandweiterhelfen, da ich momentan den Wald vor lauter Bäumen nicht sehe ???:L
 

schimmelpilz

Mitglied
Ups sorry, wie peinlich... :oops:

Ja ich möchte der Kontur folgen, hänge aber in Zeile 66-100. Ich laufe dort irgendwie im Kreis.
Eigentlich möchte ich nur dafür sorgen, das ein schon geprüftes schwarzes Pixel nicht nochmal geprüft wird.
D.h. kein Pixel doppelt in der Liste vorkommt und die schwarzen Pixel in der Liste in der Reihenfolge vorliegen, in der sie auch im Bild hintereinander liegen.
Vielleicht hat jemand einen Lösungsvorschlag, wie ich das besser machen kann...
 

Illuvatar

Top Contributor
D.h. das eigentliche Problem ist Zeile 78?

Ich würde da zu Contour noch eine Methode hinzufügen
public boolean isInList (int x, int y)
(oder so ähnlich). Da gehst du die ArrayList durch, und schaust, ob es das Pixel schon gibt.
Am Besten fängst du am hinteren Ende der ArrayList an, das sollte schneller sein. Und wenn wir schon bei Performance sind: Ich würde dir zu einer LinkedList raten - das sollte in deinem Fall sowieso schon schneller als ArrayList sein, und wenn du Java6 nimmst, auch noch geschickter, weil LinkedList Deque implementiert, da kannst du dann auch einen descendingIterator() kriegen.
 

schimmelpilz

Mitglied
@Illuvatar

Danke erstmal für Deinen guten Ansatz.
Der Code sieht nun wie folgt aus...

Auszug aus der Klasse ContourFinder:

Code:
	//*****************************************************************************
	//folgt einer Kontur solange bis ihr Ende erreicht ist und speichert dabei jeden
	//Pixel der Kontur in einer Liste ab
	private void followContour(int u, int v) 
	{
		contour = new Contour();
		do
		{
			Pixel pixel = new Pixel(u, v);
			for (int i = u-1; i <= u+1; i++) 
			{
				for (int j = v-1; j <= v+1; j++) 
				{
					//der Pixel muss Schwarz sein, darf nicht besucht sein
					//und muss innerhalb der Bildbereichs liegen
					if (byteProcessor.getPixel(i, j) == 0 
							&& !(contour.listContains(pixel.posX, pixel.posY))
							&& !(i == u && j == v)
							&& !(i < 0 || i > width || j < 0 || j > height))
					{
						pixel.visited = true;
						pixel.numberOfNeighbours = countBlackNeighbours(i, j);
						contour.pixelList.add(pixel);
						//
						tempU = i;
						tempV = j;
					}
				}
			}
			u = tempU;
			v = tempV;
		} 
		while(countBlackNeighbours(u, v) > 1);
		//speichert die komplette Pixelliste in der Konturliste
		contourList.add(contour);
	}

Die Klasse Contour

Code:
//zur Verwaltung der Konturen aus Bildpunkten
class Contour
{
	List<Pixel> pixelList;
	int length;
	
	Contour() 
	{
		pixelList = new ArrayList<Pixel>();
		length = pixelList.size();
	}

	//*****************************************************************************
	//Methode zum Suchen in der Liste
	public boolean listContains(int u, int v)
	{
		for (int i = 0; i < pixelList.size(); i++)
		{
			int m = pixelList.get(i).posX;
			int n = pixelList.get(i).posY;
			if (u == m && v == n) return true;
		}
		return false;
	}

Leider scheint er irgendwie in einer Endlosschleife zu hängen, jedenfalls kriege ich kein compiliertes Ergebnis :(
Im Debug-Modus habe ich die ersten Schritte verfolgt, dort scheint alles korrekt zu laufen, wenn ich aber auf Play drücke, dann hängt er wieder...
Weiß nicht wo das Problem liegt?
 

Illuvatar

Top Contributor
Auf Anhieb seh ich nix - aber wie meinst du, du "kriegst kein kompiliertes Ergebnis"?
Wenn du das nicht kompilieren kannst, kannst du es ja auch nicht testen ;)
 

schimmelpilz

Mitglied
Damit meine ich, das Programm läuft nicht bis zum Ende. Er hängt an einer Stelle und scheint dort in einer endlos-Schleife zu stecken. Die ersten ca. 300 Pixel arbeitet er brav ab, d.h. im Debug-Modus, wenn ich Schritt für Schritt durchgehe dann werden die Nachbarpixel korrekt erkannt und in der Liste gespeichert. Leider kommt er dann nicht weiter, ich weiß auch nicht warum :bahnhof:

Hab schon die Initialgröße der Liste erhöht und die do-while-schleife gegen eine for-Schleife mit fester Länge getauscht um zu sehen wo er hängt. Er bleibt einfach mitten in der Kontur nach ca. 300 Pixel stehen. Dort ist auch ein korrekter Nachbarpixel... Ich bin echt verzweifelt...
 

Illuvatar

Top Contributor
Naja, das anschauen ist auch etwas schwierig, wenn man es nicht ausprobieren kann...

Mir fällt nix außer Debuggen, du müsstest eben irgendwie schaffen, mal genau die Stelle zu debuggen. Vllt gibts nen Befehl für den Debugger, dass er erst beim 300. Schleifendurchlauf anhält, den kenn ich aber nicht, sonst kannst du ja in der Schleife ne Variable runterzählen - dann nen if (variable == 0){ ; //breakpoint}
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Moorhuhn Pixel-Aimbot mit Robot Library Java Basics - Anfänger-Themen 12
I Greenscreen, funktioniert nicht zu 100%... nicht alle Pixel werden geändert Java Basics - Anfänger-Themen 1
J Größe eines Strings in Pixel Java Basics - Anfänger-Themen 18
A BufferedImage Pixel Java Basics - Anfänger-Themen 7
S suche nach varible POSITION ... fuer das pixel-maennchen Java Basics - Anfänger-Themen 4
M Einzelne Pixel in einem Bild auslesen und bearbeiten Java Basics - Anfänger-Themen 1
T Java gleichfarbige Pixel vergleichen Java Basics - Anfänger-Themen 5
I Zähler, der erst wieder zählt nachdem Pixel wieder andere Farbe hat Java Basics - Anfänger-Themen 2
B Äußere Pixel auslesen Java Basics - Anfänger-Themen 3
P pixel formel versetztes Schachbrettmuster Java Basics - Anfänger-Themen 2
llabusch Fenster um x Pixel verschieben Java Basics - Anfänger-Themen 4
S Speicherbedarf Pixel vs. Polygon? Java Basics - Anfänger-Themen 7
D Kleinere Positionsangabe als einzelne Pixel bei Image? Java Basics - Anfänger-Themen 28
V Pixel auslesen? Java Basics - Anfänger-Themen 3
L Wieviel Speicher braucht ein Pixel? Java Basics - Anfänger-Themen 14
R Kurze Linien alle x-Pixel Java Basics - Anfänger-Themen 2
O Maus / Pixel Position bei mir und bei anderen. Java Basics - Anfänger-Themen 8
S Pixel auf Screen setzen Java Basics - Anfänger-Themen 4
M einzelne Pixel setzen/auslesen Java Basics - Anfänger-Themen 2
G Pixel-Abstand im JPanel Java Basics - Anfänger-Themen 11
G Bild einlesen und je Pixel die RGB-Werte ermitteln Java Basics - Anfänger-Themen 3
lin Farbwerte von Pixel Java Basics - Anfänger-Themen 4
T Bilder - Array - Pixel Java Basics - Anfänger-Themen 3

Ähnliche Java Themen

Neue Themen


Oben