Herzlich willkommen zu dieser späten Stunde zur Übung für die
Vorlesung Robotik 1.
Mein Name ist Markus Grotz.
Ich bin wissenschaftlicher Mitarbeiter und Doktorand bei Tamin Astvor.
Während meiner Arbeitszeit beschäftige ich mich mit der Frage, wo
schauen Roboter als nächstes hin, um ihre Informationen über die
aktuelle Aufgabe zu maximieren?
Dazu benötige ich allerdings Grundlagen für die Bildverarbeitung.
Und das ist so das Ziel, dass ich das heute euch ein bisschen näher
beibringe.
Damit ihr auch mit dem Thema Bildverarbeitung was anfangen könnt.
Und vor allen Dingen ist es mir wichtig, dass ihr das praktisch
umsetzen könnt und nicht nur die Fragen in der Klausur beantworten
könnt.
So, als Agenda, ihr hattet ein Übungsblatt für heute.
Ich hoffe, ihr habt euch das alle angeschaut.
Wenn nicht, dann werden wir das heute gemeinsam durchsprechen.
Ich habe hier auf der Agenda Aufgabe 3 und Aufgabe 2 ein bisschen
vertauscht.
Das hat einfach ein bisschen thematisch ein bisschen besser gepasst.
Und ich würde jetzt einfach mal direkt mit Aufgabe 1
Farbrepräsentation beginnen.
Davor noch eine kleine, also die kleine Wiederholung.
Ihr kennt alle den HSI Farbraum aus der Vorlesung.
Und das Besondere an diesem Farbraum ist, dass er Farbinformationen
die sind getrennt abgespeichert von der Helligkeit und Intensität und
Sättigung der Farbe.
Genau, dazu habt ihr diese Formel kennengelernt, um einen Farbwert,
der im RGB-Format gegeben wird, in das HSI-Format umzurechnen.
Ganz kurz, H steht für Hue, das ist die Farbnuance, S ist die
Saturation, das ist die Sättigung der Farbe und I steht für Intensity,
bzw.
das ist die Helligkeit der Farbe.
Warum das Ganze ein Vorteil ist, das werde ich gleich erklären.
Wichtig ist diese Formel.
Hue ist Theta, falls der Blauwert kleiner als der Grünwert ist.
Andernfalls müssen wir erst 360 Grad minus Theta subtrahieren.
Theta ist ein bisschen kompliziert.
Die Formel müsst ihr euch leider auch auswendig lernen, falls ihr in
einer Klausuraufgabe dran kommt.
Also das ist der Arcus Kosinus, das ist der inverse Kosinus von 2R-G-B
durch, jetzt kommt natürlich ein großer Term, zwei Wurzeln aus R-G zum
Quadrat plus R-B multipliziert mit G-B.
Also einfach, das ist jetzt ein bisschen Fleiß.
Da kann man leider nichts machen.
Die Saturation ist definiert als 1-3 über die Summe der ganzen
Farbwerte im RGB-Format multipliziert mit dem Minimum des Farbwerts.
Die Helligkeit ist hier einfach der Mittelwert aus diesen drei Farben.
Man kann auch, wenn man das hier sieht, ist hier dieser Term
entspricht 1 durch i.
Also da ist ein kleiner Zusammenhang, kann man sich ein bisschen
Rechenseit sparen.
Weiß nicht, ob das was hilft.
Es ist ja ehrlich gesagt sehr, auch sehr einfach zu rechnen hier im
Vergleich zu Theta.
Gut, so als Aufgabe 1 war gegeben, dass ihr gegeben einen Farbwert im
RGB -Format, den sollt ihr in das HSI-Format transformieren und die
anderen beiden Aufgaben sind so ein bisschen Verständnisfragen.
Ich fange einfach mal an mit der Farbnuance.
Da oben ist nochmal der Farbwert.
Wir haben das Tuple 120, 80, 210, also rot, grün, blau.
Und die wollen wir jetzt in den HSI-Farbraum transformieren.
Und dazu müssen wir erst mal Theta ausrechnen.
Und Theta ist, ich hoffe, ihr könnt meine Schrift lesen, gegeben als
Harkus -Cosinus, das ist der inverse Cosinus, sozusagen von 2R-G-B.
Jetzt kommt ein langer Term.
Das ist die zweimal Wurzel aus
R -G zum Quadrat plus R-B multipliziert mit G-B.
Genau.
So, wir müssen natürlich noch die Klammer zumachen, damit das schön
aussieht.
Und jetzt können wir einfach unsere Werte einsetzen.
Wir haben hier oben das Tuple 120, 80, 210.
Also zweimal davon.
Das ist 240 minus 80 minus 210.
Und dann können wir das einfach ausrechnen.
Zweimal 120 minus 80.
Ich mache gleich die Wurzel, damit das einfacher ist.
Plus 120 minus 210 mal 80 minus 210.
So, und davon nehmen wir jetzt noch die Wurzel.
Und wie gesagt, jetzt können wir das einfach ausrechnen.
Moment, hier fehlt natürlich Cosinus hoch minus 1.
Das gehört natürlich auch noch hier hin.
Und deshalb ist Theta minus 50, das ist jetzt kein Hexenwerk, mal 2
durch 1600 plus 1700.
Das könnt ihr jetzt nachrechnen oder mir einfach glauben.
Und wenn man das jetzt in den Taschenrechner eingibt, dann könnt ihr
das ungefähr approximieren.
Also ist das ungefähr Cosinus hoch minus 1.
Der ganze Term ist ungefähr 0,21.
Sowas.
Und das entspricht, wenn man das dann ausrechnet, 102,5 Grad.
Genau, jetzt hatten wir aber noch so eine kleine Fallunterscheidung.
Falls b größer als g ist, müssen wir noch 360 Grad abziehen.
Das heißt, h ist in dem Fall 360 Grad minus Theta.
Das haben wir gerade ausgerechnet.
Und dann bekommen wir ungefähr 257,5 raus.
So, da haben wir auch schon unser erstes Ergebnis.
So, ein bisschen weiter.
Die Saturation bzw.
die Helligkeit, das ist ein bisschen einfacher.
Ich schreibe es einfach mal hin.
Wir haben ja gesagt, die Helligkeit ist einfach der Mittelwert von
diesen Farben.
Jetzt können wir wieder hier 120 plus 80 plus 210.
Das hatten wir vorhin schon ausgerechnet.
Ungefähr durch 3.
Das war ungefähr 410.
Und dann kommt hier ungefähr 136,7 raus.
Genau, für die Sättigung, da habe ich vorhin die Formel genannt.
Das ist... Moment, das sollte ein Minus sein.
So, das ist 1 durch i, das haben wir vorhin hier ausgerechnet, mal
Minimum r gb.
In dem Fall ist das 80.
Das können wir natürlich einsetzen.
1 minus 3 durch 410 multipliziert mit 80.
Und da kommt dann ungefähr 1 minus 240 durch 410 raus.
Und das Ganze ist 0,415.
Natürlich ein bisschen doof, der Wert.
Aber jetzt haben wir die Farbe vom r gb Raum in den hsi Raum
transformiert.
Und können dadurch auch Bereiche angeben, die uns dann erlauben,
Objekte zu erkennen, die invariant gegenüber der aktuellen Beleuchtung
sind.
Sind bis hierhin noch Fragen dazu?
Eigentlich ist es ja sehr einfach und auch ein bisschen kanonisch.
Wenn keine Fragen sind, dann würde ich einfach weitermachen mit der
nächsten Aufgabe.
Wir haben jetzt nämlich hier ein anderes Tupel.
Hier ist das Besondere, dass r 0 ist.
Und deshalb vereinfacht sich die Rechnung für Theta.
Wir hatten ja oben 2r minus g minus b.
Das heißt, wir können das direkt hinschreiben.
Also es ist 0 minus 130.
Und jetzt habe ich den Kosinus wieder vergessen.
Müsst ihr aufpassen, dass euch das in der Klausur nicht passiert.
Wir hatten hier r minus g, also einfach nur minus g. Also hier minus
150 zum Quadrat plus minus 130.
Multipliziert mit 150 minus 130.
Ich muss es ein bisschen größer machen.
Genau.
Jetzt können wir wieder das einfach ausrechnen.
Das ist eine einfache Subtraktion hier oben.
Minus 280 kommt raus.
Hier unten 2.
Die Zahl ist natürlich ein bisschen größer.
Ist natürlich dann nicht so einfach.
5.
So.
Genau.
Minus 1.
Das von minus 0 auf 4.
Und das sind ungefähr 172,9 Grad.
Das entspricht auch unserer Farbnuance.
B, also der blaue Wert, ist keiner als der grüne Wert.
Deshalb ist das sofort unsere Farbnuance.
Und wir haben h gleich Theta.
So.
Gut.
Genau.
Wenn wir jetzt wieder die Helligkeit berechnen.
Das war ja wieder einfach nur der Mittelwert.
R plus G plus B durch 3.
In dem Fall ist es sehr einfach.
Wir haben hier 280 durch 3.
Und das ist ungefähr 93,3.
Oder in jedem Fall ein Drittel.
So.
Genau.
Für die Sättigung ist das jetzt einfach nur geschenkt.
Weil wir haben hier das Minimum von R, G und B.
Und da hier ein Wert 0 ist, ist natürlich das Minimum 0.
Und wir multiplizieren hier 0.
Das heißt, die Sättigung ist einfach 1.
Gut.
Das wäre es von meiner Seite aus zur Umrechnung.
Ja.
Genau.
Ich habe jetzt hier nochmal ein paar Fragen vorbereitet.
Auf dem Übungsblatt.
Genau.
Ein Roboter betrachtet eine Müslipackung in einem fensterlosen Labor.
Jemand dreht das Licht etwas heller.
Ändern sich die R-, G- oder B-Werte der Müslipackung.
Wie sieht das im HSI-Raum aus?
Weiß jemand die Antwort?
Die Helligkeit.
Nur die Helligkeit ändert sich.
Genau.
Also hier nochmal zum Mitschreiben.
R, G und B ändern sich gleichmäßig.
Bei dem HSI-Farbraum ist es ja gerade der Vorteil, dass die Helligkeit
von der Farbnuance entkoppelt ist und wir dadurch sozusagen die
Farbnuance fest angeben können und wir können dann sozusagen einen
Bereich für die Helligkeit angeben und können dann zum Beispiel
Objekterkennung bei uns im Roboter machen.
Ihr kennt wahrscheinlich unseren Roboter nur aus der Vorlesung, aus
Videos.
Ihr habt am Ende der Vorlesung nochmal die Möglichkeit, eine Tour
durch unser Labor zu erhalten.
Da könnt ihr dann auch live sehen, wie unser Roboter dann eben Objekte
erkennt.
Und ich kann euch direkt sagen, das ist nicht so einfach, in der
realen Welt Objekte zu erkennen, weil einfach die Helligkeit sich
ständig ändert und das ist ein Problem, mit dem wir eigentlich nicht
täglich, aber mit dem haben wir oft zu kämpfen.
Und das ist nicht schwierig und da ist der HSI-Farbraum eben
eigentlich von Vorteil, weil da immer so eine Art Entkopplung hat und
dann eben einfach einen Bereich für die Helligkeit angeben kann.
So, eine etwas andere Frage.
Wir befinden uns jetzt in einer Küche und draußen schiebt sich eine
Wolke vor die Sonne.
Jetzt genau die gleiche Frage, was passiert mit den RGB-Werten und was
passiert im HSI-Farbraum, wenn wir uns diese Misty-Packung angucken.
Weiß jemand die Antwort?
Gut, wenn euch das Übungsblatt nicht angeguckt hat, dann spoilere ich
ein bisschen.
Also hier ändert sich nicht nur die Lichtintensität, sondern auch das
Farbspektrum und das heißt, hier verändern sich auch die Farbnuance
und die Sättigung.
Allerdings trifft das nicht so stark wie in dem RGB-Farbraum, sind
diese Änderungen nicht so groß.
So, ich habe es vorher noch ein bisschen erwähnt, ich würde gerne ein
bisschen so ein Praxisbeispiel machen.
Ich habe mir dazu OpenCV ausgesucht und zwar OpenCV ist eine
Bibliothek zur Bilderkennung, bietet eine ganze Möglichkeit von
möglichen Detektoren, hat eine Riesenschnittstelle und auch eine
Sammlung von ganz vielen Operatoren.
Und das Tolle ist, es hat eine sehr einfache Anbindung an Python und
ich finde die sehr intuitiv und das macht eigentlich sehr Spaß.
Ich weiß nicht, ihr seid im Studium eher mit Java in Verbindung
gekommen, ist das richtig?
Wer von euch kennt Java, müssten eigentlich alle kennen, oder?
Okay, wer hat schon mal mit Python programmiert?
Dann könnt ihr mir bestimmt zustimmen, dass das deutlich eleganter ist
als Java, weil ihr einfach weniger schreiben müsst.
Und jetzt im Folgenden möchte ich euch gerne zeigen, wie ihr einfach
unseren Roboter, der hier an der Seite ist, wie ihr den einfach mit
OpenCV als Bild laden könnt und dann könnt ihr den auch mit einer
Zeile in den HSV-Raum konvertieren und dort dann eine einfache
Segmentierung machen.
So, genau, wie sieht das denn aus, wenn wir ein Python-Programm
schreiben?
Wir haben in der ersten Zeile, haben wir so ein paar Import
-Funktionen, das kennt ihr auch aus Java.
Hier ist eigentlich die wichtige Zeile import-cv2, das sind die Python
-Bindings.
Dann müsst ihr zuerst das Bild lesen.
Wir haben jetzt hier so ein bisschen komisch, OpenCV hat so ein
bisschen Legacy-Code, das heißt, wir laden eigentlich keine RGB
-Bilder, sondern BGR-Bilder, aus historischen Gründen ist das so
umgedreht.
Und wir können die dann ganz einfach anzeigen, also wir müssen erst
diese Farbkanäle vertauschen, können das anzeigen und können das dann
eigentlich mit einer einzigen Zeile, können wir das komplette Bild,
also nicht nur ein Pixel, wie wir vorhin in den Übungsaufgaben gesehen
haben, sondern können das komplette Bild einfach in ein hsv-Bild
übertragen und haben dann auch die Möglichkeit, sozusagen eine untere
Schranke oder eine obere Schranke, für uns einen Farbwert, zu
definieren.
Und können das dann mit so einer einfachen Funktion, mit inRange,
können wir sozusagen eine binäre Maske angeben, die kann ich auch
gleich anzeigen, das heißt, wir haben eine binäre Maske von dem Bild
und können das dann mit einer einfachen Unverknüpfung, wie hier in der
Zeile zu sehen ist, können wir das dann einfach mit Unverknüpfen und
erhalten dann das Ergebnis, gefilterte Bild sozusagen.
Wenn ich diesen Code auf das rechte Bild anwende, also hier auf
unseren Roboter Arma 4, dann kann ich erstmal, in der Mitte ist
sozusagen die binäre Maske, wo ich sozusagen anhand des Farbwertes das
rausgefiltert habe, das war jetzt das KIT-Grün, und wenn ich das dann
mit Unverknüpfen, mit dem Originalbild, dann bekomme ich einfach
gerade hier das KIT-Logo.
Ist ein bisschen klein, aber ich hoffe, man kann es erkennen.
Was ihr auch noch seht, ist, dass ihr vielleicht hier so am Rand hier
sind noch so ein paar, wie soll ich sagen, Ausreißer.
Das liegt daran, dass ich diese Schranke, die ich gewählt habe, die
kann man natürlich noch ein bisschen verfeinern, aber die ist einfach
zu groß gewählt, deshalb findet ihr auch immer so ein paar grüne
Farben an der Seite.
Und um sowas wegzukriegen, sind morphologische Operatoren eigentlich
ganz praktisch.
Das kommt jetzt aber, habe ich jetzt ans Ende der Vorlesung gepackt.
Werden bis dahin noch Fragen zu dem OpenCV-Code?
Also wie gesagt, das ist nicht klausurrelevant, das ist einfach nur
damit ihr, falls ihr euch mal das in die Praxis umsetzen wollt, könnt
ihr euch dann da so ein Beispiel nehmen.
Gut, okay.
Dann, wenn keine weiteren Fragen sind, dann würde ich mit Aufgabe 3
weitermachen.
So, Aufgabe 3 ist gegeben, eine Lochkamera in Positivlage mit einer
festen Brennweite von 20 mm.
Ich muss dazu sagen, in echt werden Brennweiten meistens in Pixel
angegeben, damit man das einfacher umrechnen kann.
Also da müssen wir ein bisschen aufpassen mit den Einheiten.
Jetzt hier für die Vorlesung ist es halt natürlich ein bisschen stark
vereinfacht.
Hier ist die Brennweite einfach 20 mm.
Gut.
Die erste Aufgabe ist, wir fotografieren mit dieser Lochkamera ein
Gebäude aus einer Entfernung von 350 m und können im Bild messen, dass
das Bild 0,8 mm hoch ist.
Und wir fragen uns jetzt, wie hoch ist das Gebäude in echt?
Dazu können wir gleich das einfache Modell der Lochkamera verwenden.
Wir haben aber noch gleichzeitig eine weitere Aufgabe und zwar, wir
haben eine, wir wollen uns fragen, wir wissen, wie hoch der Kölner Dom
ist und versuchen jetzt sozusagen das Gegenteil.
Also wir fragen uns, wie hoch ist der jetzt im Bild?
So.
Dazu nochmal eine ganz, ganz kurze Wiederholung.
Wir haben das Lochkamera-Modell aus der Vorlesung bekannt und wir
haben einfach diesen, ich finde, sehr fundamentalen Zusammenhang
zwischen den Objektkoordinaten und den Bildkoordinaten.
In der Realität habt ihr auch kennengelernt, da gibt es dann noch die
Kamerakalibriermatrix, die berücksichtigt noch ein paar andere
intrinsische Faktoren.
Zusätzlich gibt es noch bei Kameras gibt es so Linsverzehrungen, aber
das ist einfach, das würde jetzt den Rahmen der Vorlesung so ein
bisschen sprengen.
Deshalb nehmen wir hier einfach dieses schöne, einfache Kameramodell,
damit lässt sich gut rechnen und wie ich finde, kann man da auch sehr
gute Klausuraufgaben stellen.
Und wir fangen jetzt einfach mal an mit unserer Aufgabe.
Wir haben gegeben, okay, unser Objekt ist 350 Meter entfernt, unser
Gebäude ist im Bild 0,8 hoch und wir fragen uns jetzt, wie hoch ist
das Gebäude in der Welt?
Genau.
Wenn wir unsere Formel einfach hernehmen und jetzt sozusagen nur eine
Komponente betrachten, also wir haben das DR in X- und Y-Richtung und
in U und V, ich mal das nochmal auf, also wir haben hier ist V und
hier ist U, das sind unsere Bildkoordinaten und das Schöne ist, wir
können das ganz einfach, also das Koordinatensystem ist so gewählt,
dass man da eigentlich sehr, ja, das Ganze schön umrechnen kann.
Und wir wollen jetzt wissen, wie hoch das Gebäude in der Welt ist.
Das ist unser Y, das müssen wir jetzt einfach nur umstellen nach Y,
das ist kein Hexenwerk.
Dann multiplizieren einfach mit dem Inversen, Z mal F und wir wissen
jetzt, Y gleich, also jetzt setzen wir einfach unsere Werte ein, 0,8
Millimeter ist das Gebäude im Bild hoch und 350 Meter ist es entfernt
und die Brennweite ist 20 Millimeter und wenn wir das einsetzen, dann
können wir das einfach, ja, so ein bisschen kürzen.
Das ist dann 0,4 mal 35 Meter und das entspricht 14 Meter.
An dieser Stelle, achtet auf die Einheiten, vor allem in der Klausur
oder sowas, wenn das vorkommt, da könnt ihr ganz gut überprüfen, habe
ich richtig gerechnet oder nicht.
Wie gesagt, meistens ist das Objekt im Bild nicht in Millimetern
angegeben, sondern in Pixeln.
Also da müsst ihr vielleicht noch einen weiteren Übertrag vornehmen.
Aber jetzt für diese Aufgabe ist das natürlich sehr einfach, wir
wissen jetzt, das Objekt ist 14 Meter hoch.
Jetzt haben wir genau das gleiche Problem, wir wissen allerdings die
Objekthöhe in der realen Welt und wir wissen auch die Entfernung und
wir fragen uns, wie hoch ist der abgebildete Kölner Dom jetzt in
unserem Bild.
Genau, dann müssen wir das erstmal noch so ein bisschen vereinfachen.
Wir haben hier 100 Pi Halbe Meter, ich weiß auch nicht, wer sich das
ausgedacht hat, aber genau, das können wir erstmal ungefähr so grob
abschätzen.
Wir können jetzt natürlich die Formel aus den vorigen Aufgaben nehmen,
die wir hergeleitet haben und da haben wir einfach diesen
Zusammenhang.
20 Millimeter durch...
genau, jetzt habe ich da aufgepasst.
Jetzt
können wir hier wieder kürzen.
Also das können wir wieder kürzen, 20 Millimeter durch 100, das können
wir auch verkürzen und das ist ungefähr dann 1 Millimeter durch 40,
können wir wieder kürzen und dann können wir das nochmal umstellen,
indem wir mit 40 multiplizieren, dann haben wir 80 Pixel, sprechen
ungefähr 1 Millimeter, genau.
So, gut, also hätten wir die Aufgabe gelöst.
So, das wäre es dann auch noch dazu.
Hat jemand noch Fragen zum Kameramodell oder sowas, sonst könnt ihr
auch gerne nach der Übung zu mir kommen und Fragen stellen oder ihr
fragt euch halt in der Klausur, was da los ist.
So, genau, dann mache ich einfach weiter mit Filter in der
Bildverarbeitung.
Das ist eigentlich so ein fundamentales Kapitel, da ich meistens meine
Bilder haben schlechte Qualität und ich muss die irgendwie vorfiltern
oder ich brauche bestimmte Eigenschaften, ich möchte Kanten
extrahieren und dazu habt ihr zum Beispiel für die Kantenextration
habt ihr in der Vorlesung das PreWidFilter kennengelernt, das ist
einfach eine Approximation des Gradienten, das gibt es in x- und y
-Richtung und damit können wir Kanten in horizontaler und in
vertikaler Richtung gut detektieren.
So, jetzt ein bisschen nicht erschrecken, genau, auf dem Übungsblatt
habt ihr so eine Riesenmatrix bekommen, das ist natürlich ein bisschen
ein Overkill, aber ihr seht schon, die hat überall die gleichen
Elemente und was wir jetzt machen ist, wenn wir jetzt zum Beispiel
diesen Wert hier berechnen wollen, dann müssen wir uns sozusagen seine
Nachbarschaft angucken, das wäre die hier und können dann sozusagen
damit mal anfangen.
Genau, jetzt solltet ihr die Filterung mit b in x-Richtung berechnen
und das auch in y-Richtung, ich sehe gerade, es ist ein Fehler, das
ist y, aber ich denke, das ist ziemlich einfach, wir nehmen uns
einfach einen Wert aus dieser Ursprungsmatrix, gucken uns die Umgebung
an und setzen dann die Werte ein und dann sind wir eigentlich schon
fertig.
Also ihr könnt das dann gerne zu Hause nachvollziehen.
Wenn ihr das macht, dann erhaltet ihr sozusagen hier diese sehr große
Matrix.
Was wir gerne oft machen auf dem Übungsblatt und auch, ich sage es
einfach mal so straight forward, in der Klausur, wir ignorieren gerne
die Randpunkte.
Da möchte ich gleich noch später was in der Vorlesung dazu sagen, weil
es gibt in der Praxis, es ist nämlich doof, wenn man dann immer den
Rand abschneidet, das möchte man nicht, deshalb habt ihr in der
Vorlesung da auch unterschiedliche Methoden kennengelernt, wie ihr
sozusagen mit diesem Rand umgehen könnt.
Genau, hier ist die Lösung für diese Aufgabe.
Ich finde, das ist eigentlich so ein bisschen trivial, aber lässt sich
sehr gut damit rechnen.
So, genau, ich habe jetzt hier noch so einen kleinen Praxiseinschub.
Wenn wir für Arma 4, das Bild habt ihr vorhin gesehen, das ist auch
auf vielen Folien, wenn wir für Arma 4 zum Beispiel die Kanten
detektieren wollen, dann ist das in OpenCV sehr einfach.
Wir laden einfach das Bild.
Wichtig ist hier diese Null, das ist eine Flag, damit können wir das
Bild automatisch als Graubild laden, können dann einfach den Canny
Edge Detection, der ist ein bisschen jetzt komplizierter, der lässt
sich nicht so einfach berechnen, aber in OpenCV ist das einfach nur
eine Zeile und die restlichen sechs Zeilen sind einfach nur, um das
Eingabebild anzuzeigen und sozusagen das Ausgabebild, also wie das
dann sozusagen in der Praxis aussieht.
Im Grunde genommen ist diese Kantendetektion eigentlich nur eine
einzige Funktion, Canny Detection.
Ich glaube, in der Vorlesung hattet ihr mehrere Folien dazu und wurdet
da auch so ein bisschen erschlagen, wie das eigentlich geht.
Wie gesagt, in der Praxis ist das sehr einfach, dafür kämpfen wir
häufig mit anderen Problemen, wie z.B.
der Helligkeit oder Lichtverhältnissen.
Genau, und wenn wir das einfach mal ausführen, dann erhalten wir hier
rechts unser Eingabebild und links ist unser, sozusagen das Ergebnis
von dem Canny Edge Detection und da können wir dann jetzt auch andere
Algorithmen drauflaufen lassen, wie z.B.
irgendwie zum Segmentieren oder wir können das für Lokalisierung
verwenden.
Aber ja, genau.
Ich habe es vorhin schon angesprochen, ihr hattet es auch schon in der
Vorlesung, wie gehe ich denn eigentlich bei der Berechnung von so
einem Filteroperator, wie gehe ich mit Rändern um und ihr habt da in
der Vorlesung mehrere Möglichkeiten kennengelernt.
Einmal hier könnt ihr einfach die Umgebung auf Konstanz setzen, also
hier auf 0.
Ich habe jetzt hier so einen großen Operator gewählt, das heißt, ihr
habt einfach einen größeren Rand.
Und das war vielleicht ein bisschen schnell.
Genau, das Ganze könnt ihr dann noch mit, es gibt noch andere
Möglichkeiten, ihr könnt z.B.
das Bild einfach fortsetzen.
Dabei wird das Bild von eurem, von OpenCV oder von eurer Bibliothek,
das wird einfach kopiert und dann nehmt ihr dann einen entsprechenden
Wert daraus.
Genau, man kann das natürlich auch spiegeln oder einfach den alten
Wert fest, oder den letzten Wert einfach festsetzen.
So, wie sieht das denn in der Praxis aus?
Wenn wir z.B.
so einen Medianfilter haben, ganz trivial, der nimmt einfach nur den
Mittelwert von seiner Umgebung.
Wichtig ist, wir haben jetzt bisher nur mit 3x3 Operatoren gearbeitet,
aber ich kann beim Filtern, ich kann eigentlich jede beliebige Größe
nehmen.
Also ich kann auch einen 9x9 Filter nehmen oder sowas.
Also es sind eigentlich keine Grenzen gesetzt.
Und ich möchte jetzt diesen Filter, möchte ich auf das sehr kleine
Eingabebild ansetzen.
Und da seht ihr schon, wie gehe ich da mit den Rändern um, weil ihr
merkt ja schon, dieser Operator, der passt ja nicht, all den kann ich
nicht überall anwenden.
Wenn wir das Bild konstant wählen, dann erweitern wir uns, oder denken
wir uns sozusagen eine Erweiterung vor.
Und wenn wir jetzt diesen Wert berechnen wollen, dann müssen wir uns
diese drei Werte angucken.
Bei konstant kann ich natürlich auch noch andere Werte einsetzen.
Und jetzt kann ich sozusagen mein Ergebnis berechnen.
Das Ganze sieht dann auch, wenn ich das fortsetze, dann sieht das so
aus.
Hier sieht man eigentlich schon sehr gut diese Struktur, also diese
90.
Diese Zeile wird hier unten genommen und einfach hier unten
hingesetzt.
Und ihr seht schon, ihr bekommt ein komplett anderes Ergebnis als
davor, wenn ihr einfach nur die Ränder konstant lässt.
So, genau, wenn ich das Ganze spiegel oder einfach festsetze, in dem
Fall ist es gleich, weil der Rand nur ein Pixel ist, dann bekommt der
wieder eine andere Matrix und dann gibt es noch einfach, sage ich mal
in Übungsaufgaben oder Klausuraufgaben, ist dann noch gerne einfach
der Wert ignoriert.
Dann bekommt ihr allerdings nur eine 1x1 Matrix.
In dem Fall ist das natürlich so ein bisschen schlecht, weil ihr
sozusagen den Großteil der Matrix einfach wegwerft.
So, das war einfach nur so eine kleine Wiederholung an euch, damit ihr
das so ein bisschen vertiefen könnt und euch da auch so ein bisschen,
dass das intuitiv für euch wird.
So, ich würde jetzt weitermachen mit morphologischen Operatoren, wenn
jetzt nicht noch irgendwelche Fragen zu den Filtern in der
Bilderverarbeitung sind.
Gut, dann weiter mit den morphologischen Operatoren.
Ihr kennt Erosion, Dilatation aus der V-Lösung.
Ich möchte jetzt auf Öffnen und Schließen nochmal eingehen.
Öffnen ist einfach zuerst Erosion und dann Dilatation.
Das muss man einfach auswendig lernen.
Schließen ist Dilatation und dann Erosion.
Das kann so ein bisschen verwirrend sein.
Und ich habe euch da folgendes Rauchstufenbild sozusagen als Beispiel
gegeben und dann so ein strukturierendes Element.
Ich nenne das jetzt mal strukturierendes Element.
Das ist nicht so ganz eins zu eins mit der Vorlesung, weil in der
Vorlesung habt ihr so einen Algorithmus, der sozusagen die N-Nachbarn
anguckt.
Weil ich habe jetzt sozusagen mit diesem strukturierenden Element, das
kann nämlich auch anders aussehen.
Das kann zum Beispiel auch so ein Kreuz sein.
Genau,
das könnte auch ein strukturierendes Element sein.
Das ist dann ein bisschen aufwendiger, weil ich kann nämlich die
morphologischen Operatoren als Mengenoperatoren betrachten.
Und dann kann man da sofort mit einer ganzen, sozusagen ein bisschen
mehr Mathematik machen.
Aber das ist jetzt für diese Vorlesung erstmal egal.
Das strukturierende Element, was ich hier angegeben habe, das
entspricht in unserem Algorithmus für N gleich drei.
Und wir möchten jetzt dieses Bild, was hier oben ist, diese große
Matrix, da möchten wir sozusagen unseren Erosionsalgorithmus, und
danach Dilatation anwenden.
Und ihr sollt die Randwerte ignorieren.
Unser strukturierendes Element entspricht N gleich drei, also wir
gucken uns einfach nur die Nachbarn an.
Genau, was macht dieser Algorithmus?
Wir gehen jetzt einfach mal Schritt für Schritt durch.
Wir setzen erstmal alle Pixel unseres neuen Bildes, also den I-Strich,
setzen wir auf Null.
Ich habe geschrieben, dass wir die Randwerte bitte ignorieren sollen,
deshalb habe ich die so ein bisschen ausgegraut, das ist eigentlich
egal, was da drin steht, das müssen wir nicht berechnen.
Und jetzt gehen wir einfach für dieses strukturierende Element, das
wir da haben, da überprüfen wir jetzt sozusagen die
Nachbarschaftsumgebung in diesem Teil, und gucken da einfach, was
passiert.
So, das können wir einfach mal machen, wir haben hier oben unser
Eingabebild, und wir wollen jetzt für diesen Zielwert, wollen wir den
morphologischen Operator anwenden, und dann müssen wir uns sozusagen
hier diese Werte angucken.
Okay, genau, was macht eigentlich die Erosion?
Die Erosion guckt, ob alle Werte, die hier gegeben sind, also die
jetzt in meinem roten Viereck sind, ob die gleich 255 sind, oder Q in
dem Fall, und wenn das nicht der Fall ist, dann wird der Zielwert auf
Null gesetzt, andernfalls wird er auf 255 gesetzt.
So, das ist jetzt das Ergebnis für die erste Iteration, wir nehmen
eine Vorschleife, wenn wir jetzt in der Vorschleife sozusagen eins
weiter springen und das nächste Element berechnen, dann gucken wir uns
hier diese Werte an, und da sind wieder Werte, die einfach nicht auf
Null gesetzt sind, deshalb kommt hier wieder ein Null, das können wir
bei der dritten Iteration eigentlich genauso, deshalb überspringe ich
das jetzt, und in der vierten Iteration sind sozusagen alle Werte auf
255, und deshalb ist das ja auch in unserer Zielmatrix, ist der Wert
auch gleich 255.
So, genau.
Das können wir beliebig weitermachen, und wir erhalten jetzt als
Ergebnis die untenstehende Matrix, wie gesagt, wir haben gesagt, wir
ignorieren die Randwerte, das heißt, wir erhalten eine neue Matrix,
die sozusagen jeweils ein bisschen kleiner ist als unsere
Eingangsmatrix, und wenn wir die Erosion dann darauf anwenden, dann
erhalten wir das Bild.
Und wir sehen ja auch schon, es haben sich jetzt hier, also, genau,
die Zielmatrix hat dann sozusagen das gleiche Wert, und wir sehen es
schon, es haben sich hier so, ja, also, die Werte hier, die sind jetzt
auf Null gesetzt worden.
Also mit dieser Erosion können wir so kleine Stege entfernen.
Analog dazu funktioniert die Dilatation, die Dilatation entfernt
allerdings keine kleinen Stege, sondern die Dilatation kann man
sozusagen so beschreiben, dass sie kleine Löcher schließt.
So, also, wir haben unser Eingabebild, das haben wir jetzt sozusagen
als Teilergebnis davor, und hier steht schon natürlich das Ergebnis,
aber ich mache jetzt einfach mal weiter.
In unserem Algorithmus, also die Dilatation, die fängt genauso wie die
Erosion an, die werden erstmal alle Werte in dem Zielbild, die werden
auf Null gesetzt, und genau, dann gehen wir anfangs mit unserem
strukturierenden Element durch die Matrix, und berechnen dann für
jedes Pixel im Zielbild, berechnen wir dann die entsprechenden Werte.
So, genau, also, genauso, hier ist die erste Iteration, wir gucken uns
jetzt in der Eingabematrix diese Bilder an, und wenn da kein Wert
davon 255 ist, dann setzen wir in der Null, ist, sobald einer dieser
Werte im Eingabebild sozusagen in der Umgebung, die durch das
strukturierende Element gegeben ist, ist, wenn die, sagen, größer als
255 ist, oder ein Wert davon 255 ist, dann ist unser Wert in der
Zielmatrix auch 255.
Genau, das ist auch hier schon gegeben, wir haben jetzt uns nämlich
hier in dieser Umgebung, das sind gleich drei Werte, eben entsprechend
Q, also Q ist 255, und deshalb ist unser, in der zweiten Iteration ist
dieser Pixelwert auch 255.
Genau, das können wir natürlich so beliebig machen, und erhalten dann
als Ergebnis sozusagen ein ausgedünntes Bild, und, ja, da können wir
so kleine Löcher eigentlich damit schließen, das wird eigentlich bei
größeren Bildern eher sichtbar.
So, ich habe jetzt nämlich noch ein ganzes, wieder ein Python
-Beispiel, und zwar haben wir dieses Bild aus der Vorlesung, das ist
unser Eingabebild, wir definieren, das sind Körner, also das ist das
strukturierende Element, das ist einfach eine Zehn-Kreuz-Zehen-Matrix,
die mit 255 gefüllt ist, und die lassen wir einfach über das Bild
laufen, mit dem öffnen Algorithmus, mit dem morphologischen Operator,
und wir sehen, wir haben jetzt schon in diesem Eingabebild, haben wir
so kleine Stege entfernt, wie hier zu sehen ist, und wir haben hier
auch so ein paar Löcher geschlossen.
Und damit kann man dann zum Beispiel schon so ein einfaches Hand
-Tracking oder sowas implementieren, oder einfach einen Detektor für
eine grüne Tasse.
Wichtig sind hier diese beiden Zeilen.
Und das wäre es dann auch schon von meiner Seite aus zu dem Übungsblatt.