Kreis und Linie mit zufälliger Anordung in einer Bitmap finden // diverse Filter
-
vielleicht wäre es besser für diese Frage ein neues Thema im im forum zu öffen. Ich stelle sie aber hier rein, da hier die ganzen Filter angesprochen sind.
Ich glaube ich habe den Sobel Filter nicht richtig verstanden.
Nachdem was ich bisher gelesen habe muss ich beim Sobel Filter jedes einzelne Pixel, und die 8 Pixel darum herum mit zwei Filtermatrizen multiplizieren und dann die Summe der in das Pixel in der Mitte schreiben. dies mache ich einmal für die X- und einmal für die Y-Richtung und lege dann die beiden Bilder übereinander.
Danach sollte ich ein Graustufenbild mit den erkannten Kanten erhalten (?????)Bei einer Bitmap ist es doch so, dass ich pro Pixel drei Farbwerte (rot, grün, blau) von 0-255 habe. Heißt das jetzt für mich, dass ich das gerade Beschriebene dreimal, d.h. für jede Farbe, machen muss?
Oder muss ich zurst ein Graustufenbild (wenn es so etwas gibt??) aus meiner Bitmap erzeugen? Ich habe zwar noch nie etwas mit Graustufenbilder gemacht, aber ich könnte mir vorstellen, dass es für so ein Bild nur eine Information pro Pixel gibt und alles viel einfacher wäre.
-
Mach ein Graustufen Bild daraus !
Ich weiss nicht ob der "MedianCut" Algo dafür geeignet ist oder du einfach eine "Graustufenkonvertierung" durchführen solltest.@Graustufen
Ganz einfach, vielleicht mal mit folgenden Werten testen.
z.B. wahrnehmungsorientiert:
Luminanz = 0.299·P.rot + 0.587·P.grün + 0.114·P.blau
Graustufenkonvertierung nach dem NTSC-Standard:
Luminanz = 0.176·P.rot + 0.81·P.grün + 0.011·P.blauOder selber googlen...
Danach noch einen Max oder Min Filter drüber jagen um den Noise wegzubekommen, und immer wieder schaun wie es aussieht.
Dann den Sobel drüber laufen lassen. Weiss grad nicht mehr ob man die 2 Filter hintereinander durchlaufen lassen muss oder ob man beide gleichzeitig drüber jagen kann ...
Anstatt der Max/Min Filter könntest du nochmal nach nem Median Filter suchen, der sollte auch zur NoiseReduktion funktionieren und net soo schwer sein.
PS: Wenn irgendwas schon durchgelaufen ist zeig mal die Ergebnisse, wäre cool !
-
Jester schrieb:
Nen Beispielcode zur Hough-Trafo hab ich leider grad nicht zur Hand. Aber die ist eigentlich recht einfach zu bauen. Geht übrigens ziemlich analog auch für Kreise.

Die Hough-Transformation für Kreise hat den Nachteil, dass sie nur Kreise mit einem bestimmten Radius findet. Wenn du nur knapp daneben liegst, bilden sich die Peaks nicht mehr besonders deutlich heraus; bei größerer Abweichung klappts gar nicht.
-
ChaosAngel schrieb:
PS: Wenn irgendwas schon durchgelaufen ist zeig mal die Ergebnisse, wäre cool !
-> ist versprochen!!!!
Bis es soweit ist, werde ich euch aber noch ein paar mal fragen müssen

das 1. Ergebnis kann ich schon liefern:
http://img85.imageshack.us/my.php?image=schwarzweiss5dc.jpg
ich habe die Graustufenkonvertierung nach dem NTSC-Standard benutzt:
Luminanz = 0.176·P.rot + 0.81·P.grün + 0.011·P.blauIch bin mit der Kamera näher and das Teil herangefahren. Außerdem istist das gezeigte Bild eine eine JPEG Datei und keine Bitmap. Ich bearbeite aber die Bitmap. da ist die Qualität noch viel besser.

-
Bashar schrieb:
Die Hough-Transformation für Kreise hat den Nachteil, dass sie nur Kreise mit einem bestimmten Radius findet. Wenn du nur knapp daneben liegst, bilden sich die Peaks nicht mehr besonders deutlich heraus; bei größerer Abweichung klappts gar nicht.
Ja, aber er sagte, der Radius sei bekannt. Außerdem kann man die Trafo natürlich auch mit variablem Radius durchführen. Ist halt etwas mehr Rechenaufwand. Aber um den Kreis zu finden würde ich eher ein matched-Filter verwenden.
-
ok, ....entweder ich finde keinen passenden Median Filter oder ich bin zu blöd ihn zu verstehen.
Ich zeige euch einmal was ich gemacht habe um mein Graustufenbild zu erzeugen. Vielleicht habe ich auch da schon etwas falsch verstanden, aber es funktioniert:
//---- Schwarz- / Weisbild daraus machen ------------------------------------ for (int i=0; i< 240/*bmih.biHeight*/; i++) { for (int j=0; j< 320/*bmih.biWidth*/; j++) { luminanz = picture[j][i].rgbBlue * 0.299 + picture[j][i].rgbRed * 0.587 + picture[j][i].rgbGreen * 0.114; picture[j][i].rgbBlue = luminanz; picture[j][i].rgbRed = luminanz; picture[j][i].rgbGreen = luminanz; picture[j][i].rgbReserved = 0; } }dies erzeugt mir ein wunderbares s/w-Bild. Vielleicht sollte ich noch erklären, dass in picture [j][i].rgbBlue/Red/Green die jeweiligen Farbwerte für jedes einzelne Pixel stehen. Da ich nun ein Graustufenbild habe sind nun alle drei Werte gleich.
Wer verrät mir nun, wie ich dazu einen Median Filter schreibe?
Oder was sollte ich anders machen?
Ich weiss gerade wirklich nicht weiter.
-
Hab leider grad garkeine Zeit, muss zur Uni, mach mal nur kurz Copy und Paste ausm \1:
Ersetzt den Wert eines Pixel mit dem Median der Werte der Pixel in
der n×n-Nachbarschaft.
-----Shit Formel lässt sich net kopieren ....
Hier mal die Ränge auf dem Bild was hier steht für 3x3
3 8 5
2 4 9
1 7 6So, muss nu los, vielleicht hilft wiki ...
ByeEdit:
Sorry, hab grad Gülle geschrieben !
Du nimmst imho einfach alle Pixel in deiner n x n Umgebung sortierst die Werte der Grösse nach und nimmst das mittlere Element. Lässt sich natürlich optimieren.Desweiteren solltest du für das Filtern vielleicht mit nem 8bit Bild rechnen und net mit 3 mal den selben Wert berechnen für das 24bit Bild.
-
ok,.........wie ich sehe bist du in der Uni angekommen. Bin übrigends schon seit 7.15 in meiner FH.
Wie der Opa schon gesagt hat:Zitat meines Großvaters schrieb:
"Du musst den Feierabend in der Früh suchen,...mein Sohn"
Aber nun zurück zu meinem Problem:
ChaosAngel schrieb:
Desweiteren solltest du für das Filtern vielleicht mit nem 8bit Bild rechnen und net mit 3 mal den selben Wert berechnen für das 24bit Bild.
Ich weiss nicht ob dass geht, wenn ich am Ende meines Progarmes wieder eine Bitmap haben muss. Oder gibt es eine 8 bit Bitmap?
ChaosAngel schrieb:
Du nimmst imho einfach alle Pixel in deiner n x n Umgebung sortierst die Werte der Grösse nach und nimmst das mittlere Element. Lässt sich natürlich optimieren.
Ich nehme an, dass ich diese Matrix um mein Pixel legen muss. Mein Pixel ersetze ich dann durch mein durch das mittlere Element.
-
Jetzt habe ich ein komplett weises Bild. Meiner Meinung habe ich aber genau das gemacht (einmal abgesehen von dem 8 bit Bitmap) was ChaosAngel geschrieben hat.
ich habe mir eine Matrize, 3x3, um das aktuell zu bearbeitende Pixel gelegt und diese dann mit einem Bubblesort sortiert. Den mittleren Wert habe ich dann in das Pixel geschrieben.
for (int y=0; y< 240/*bmih.biHeight*/; y++) { for (int x=0; x< 320/*bmih.biWidth*/; x++) { filterfeldX[x][y] = picture[x][y].rgbRed; // hier habe ich nur Rot genommen, da blau und grün = rot sind } } for (int y=0; y< 240/*bmih.biHeight*/; y++) { for (int x=0; x< 320/*bmih.biWidth*/; x++) { f = 0; for (int my=y-1; my<y+1; my++) { for (int mx=x-1; mx<x+1; mx++) { feld[f]= filterfeldX[mx][my]; f++; } } int temp; for (int i=0; i<8; i++) { for (int j=0; j < 8-i; j++) { if ( feld[j] > feld[j+1]) { temp = feld[j]; feld[j] = feld[j+1]; feld[j+1] = temp; } } } mittelWert = feld[5]; picture[x][y].rgbBlue = mittelWert; picture[x][y].rgbRed = mittelWert; picture[x][y].rgbGreen = mittelWert; } }das Resultat ist ein komplett weises Bild.
Ich hoffe mit dem mittleren Wert wurde nicht der durchschnitt aller Pixel gemeint.
Interessatnt ist, dass wenn ich schreibe mittelWert = feld[0]; dann bekomme ich ein Graustufenbild. Habe ich so einen Min- Filter geschrieben?
Ab dem feld[4] ist das Bild dann komplett weis.
Der Bubbelsort müsste aber richtig funktionieren.
-
1. Ich glaube du greifst auf bereiche zu die nicht zum Bild gehören...
weil du wenn du z.B. in der ersten Spalte bist auf das -1 element zugreifst ... du solltest also schreiben:for (int y=1; y< 240-1/*bmih.biHeight*/; y++) { for (int x=1; x< 320-1/*bmih.biWidth*/; x++) {Das -i macht doch irgendwie alles kaputt ? Wenn das stärkste element ganz vorne ist, sollte es so doch nie bis ganz nach hinten kommen ?
for (int i=0; i<8; i++) { for (int j=0; j < 8-i; j++)Naja ich weiß nicht genau was ein min oder max filter macht, aber könnte es nicht besser sein das ganze in eine "neue" bitmap zu schreiben?
Kann mich bei den Sachen auch irren .. bin nicht so der pro

-
du musst das auf jeden fall in eine neue bitmap schreiben...
stell dir vor:
du machst in der linken oberen 'Ecke mal so ein medianfilter drauf, dann hat die linke obere Ecke ja die Farbe des Medians der n*n Pixel drum herum (bzw. nur n/2 weil es ja die ecke ist). Wenn du jetzt einen Pixel weiter nach rechts gehst und wieder median machst, dann wird ja schon die neue Farbe der linken oberen Ecke verwendet und der median des ixels daneben stimmt gar nicht mehr. Deshalb: aus der einen bm lesen, und in die neue bm schreiben, zum schluss die alte durch die neue erstezten oder auch behalten, wie dus brauchst
-
Also, ich denke
1. Das du in eine neue Bitmap schreiben musst.
2. Ich meine mit BitMap (auch mein 8Bit PerPixel bezog sich darauf) nicht ein *.bmp Bild sondern einfach ein 2D Array. In deinem Beispiel heisst es glaube ich filterFeld, das ist genau das was ich meinte !
Am ende aller FilterOperationen schreibst du halt alles wieder in dein 24bit BMP zurück indem alle Farben halt den gleichen Wert haben.So, zum Filtern legst du dir erstmal 2 filterFelder an.
In einem stehen deine Input Daten und im zweiten sollen deine OutPut Daten dann stehen.
Dein Feld sieht schon ganz ok aus. Ich nehme an, hoffe das du C++ schreibst.
Dann nimm gefälligst einen std::vector statt dem "Feld", und benutze die sort Methode, n eigenes Bubblesort möcht ich hier bitte nicht sehen, dafür gibt es std libs.
So, dann füllst du dein Feld wie bisher mit den 9 Werten und sortierst es. Der Median soll tatsächlich NICHT das arithmetische Mittel sein sondern wirklich der Pixel in der Mitte. Hast du also richtig erkannt.
Diesen Wert schreibst du nun aber nicht sofort zurück ins OriginalBild, sondern in dein 2tes filterFeld.Wenn du damit fertig bist kannst du von mir aus aus dem OutPut FilterFeld wieder deine bmp machen.
Soweit ich das richtig erkannt habe hast du das alles auch so gemacht !(ohne Umweg über 2tes filterFeld, aber bei mehreren FIlterOperationen ist es vielleicht besser so ...)
Das einzige Woran es also liegen kann wäre dein Bubblesort. Also entweder nimmst du dir schnell ne std methode dafür oder du musst das Ding debuggen und richtig machen. Wird letztendlich aber ungünstig sein da Bubble ja auch noch verdammt langsam ist.PPS: Du greifst in deiner Schleife wo du dein Feld füllst über die Array Grenzen hinaus. Hier musst du also manuell abfangen das y mindestens 1 und höchstens 239 oder so.. ist.
Es gibt mehrere Methoden Randpixel zu behandeln. Am besten wird hier sein einfach den Rand zu nehmen, also wenn y=-1 ist dann die Stelle 0 zu nehmen...Na denn man Tau ...
PPPPS:
mittelWert = feld[0]; dann bekomme ich ein Graustufenbild. Habe ich so einen Min- Filter geschrieben?
Wenn ich mich net völlig irre ergibt feld[0] den min Filter und feld[8] den max Filter... Das Graustufenbild hast du aber schon vorher !!!
Du sagtest das alle Werte (rot, grün, blau) gleich seien in deinem Bitmap (du hast also schon ein Graustufenbild erzeugt).Der Min/Max/Median Filter dient nur zur Noise Reduktions, also das hässliche kleine schwarze und Weisse Punkte auf dem Bild verschwinden die da auch garnicht hingehören (so kannst du halt einfach ein bisschen die Auflösung der Kamera kompensieren)
-
Mortal2006 schrieb:
Das -i macht doch irgendwie alles kaputt ? Wenn das stärkste element ganz vorne ist, sollte es so doch nie bis ganz nach hinten kommen ?
for (int i=0; i<8; i++) { for (int j=0; j < 8-i; j++)-> nein das ist der Bubbelsort, und der funktioniert auch.
ich habe meinen Code ändern müssen, damit ich kein weises Bild mehr bekomme.
Die Lösung war ganz einfach. Ich habe mir nicht alle Pixel der Median Matrix angeschaut, sonder nur ein Teil. Somit hat auch mein Bubbelsort nicht funktioniert.
... for (int my=y-1; my<y+2; my++) //hier steht nicht mehr y+1 bzw. x+1. { for (int mx=x-1; mx<x+2; mx++) { ...mit dieser kleinen Änderung geht es.
@ChaosAngel
Ich habe nicht gewusst, dass es eine Methode zum sortieren gibt, mir war nur der qsort bekannt.
Da ich den Bubbelsort schneller geschrieben habe, als mich durch zahlreiche Internetseiten und die MSDN Library durchzuarbeiten, nur um so etwas zu finden, habe ich es so gemacht. Ich werde mir aber auf jedenfall die std::vector anschauen.So dann bin ich jetzt einmal gespannt, was für Probleme der Sobel Filter noch mit sich bringt

DANKE an alle die mir bis dahin geholfen haben!!!! Das war wirklich SPITZE, ohne euch hätte ich es vielleicht oder nicht in der Zeit nicht geschafft.

-
Bilder !!!
@Sobel
Input -> VertFilter -> Output
Output -> HorizFilter -> FinalOutAls Input natürlich das Bild nehmen was du durch die anderen Filter bereits erhalten hast.
@std::sort
Ja, genau wegen diesem Fehler in deinem sort lgo sollte halt der Erste Blick immer erst in die Bibliotheken sein. Man spart SEHR viel Zeit damit die stl zu benutzen anstatt nen sort algo, ne verkettete Liste, nen dynamisches Array, ne Map, nen Stack etc... zu implementieren. Ausserdem weiss man das diese algo's und strukturen Fehlerfrei sind(naja, meißtens jedenfalls, einige MS implementierungen der STL sind echt buggy, aber das sollte bei deinem Gebrauch nicht auffallen und tut hier auch nichts zur Sache).
-
Also der Sobel Filter hat mich nicht wirklich überzeugt.
hier ist das Ergebnis:
http://img164.imageshack.us/my.php?image=mitsobel9yg.jpg
Ich habe den Median Filter hinter den Sobel geschrieben. Das hat noch zu den besten Ergebnissen geführt.
Wen es interessiert wie es geht:
for (int y=0; y<240/*bmih.biHeight*/; y++) { for (int x=0; x<320/*bmih.biWidth*/; x++) { input[x][y] = output[x][y]; } } for (int y=0; y<240/*bmih.biHeight*/; y++) { for (int x=0; x<320/*bmih.biWidth*/; x++) { output[x][y] = abs( (-1 * input[x-1][y+1]) + (1 * input[x+1][y+1]) + (-2 * input[x-1][y] ) + (2 * input[x+1][y] ) + (-1 * input[x-1][y-1]) + (1 * input[x+1][y-1])); } } // Kanten in Y-Richtung for (int y=0; y< 240/*bmih.biHeight*/; y++) { for (int x=0; x< 320/*bmih.biWidth*/; x++) { input[x][y] = output[x][y]; } } for (int y=0; y< 240/*bmih.biHeight*/; y++) { for (int x=0; x< 320/*bmih.biWidth*/; x++) { output[x][y] = abs( (-1 * input[x-1][y+1]) + (1 * input[x-1][y-1]) +(-2 * input[x] [y+1]) + (2 * input[x] [y-1]) +(-1 * input[x+1][y+1]) + (1 * input[x+1][y-1])); } }
-
Ehm, das was Du da gemacht hast ist kein wirklicher Sobel. Also die einzelnen Teile schon, aber du sollst nicht beide zusammen auf das Bild anwenden.
Erst Sobel-X, dann wieder auf das Originalbild(!) den Sobel-Y. Das gesambild erhältst Du nun, indem Du an jeder Stelle sqrt(Sobel-X^2 + Sobel-Y^2) hinschreibst.
-
Ob ich das Ergebnis für meine Anwendung gebrauchen kann muss ich noch herausfinden. Aber hier ist das Resultat des nun hoffentlich richtigen Sobel Filters.
http://img161.imageshack.us/my.php?image=mitsobel1lb.jpg
die Linien um das Teil herum sind meine Finger.
und hier das vielleicht interessantere,.... der Code:
//---- Sobel Filter --------------------------------------------------------- // -1 0 1 -1 -2 -1 // -2 0 2 x Filtermatrix 0 0 0 y Filtermatrix // -1 0 1 1 2 1 for (int y=0; y<240/*bmih.biHeight*/; y++) { for (int x=0; x<320/*bmih.biWidth*/; x++) { sobelX[x][y] = output[x][y]; sobelY[x][y] = output[x][y]; } } // Kanten in X-Richtung for (int y=0; y<240/*bmih.biHeight*/; y++) { for (int x=0; x<320/*bmih.biWidth*/; x++) { sobelX[x][y] = abs( (-1 * input[x-1][y+1]) + (1 * input[x+1][y+1]) + (-2 * input[x-1][y] ) + (2 * input[x+1][y] ) + (-1 * input[x-1][y-1]) + (1 * input[x+1][y-1])); } } // Kanten in Y-Richtung for (int y=0; y< 240/*bmih.biHeight*/; y++) { for (int x=0; x< 320/*bmih.biWidth*/; x++) { sobelY[x][y] = abs( (-1 * input[x-1][y+1]) + (1 * input[x-1][y-1]) +(-2 * input[x] [y+1]) + (2 * input[x] [y-1]) +(-1 * input[x+1][y+1]) + (1 * input[x+1][y-1])); } } for (int y=0; y< 240/*bmih.biHeight*/; y++) { for (int x=0; x< 320/*bmih.biWidth*/; x++) { output[x][y] = sqrt(sobelX[x][y] * sobelX[x][y] + sobelY[x][y] * sobelY[x][y]); } } //------------------------------------------------------------------------------
-
Na das sieht doch schon eher nach Sobel aus. Sorry, das mit dem falschen Sobel war mein Fehler, hatte es falsch beschrieben.
for (int y=0; y<240/*bmih.biHeight*/; y++) { for (int x=0; x<320/*bmih.biWidth*/; x++) { sobelX[x][y] = output[x][y]; sobelY[x][y] = output[x][y]; } }Dafür könntest auch mal n memcpy nehmen, und das ganze hin und her midde Speicher kannste gut über Pointer vereinfachen und ne Menge Performance rausholen, aber das tut ja erstmal noch nichts zur Sache.
Ob du das Bild gebrauchen kannst, nunja, ich muss gestehen das ich momentan nichts mehr auf dem Bild erkenne. Ich denke du musst einfach ein bisschen mit den Filtern experimentieren welches Anti-Noise Filter am besten dein Bild bereinigt und beim Sobeln vielleicht den Kernel vergrössern, oder sogar den Filter mehrmals drüber jagen um die Kanten noch stärker hervor zu heben ...
Du musst am Ende eine gute Mischung zwischen den Filtern finden so das die unwichtigen Linien herausfliegen und nur deine Kugel übrig bleibt. Ich denke darauf ein paar mal den Sobel angewendet sollte dir dann schon richtig scharfe linien geben die du dann testen kannst.
-
Also ich würde das mit dem Sobel lassen
... das bringt zwar nachher bei der Linienerkennung nen bischen geschwindigkeit aber sonst wäre mir für deine Aufgabe kein weiterer vorteil bekannt (was natürlich nichts heißt) ...Ich würde das Bild Binarisieren, oder wie man das nennt, und dann die linien mit so einer Art LaPlace Filter erkennen. Nur das der Laplace Filter eventl. werte außerhalb von 0-255 liefert ... deswegen würde ich sowas machen...
abs(input[x-1][y]-input[x][y])Das ganze dann so wie beim Sobelfilter aus X und Y Richtung und man sollte die linien schön erkennen können

-
ChaosAngel schrieb:
Dafür könntest auch mal n memcpy nehmen, und das ganze hin und her midde Speicher kannste gut über Pointer vereinfachen und ne Menge Performance rausholen, aber das tut ja erstmal noch nichts zur Sache.
Ne ganze Menge Performance dürfte sich auch rausholen lassen, indem man den Sobel-Filter zerlegt:
(-1 0 1) (1) (-2 0 2) = (2) ** (1 0 -1) (-1 0 1) (1)** bezeichnet die Faltung. Also erst Kanten suchen und dann Mit Binomial-TP glätten. Der für waagrechte Kanten geht analog. Müßte man mal probieren, ob's was bringt. Bei größeren Matrizen ist der Vorteil größer.
Weißt Du eigentlich schon, wie's danach weitergehen soll? Außer "Linien suchen"? Falls nein, schau doch nochmal nach, ob Du nicht eine der bereits vorgeschlagenen Ideen ausprobieren möchtest.