Archiv verlassen und diese Seite im Standarddesign anzeigen : Java: Objekterkennung für Anfänger
Hallo
Ich hab mich auch mal wieder ans Proggen gesetzt und mich in Bilderkennung geübt. Ziel ist es, aus einem Bild einer Webcam, die einen grünen Tisch mit einer roten Kugel drauf filmt die Position der roten Kugel zu errechnen. Ich habs in Java gemacht. Momentan arbeite ich mit einem idealisierten Testbild (rein grüner Grund und rein rote Kugel). Ich hab nen Array of Arrays (2-Dimensionales Feld), das 320x240 groß ist, also so groß wie das Bild. Jede Stelle ist entweder 1 oder 0, 1 für "Der Pixel ist rot" und 0 für "Der Pixel ist nicht rot". Nun probiere ich schon die ganze Zeit, möglichst effizient (soll ja mal realtime werden) die Mitte der roten Fläche (in diesem Falle ein Kreis) herauszufinden, also die beiden Array-"Koordinaten", die diese repräsentieren. Kurz gesagt: Ich kriegs ned auf die Reihe. Gibts da vielleicht nen gängiges Verfahren oder hat jemand schonmal sowas gemacht? Ich bin am verzweifeln.
Ach, und wenn jemand zufällig noch weiss, wie man nen Webcambild in Java in nen Image oder BufferedImage einließt, nur her damit. Ich hatte noch keine Zeit, danach zu googlen. Wie gesagt, ich erwarte nich, dass ihr für mich sucht, aber kann ja sein, dass jemand sowas "auf Halde" hat! :)
edit:
Ich lese gerade: eine Byte-Variable belegt logischerweise 1 Byte. Eine Boolean allerdings auch. :-s Die Boolean bräuchte doch nur 1 Bit.... Ich will halt ne möglichst kleine für das Array nehmen, damit es schnell geht...
ok, schade dass es kein feedback gab. aber hier mal trotzdem meine ergebnisse:
ich habs hinbekommen, dass ich das webcam-bild in mein prog bekomme und das auch mit einer guten geschwindigkeit.
hier mal ein bild:
http://img337.imageshack.us/img337/4956/geschafft6hb.jpg
ich hab nen laserpunkt auf den teppich geworfen. sieht man links. und rechts ist der laserpunkt aus dem bild herausgerechnet.
weitere ziele sind jetzt:
- den punkt auf den pixel in seiner mitte zu reduzieren
- linien erkennen, auf 1 pixel breite reduzieren und als vektor speichern
- störende pixel herausrechnen (ich denke das werd ich mit faltung machen. muss mich da noch informieren)
und in zukunft:
- aus 2 bildern, die versetzt aufgenommen sind (stereoskopisch) eine tiefenmap erstellen (anhand einer laserlinie, die auf ein objekt projeziert wird)
- urlaub
- den punkt auf den pixel in seiner mitte zu reduzieren
Wie wärs wenn du einfach den Durschnittswert der Koordinaten aller Punkte berechnest, die zu deinem Laser-"Fleck" gehören? Also den Mittelwert der x-Koordinaten und den Mittelwert der y-Koordinaten. Das ist dann ziemlich gut der Mittelpunkt deiner Fläche.
- linien erkennen, auf 1 pixel breite reduzieren und als vektor speichern
Google: Sobel-Operator, Skelettierung, Hough-Transformation
- aus 2 bildern, die versetzt aufgenommen sind (stereoskopisch) eine tiefenmap erstellen (anhand einer laserlinie, die auf ein objekt projeziert wird)
Schick. \:D/
auf den sobel-operator bin ich auch schon gestoßen. ich hab da nen >100 seiten-script gefunden, in dem alles sehr interessant erklärt ist...
Dann poste doch mal den Link, das könnte auch für andere interessant sein.
uf.... da muss ich mal in der history wühlen....
http://www.uni-koblenz.de/~agas/lehre/ws0304/sem_rek/Seminar_Rekonstruktion_WS0304.pdf
ich hab mir das mit der hough-transformation mal angesehen. sieht interessant aus, verstanden hab ichs leider auf die schnelle noch nicht so ganz. hättest du da evtl nen programmierbeispiel für? ich hab bisher nix gefunden
ojmjakon
23.09.2005, 13:49
Hallo Goblin
Ich glaube auf die Schnelle ist das auch nicht zu verstehen.
Was hast Du Dir denn genau angesehen, die mx+n Variante oder die mit Hessescher Normalform, in der Du Winkel und Abstand zur x Achse benutzt?
mfg
ojmjakon
23.09.2005, 14:19
http://www.iat.uni-bremen.de/mitarbeiter/nordbruch/research_projects/diploma/Kap4_Segmentierung.html
http://www.physik.uni-osnabrueck.de/nonlinop/Hough/LineHough.html
http://www.vision.ee.ethz.ch/~buc/brechbuehler/hough.html
Wenn du damit weiterkommst, dann kannst du ja mal Bescheid geben.
In Wikipedia findest auch noch was.
mfg
Über Sobel, Laplace etc. kannst du in dem Buch "Embedded Robotics" von Thomas Bräunl einiges finden, sogar mit C-Code
Da findest du auch Beispiele für Farb- und Bewegungserkennung.
ojmjakon
24.09.2005, 16:01
wenn das mal nicht so teuer wäre....
leider!
mfg
Leih es dir doch in der Bücherei!!
Ich habs mir in der Uni-Bücherei ausgeliehen...
michaelb
25.09.2005, 14:55
Hi,
hab ne Frage:
Wie kann man ein Webcambild in eine Applikation einbauen?
Gruß Michi
In Java? Schau dir mal folgenden Link an:
http://ltu164.ltu.edu/itseng/version.htm
damit hats bei mir auch geklappt. Ich hab jetzt allerdings nen neues Problem: Ich hab mein Webcambild in ein Schwarzweissbild umgewandelt und die RGB-Werte jedes Pixels in ein int[][] gespeichert. (Genauer gesagt nur einen Wert, weil bei einem S/W-Bild ja R = B = G ist. Auf diesem Array wollte ich nun verschiedene Operationen testen, als erstes den Sobel.
Hier der Code:
ActionListener sobelmebaby = new ActionListener() {
public void actionPerformed(ActionEvent e) {
int [][] sobelarray = new int[grayImage.getWidth()][grayImage.getHeight()];
for(int i = 0;i<grayImage.getWidth();i++){
for(int j = 0;j<grayImage.getHeight();j++){
sobelarray [i][j] = (((grayImage.getRGB(i,j))>>16& 0xFF)+0);
}
}
//Faltungskern:
//11,12,13
//21,22,23
//31,32,33
int sobel_11 = 0;
int sobel_12 = -1;
int sobel_13 = 0;
int sobel_21 = -1;
int sobel_22 = -4;
int sobel_23 = -1;
int sobel_31 = 0;
int sobel_32 = -1;
int sobel_33 = 0;
int workpixel;
if(grayImage != null){
for(int i = 2;i<318;i++){
for(int j = 2;j<238;j++){
//System.out.println("i: "+i+" ,j: "+j);
sobelarray[i][j] = sobelarray[i][j] + sobel_22;
sobelarray[i-1][j-1] = sobelarray[i-1][j-1] + sobel_11;
sobelarray[i][j-1] = sobelarray[i][j-1] + sobel_12;
sobelarray[i+1][j-1] = sobelarray[i+1][j-1] + sobel_13;
sobelarray[i-1][j] = sobelarray[i-1][j] + sobel_21;
sobelarray[i+1][j] = sobelarray[i+1][j] + sobel_23;
sobelarray[i-1][j+1] = sobelarray[i-1][j+1] + sobel_31;
sobelarray[i][j+1] = sobelarray[i][j+1] + sobel_32;
sobelarray[i+1][j+1] = sobelarray[i+1][j+1] + sobel_33;
}
}
for(int i = 2;i<320;i++){
for(int j = 2;j<240;j++){
workpixel = sobelarray [i][j];
Color farbe = new Color (workpixel,workpixel,workpixel);
grayImage.setRGB(i,j,farbe.getRGB());
}
}
}
System.out.println("Sobeling... done");
outcanvas.repaint();
}
};
Also als erstes wird halt das Array aus dem Grayimage (ein BufferedImage als BYTE_GREY) erzeugt. Dann die Sobel-Operationen am Array vorgenommen und dann das Array wieder in das BufferedImage geschrieben. Ich gehe den Weg über das Array, weils übersichtlicher und Afaik auch schneller ist.
Ich hab nun schon verschiedene Faltungskerne aus dem www probiert, darunter auch den von Wikipedia und bin bisher nur zu dem Ergebnis gekommen, dass das Bild von Schritt zu Schritt dunkeler wird... Bis mir irgendwann die Farbwerte von Color "out of bounds" gehen. Was ist an meinem Code falsch, dass das nicht funktioniert...? Ich vermute es liegt daran, WIE ich die Sobel-Faltung vornehme...
ojmjakon
28.09.2005, 16:30
Also wenn Du Dir Deinen Code ansiehst, siehst Du ja, daß für jeden Pixel die Werte desselben und die der umgebenden ständig dekrementiert werden.
Ein Sobel sieht meines Erachtens so aus
für Horizontal
1 2 1
0 0 0
-1 -2 -1
und für Vertikal
1 0 -1
2 0 -2
1 0 -1.
Du willst ja die Kanten betonen. Die daraus entstehende Formel wendest du nur für den akutelle Pixel, also den Mittelpunktpixel an.
Für ein skalierung, damit die Werte sich nicht zu stark verändern und in der Summe eins bleiben, kannst du 0.166 statt 1 und 0.333 statt 2 nehmen
double horiSobel = 0;
double vertSobel = 0;
vertSobel += sobelarray[i-1][j-1] * -0.1666;
vertSobel += sobelarray[i-1][j ] * -0.3333;
vertSobel += sobelarray[i-1][j+1] * -0.1666;
vertSobel += sobelarray[i+1][j-1] * 0.1666;
vertSobel += sobelarray[i+1][j ] * 0.3333;
vertSobel += sobelarray[i+1][j+1] * 0.1666;
horiSobel += sobelarray[i-1][j-1] * -0.1666;
horiSobel += sobelarray[i ][j-1] * -0.3333;
horiSobel += sobelarray[i+1][j-1] * -0.1666;
horiSobel += sobelarray[i-1][j-1] * 0.1666;
horiSobel += sobelarray[i ][j-1] * 0.3333;
horiSobel += sobelarray[i+1][j-1] * 0.1666;
sobelarray[i][j] = 360.0/(2.0*pi(atan(vertSobel / horiSobel)))
Am Ende stehts hier mir dem Arcustangens, musst mal sehen wie die Werte berechnet werden,wichtig scheint die aber Fließkommaarithmetik zu sein und nicht nur Integerwerte.
Du kannst auch nur die horiSobel- oder vertSobel-Werte in deine Matrix eintragen lassen. Dann hast du jeweils die horizontale und vertiakel Komponente. Auf jeden Fall funktioniert es so wie in Wikipedia beim Canny Operator beschrieben.
Wenn du mal verschiedene Faltungen unter Photoshop ausprobieren unter Filter/Sonstige Filter/Eigener Filter
Fragen?
mfg
ojmjakon
28.09.2005, 16:44
ah wichtig, du musst alle Sobelwerte erstmal in einer Matrix zwischenspeichern, Du willst ja nicht, daß bereits geänderte Werte der Nachbarpixel in die Berechnung des aktuellen Pixels mit einfließen. WEenn Du alle Pixel berechnet hast, kannst du sie in deine entgültige Matrix überschreiben.
ah, ok. ein weiteres prob war imho dass ich nen rgb-image und kein hsb genommen hab. afaik sobelt man auf dem b-kanal von hsb...
Allso meine Erfahrungen sind besser wenn man nicht vom Hue Kanal des HSB sobelt.
In meiner Galerie befinden sich 2 Screenshots von einem Programm, dass ich mal geschrieben habe. Eins direkt vom rgb gesobelt, und eins vom Hue Kanal... Als Faltungskern wurden der vert + horz Sobeloperator addiert.
Schauts euch mal an...
mmmm stimmt, das mit dem rgb is in der tat gut... ich habs nun so gemacht, dass ich halt aus nem bunten rgb nen s/w-rgb mache (R = B = G) und von jedem pixel den R-wert (ginge auch jeder andere) raushole und in nen array packe. dann sobel ich wie oben im code zu sehen. weiss jemand ob man in java 2 arrays of array direkt verwurschteln kann, damit ich den faltungskern nicht manuell einzeln verrechnen muss?
ah wichtig, du musst alle Sobelwerte erstmal in einer Matrix zwischenspeichern, Du willst ja nicht, daß bereits geänderte Werte der Nachbarpixel in die Berechnung des aktuellen Pixels mit einfließen. WEenn Du alle Pixel berechnet hast, kannst du sie in deine entgültige Matrix überschreiben.
weiss nicht genau, wie du das meinst. ich berechne ja alle werte, die unter dem faltungskern liegen und dann schreib ich sie direkt wieder ins gesamtarray. dann wird der kern verschoben und wieder verrechnet...
Ein Sobel sieht meines Erachtens so aus
für Horizontal
1 2 1
0 0 0
-1 -2 -1
und für Vertikal
1 0 -1
2 0 -2
1 0 -1.
ja, den hatte ich auch getestet. ich hab den anderen aus
http://www-user.tu-chemnitz.de/~niko/biber/tutorial/tutorial.pdf
ich muss mir das mit der faltung im allgemeinem nochmal anschauen, ich glaub ich (=mathe-noob) hab das noch nicht ganz kapiert... :)
weiss nicht genau, wie du das meinst. ich berechne ja alle werte, die unter dem faltungskern liegen und dann schreib ich sie direkt wieder ins gesamtarray. dann wird der kern verschoben und wieder verrechnet...
Das ist aber genau der falsche Weg, vor dem ojmjakon gewarnt hat.
Du musst die Ergebnisse des Faltungskerns in ein temporäres Array schreiben und das Originalbild unverändert lassen, bis du mit dem Faltungskern komplett durch das Bild gelaufen bist. Sonst gehen ja die geänderten Werte der schon berechneten Pixel mit in die Faltungsergebnisse der anderen Pixel ein.
Oder du nimmst einfach zwei verschiedene Images (Delphi) aus einem liest du ins andere schreibst du =)
ojmjakon
30.09.2005, 00:48
nochmal zur Houghe Transformation mit mx + n.
Ich habe eine Achse den Anstieg m. Der geht z.B. von 0 bis 1.
Was ist aber mit größeren und negativen Anstiegen. Die werden in dem Parameterraum gar nicht abgebildet.
mfg
was ist eigentlich afaik und imho??
und hsb?
afaik = as far as i know
imho = in my humble opinion
hsb = hue saturation brightness
nochmal zur Houghe Transformation mit mx + n.
Ich habe eine Achse den Anstieg m. Der geht z.B. von 0 bis 1.
Was ist aber mit größeren und negativen Anstiegen. Die werden in dem Parameterraum gar nicht abgebildet.
Deshalb nutzt man auch nicht die Parametriesierung mit mx+n. Das Problem dabei: Welchen Anstieg hast eine senkrechte vertikale Linie? Ja, einen unendlichen. Und unendlich große Zahlen machen sich immer schlecht.
Daher wählt man eine andere Parametrisierung, nämlich die Hessesche Normalform (siehe Wikipedia). Die beiden Parameter da sind der Winkel der Linie (von 0 bis 180 Grad) sowie der Abstand der Linie zum Koordinatenursprung. (die Länge des Lotes auf die Linie durch den Koordinatenursprung)
ojmjakon
30.09.2005, 20:47
Daher wählt man eine andere Parametrisierung, nämlich die Hessesche Normalform (siehe Wikipedia).
Ja daran hängt es etwas bei mir.
Ist mir zwar bischen peinlich zu fragen, aber kennt man noch andere Verfahren, die Normale einer Gerade in 2D zu bestimmen, als über den Sinus/Cosinus??
mfg
Steigungsdreieck??? Meinst du dass??
Daher wählt man eine andere Parametrisierung, nämlich die Hessesche Normalform (siehe Wikipedia).
Ja daran hängt es etwas bei mir.
Ist mir zwar bischen peinlich zu fragen, aber kennt man noch andere Verfahren, die Normale einer Gerade in 2D zu bestimmen, als über den Sinus/Cosinus??
Wo genau ist das Problem?
Pseudocode:
Für jede Bild-Koordinate (x,y) do:
if Pixel (x,y) ist gesetzt do:
für jedes a aus (0...180) do:
berechne d=x*sin(a) + y*cos(a)
inkrementiere den Wert an Position (d,a) im Parameter-Raum (Hough-Raum)
end
endif
end
Damit man nicht tausendmal sin() und cos() aufrufen muss, sollte man die Werte für die 180 Winkel vorher einmal berechnen und in ein array speichern.
PS: Den Grund, aus dem das Steigungsdreieck als Parametrisierung ausfällt, hatten wir schon geklärt.
ojmjakon
04.10.2005, 10:47
Schankedön :)
Die Parametrisierung funktioniert jetzt. Hatte einen Denkfehler, weil ich immer an eine bestimmte Gerade gedacht habe und nicht an alle möglichen bezüglich eines Pixels.
mfg
ojmjakon
was ist denn der akutelle stand der entwicklungen?
was leistet deine kantenerkennung und wie schnell fps/rechner ist sie?
ich hatte mal mit dem sobel tutorial über den h kanal experimentiert, allerdings mit eher bescheidenen ergebnissen.
h-Kanal is ja auch nix... Siehe oben
ojmjakon
13.10.2005, 00:14
was ist denn der akutelle stand der entwicklungen?
das würde mich auch interessieren. Ich schätze es ist so, daß man nur weitermacht wenn man Lust hat, bei mir ist das nicht anders.....
mfg
ojmjakon
Thomas Sc.
21.12.2005, 14:26
Hallo,
das ist ja genau das, wonach ich unter
https://www.roboternetz.de/phpBB2/viewtopic.php?t=15209
gefragt habe. Und dann auch noch in java, prima!
Goblin: Wie ist der Stand? Kann ich wo Deine aktuellen Sourcen downloaden? ich wäre (je nach freier zeit) auch gerne bereit, aktiv daran mitzuarbeiten, wenn das Ergebnis als OpenSource in Sinne von [siehe link] freigegeben wird.
cu,
Thomas
ok, schade dass es kein feedback gab. aber hier mal trotzdem meine ergebnisse:
ich habs hinbekommen, dass ich das webcam-bild in mein prog bekomme und das auch mit einer guten geschwindigkeit.
hier mal ein bild:
http://img337.imageshack.us/img337/4956/geschafft6hb.jpg
ich hab nen laserpunkt auf den teppich geworfen. sieht man links. und rechts ist der laserpunkt aus dem bild herausgerechnet.
weitere ziele sind jetzt:
- den punkt auf den pixel in seiner mitte zu reduzieren
- linien erkennen, auf 1 pixel breite reduzieren und als vektor speichern
- störende pixel herausrechnen (ich denke das werd ich mit faltung machen. muss mich da noch informieren)
und in zukunft:
- aus 2 bildern, die versetzt aufgenommen sind (stereoskopisch) eine tiefenmap erstellen (anhand einer laserlinie, die auf ein objekt projeziert wird)
- urlaub
Wäre es möglich, den Code Online zu stellen?
LG
LJTobek
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.