[C++] Angew. Bildverarbeitung - Sobel/Prewitt-Filter

Bl@ckD0G

Lieutenant
Registriert
Nov. 2002
Beiträge
730
Hi!

Ich habe versucht mal selbst einen Sobel - Filter zu programmieren (auch einige andere) ich habe aber bei allen das selbe Problem.
Nämlich sehen meine gefilterten Bilder nicht so aus, wie sie z.b. in AdOculos aussehn.
Ich dachte ich hätte meinen Fehler gefunden, und zwar:

Code:
void prewitt_filter(UCHAR **img) 
{
	// Maske : -1 -1 -1 0 0 0 1 1 1 
	char sw;
	
	cout << "(H) Horizontal\n\n(-1-1-1)\n( 0 0 0) \n( 1 1 1)\n\n" << endl;
	cout << "(V) Vertikal\n\n(-1 0 1)\n(-1 0 1)\n(-1 0 1)\n\n" << endl;
	cin >> sw;
	
	switch(sw)
	{
	case 'h': case 'H':{
		for(int i =1 ; i<HEIGHT-1 ; ++i)
			for(int j=1 ; j<WIDTH-1 ; ++j){
				[B]img[i][j] = ((img[i-1][j-1]+img[i-1][j]+img[i-1][j+1])
					-
					(img[i+1][j-1]+img[i+1][j]+	img[i+1][j+1]))/6;[/B]
			}
			break;	  }}}

Bei dem Fettgedruckten: da ersetzt ich den aktuellen Pixel ja schon mit dem neuen wert, d.h. beim nächsten durchlauf hat der neue_aktuelle Pixel ja als nachbarn schon einen pixel mit anderen werten, als den Ursprungswert.

Dann dachte ich mir, mach ich es halt so:
Code:
for(int i=1 ; i<HEIGHT-1 ; ++i)
		for(int j=1 ; j<WIDTH-1 ; ++j){
				pixel = ((img[i-1][j-1]+2*img[i-1][j]+img[i-1][j+1])
					-
					(img[i+1][j-1]+2*img[i+1][j]+img[i+1][j+1])) / 8;
				vec_sobel.push_back(pixel);
			}

und nachdem ich durch das ganze bild gelaufen bin, ersetze ich die alten werte durch die neuen:

Code:
for(int k = 0; k < vec_sobel.size(); ++k)
		for(int i =1 ; i<HEIGHT-1 ; ++i)
			for(int j=1 ; j<WIDTH-1 ; ++j)
				img[i][j] = vec_sobel[k];

Es gibt keine Fehler oder so, aber das Bild sieht unverändert aus. Es schaut aus, wie das original.

Könnt ihr mir sagen, was ich hier übersehn habe?
Bin für jede Hilfe Dankbar
Gruß
Doggy

EDIT: Beim Laplace - Filter wird das Bild komplett schwarz....
 
Zuletzt bearbeitet: ([code]-Tags verwenden!)
Den Fehler den du gefunden hattest, war auf jeden Fall schonmal ein fetter Fehler. :)

Beim zurückschreiben der Infos aus dem sobel-Vektor machst du aber einen Fehler. In der äußeren Schleife durchläufst du alle Pixel aus dem sobel-Vektor. In den inneren beiden weist du jedem Pixel des Original-Bildes den einen Wert vec_sobel[k] zu.
Demnach müsstest du eigentlich am ende ein Einfarbiges Bild haben in der Farbe des letzten Pixels "vec_sobel[vec_sobel.size()-1]"
Da das aber nicht der Fall ist, würde ich auf einen Fehler bei den Gültigkeitsbereichen der Datenstruktur img[][] tippen.

Ein Tip: Verwende für den temporären Bildspeicher die gleiche Datenstruktur wie beim Originalbild, das macht die Sache einfacher. ;)
Also ein img[][] und ein sobel_temp[][]
 
Zuletzt bearbeitet:
Hm stimmt....
d.h. ich müsste die äußere eigentlich nach innen bauen oder seh ich das falsch?

Und mit der einen farbe hast du recht, bei meinem laplace-filter passiert das nämlich -> alles schwarz.
 
Nein, du musst einfach die zweidimensionalen Koordinaten von i und j auf die eindimensionale von vec_sobel abbilden. Lass die äußere weg, und schreib:

Code:
		for(int i =1 ; i<HEIGHT-1 ; ++i)
			for(int j=1 ; j<WIDTH-1 ; ++j)
				img[i][j] = vec_sobel[(i*WIDTH)+j];

Dann müsste es mit den Indizes passen. :)

//Edit
Aber wie ich oben noch dazugeschrieben habe würde ich gleiche Datenstrukturen verwenden.

Ach ja, wenn du Kantendetektion mit dem Sobel machen willst, musst du mit beiden Filterkernen nacheinander rechnen, und dann die beiden Ergebnisbilder addieren.
Dazu kommt dann noch eine Schwellwertberechnung, so dass die Kanten sauber dargestellt werden.
 
Zuletzt bearbeitet:
das wäre ne Möglichkeit, wollte zwar speicher sparen, aber kann ja erstmal testen, ob es so funktioniert.
Danke werd es mal versuchen!

Langsam wird es echt unübersichtlich... hätte es doch ERST in eine classe schreiben sollen, und dann alles ausprogrammieren :(
 
*lol*
Auf jeden Fall, gut planung zahlt sich am Ende immer aus. :D

PS: Hab oben noch einen Hinweis dabei editiert! ;)
 
jaja ich weiß bin ein unstruckturierter kerl :)

Bin ja kein informatiker *g*
Und das der Sobel so aufwendig ist hätte ich nicht gedacht. Hab gedacht, ich muss nur mein 3x3 fenster über das Bild schieben und die "darunterliegenden" pixel mit der gewichtung des filters multiplizieren.
Wie mache ich eine Schwellwertberechnung? Und was meinst du mit Filterkern?

Code:
for(int i =1 ; i<HEIGHT-1 ; ++i)
			for(int j=1 ; j<WIDTH-1 ; ++j)
				img[i][j] = vec_sobel[(i*WIDTH-1)+j];
Das geht so allerdings nicht, da stürzt mir das proggy ab, und sagt mir mehr oder weniger, dass ich auf nicht allocierten speicher zugreife.
 
Zuletzt bearbeitet:
Das hier sind deine Filterkerne:
Code:
	cout << "(H) Horizontal\n\n(-1-1-1)\n( 0 0 0) \n( 1 1 1)\n\n" << endl;
	cout << "(V) Vertikal\n\n(-1 0 1)\n(-1 0 1)\n(-1 0 1)\n\n" << endl;
Die unterscheiden sich bei der Kantendetektion in horizontaler und vertikaler Richtung.
Hab gedacht, ich muss nur mein 3x3 fenster über das Bild schieben und die "darunterliegenden" pixel mit der gewichtung des filters multiplizieren.
Ja, genau das machst du doch! :D
Zu der Schwellwert-Berechnung, implementier mal den Filter ordentlich, und poste dann mal das Ergebnisbild, dann kann ich dir das besser erklären. :)

PS: In welchem Studiengang, wenn nicht Informatik, lernt man denn wie man lineare Filter implementiert?
 
Optotechnik und Bildverarbeitung

http://www.fbmn.fh-darmstadt.de/
Einzigartig in Deutschland zumindest in dieser Form. Bin allerdings erst im 2. Semester. Und Bildverarbeitung hab ich erst seit diesem.
Werde mal versuchen den Filter zu implementieren. Kann sich nur um Stunden handeln :)
 
Mach am besten eine Methode die den Filterkern als Parameter bekommt, denn dann bist du universeller, und kannst auch andere Filter laufen lassen, wie einen Gauß-Filter, der dir das Bild unscharf macht. :)

//Edit
Der Studiengang hört sich ziemlich spannend an!
Hätte ich glaub ich auch eher gemacht anstelle Medieninformatik, aber wurde damals noch nicht angeboten, oder ich habs einfach nicht gewusst.
 
Zuletzt bearbeitet:
Gauss hab ich auch schon. Und die Idee mit der Universellen Methode hatte ich auch schon, aber da hat es an der umsetzungsfähigkeit gemangelt :( Ich tu mir beim programmieren immer etwas schwer...

EDIT: Ist er auch wirklich.
Medieninformatik wollte ich auch machen, hab ich allerdings nur als aufbau studiengänge gefunden, hab aber auch nicht wirklich ernsthaft danach gesucht :)
 
Zuletzt bearbeitet:
So hier ist das bild von meinem Prewitt-Filter Horiz. und vertik. zusammen.

Maske:
Code:
|(-1 0 1)|   |(-1 -2 -1 )|
|(-2 0 2)|+|(0  0  0 )|
|(-1 0 1)|   |(1 +2   1)|

Ich hoffe die betragsstriche sind als solche zu erkennen. Hab es wie du gesagt hast mit einem tmpimg gemacht.
Code:
TmpImg[i][j] = abs(abs(abs_value)+abs(abs_value2));

Ergebnis Prewitt:
prewitt.jpg


Wenn alles soweit stimmt dann...
Zu der Schwellwert-Berechnung, implementier mal den Filter ordentlich, und poste dann mal das Ergebnisbild, dann kann ich dir das besser erklären

Bitte :)
 
Das sieht doch sehr gut aus. Zu der Schwellwertberechnung muss man noch sagen dass das eben drauf ankommt was man damit vor hat. D hast ja hier offensichtlich en Filter auf ein SW-Bild angewendet.

Sinn des Sobel-Filter ist es ja die Kanten aus dem Bild zu filtern. Diese sind ja nun hier schon sehr gut hervorgehoben, aber wenn man das bild weiter verarbeiten will, so kann man jetzt noch eine Schwellwert-Berechnung drauf loslassen, die aus diesem Bild alle Pixel herausfiltert, die einen bestimmten Wert überschreiten. Damit kann man dann erreichen dass wirklich nur noch harte Kanten enthalten sind.

Danach würde man sowas hier erhalten wie im Anhang. zeichnest einfach jeweils einen Pixel dann Schwarz, wenn der ursprüngliche Wert einen bestimmten Grenzwert überschreitet, ansonsten weiß. :)
 

Anhänge

  • konturen.jpg
    konturen.jpg
    98,2 KB · Aufrufe: 463
Zuletzt bearbeitet:
axo, ich glaube was du unter Schwellwertberechnung verstehst nenen wir Spreizen bzw. binarisieren.
Hier mal ein Bild, das Linear gespreitzt wurde nachdem der Prewitt angewandt wurde (Prewitt/Sober ist ja eigentlich fast wurscht) und noch eins, das binarisiert wurde.
prew_lin_spr.jpg
prew_binar.gif


links gespreitzt, rechts binarisiert. Ist aber gut zu erkennen.
Ein weiterer ganz guter Kantenfilter ist der Roberts-cross, den werd ich auch eben noch schnell implementieren.

EDIT:

Jetzt seh ich erst den anhang. Wenn ich das Binarisierte Bild negiere bekomme ich auch ungefähr sowas, was du erhältst. (Dies kann mein proggy übrigends auch :p )
 
Zuletzt bearbeitet:
Ja, binarisieren ist nur ein anderes Wort für die Schwellwert-Berechnung. :)
Aber was ist denn mit spreizen gemeint? Ist das ein Hochpassfilter oder auch Rechteckfilter?
 
es gibt Lineares Spreizen und Quadratisches spreizen, vielleicht noch mehr, aber die kenne ich bisher nur. Spreizen ist eigentlich kein wirklicher Filter. Rechteckfilter sind sowas wie Medianfilter, also morphographische Filter. Dies trift jedoch nicht auf das Spreizen zu. Es ist zum Kontrastverbessern gedacht. Allerdings gehen dabei Details verloren.

Beim Spreizen gibt es 2 Grenzen.
für alle gw <= untere grenze --> gw = 0
für alle gw >= obere grenze --> gw = 255

die grauwerte dazwischen werde mit :

(grauw. - unteregr. ) / (obere - unteregr.) *255

das macht eine schön lineare fkt.
Code:
      ___255
     / 
____/       0

Wenn du willst, kann ich dir mal das Proggy zuschicken, da kannst du ne menge mit machen / ausprobieren. Naja solange man sich auf Grauwertbilder im Binärformat beschränkt. Bildformate IV, 128, 256 etc und raw, aber auch nicht alle und das Bild muss quadratisch sein...
Also noch sehr eingeschränkt in seinen möglichkeiten :)

EDIT:
Hochpassfilter sind Filter durch Fourier-Transformation. Da kann man die niedrigen/hohen Ortsfrequenzen unterdrücken bzw. sichtbar machen. Beispiel für so nen Filter hab ich leider nicht. Die sind wohl auch recht komplex :)
 
Zuletzt bearbeitet:
Zurück
Oben