Verkehrszeichenerkennung: Unterschied zwischen den Versionen

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen
Zeile 19: Zeile 19:


=== Einlesen und Zerlegen des Videos ===
=== Einlesen und Zerlegen des Videos ===
[[Datei:1Original.jpg|500px|thumb|right|Ursprungsbild das analysiert werden soll]]
Zum Einlesen eines Bildes in Matlab kann man das Tool VideoReader benutzen. Dazu navigiert man als aller erstes zum Speicherort des Videos und kann dann durch das Tool die Videodatei in den Workspace laden. Dies kann wie folgt aussehen:
Zum Einlesen eines Bildes in Matlab kann man das Tool VideoReader benutzen. Dazu navigiert man als aller erstes zum Speicherort des Videos und kann dann durch das Tool die Videodatei in den Workspace laden. Dies kann wie folgt aussehen:
  cd C:\Users\IronMan
  cd C:\Users\IronMan
Zeile 45: Zeile 46:
Im eigentlichen Programm können nun die abgespeicherten Bilder aufgerufen werden und in einer Datenbank abgespeichert werden um dann mit der Verkehrszeichenerkennung beginnen zu können. In diesem Projekt sollen dabei Geschwindigkeitsschilder erkannt werden und die Geschwindigkeit ausgelesen werden.<br />
Im eigentlichen Programm können nun die abgespeicherten Bilder aufgerufen werden und in einer Datenbank abgespeichert werden um dann mit der Verkehrszeichenerkennung beginnen zu können. In diesem Projekt sollen dabei Geschwindigkeitsschilder erkannt werden und die Geschwindigkeit ausgelesen werden.<br />
[[Datei:70.gif|150px|thumb|right|70er Verkehrszeichen]]
[[Datei:70.gif|150px|thumb|right|70er Verkehrszeichen]]
Wenn man sich nun so ein Geschwindigkeitsschild beschreibt, kann man einen roten Kreis erkennen und zwei oder drei schwarze Ziffern. Also könnte man nach Zahlen,Kreisen oder einer Farbe im Bild suchen suchen. Zahlen kann man sehr gut durch TemplateMatching finden, allerdings ist es hier am besten, wenn die Größe und die Rotation des Templates mit der Zahl im Bild übereinstimmt. Also sollte man diesen Schritt nicht zuerst durchführen, da dies zu rechenaufwendig wär,weil man in diesem Fall das Template auf verschiedene Größen ziehen würde um eine Zahl zu erkennen. Wahrscheinlich wäre es auch zu ungenau. Kreise zu finden könnte man durchaus auch in Betracht ziehen, allerdings wie soll gewährleistet werden dass dies wirklich ein Verkehrszeichen ist und nicht ein ungünstig liegender Fußball. Eine Farberkennung  führt zum Ziel, wie man in den folgenden Zeilen erkennen wird.  
Wenn man sich nun so ein Geschwindigkeitsschild beschreibt, kann man einen roten Kreis erkennen und zwei oder drei schwarze Ziffern. Also könnte man nach Zahlen,Kreisen oder einer Farbe im Bild suchen suchen. Zahlen kann man sehr gut durch TemplateMatching finden, allerdings ist es hier am besten, wenn die Größe und die Rotation des Templates mit der Zahl im Bild übereinstimmt. Also sollte man diesen Schritt nicht zuerst durchführen, da dies zu rechenaufwendig wär,weil man in diesem Fall das Template auf verschiedene Größen ziehen würde um eine Zahl zu erkennen. Wahrscheinlich wäre es auch zu ungenau. Kreise zu finden könnte man durchaus auch in Betracht ziehen, allerdings wie soll gewährleistet werden dass dies wirklich ein Verkehrszeichen ist und nicht ein ungünstig liegender Fußball. Eine Farberkennung  führt zum Ziel, wie man in den folgenden Zeilen erkennen wird.  
Der RGB-Farbraum teilt sich in drei Bereiche ein. Es gibt eine rote, eine grüne und eine blaue Matrix. Erst könnte man denken es würde reichen nur die rote Matrix zu betrachten, allerdings ist in der Farbe weiß jeder Farbanteil zu 100 Prozent enthalten, weshalb es von Vorteil ist die Farben miteinander zu vergleichen. Im Matlabcode kann dies folgendermaßen aussehen:
Der RGB-Farbraum teilt sich in drei Bereiche ein. Es gibt eine rote, eine grüne und eine blaue Matrix. Erst könnte man denken es würde reichen nur die rote Matrix zu betrachten, allerdings ist in der Farbe weiß jeder Farbanteil zu 100 Prozent enthalten, weshalb es von Vorteil ist die Farben miteinander zu vergleichen. Im Matlabcode kann dies folgendermaßen aussehen:
Zeile 50: Zeile 52:
     Pic(x,y)=1;
     Pic(x,y)=1;
  end
  end
[[Datei:1Original.jpg|500px|thumb|right|Ursprungsbild das analysiert werden soll]]


[[Datei:2Bereiche.jpg|500px|thumb|right|Hier wurden rote Bereiche gefunden(Dies ist nur der linke obere Teil des Bildes)]]
[[Datei:Ziffern.png|1000px|thumb|right|1.Position Schild 2.Umwandlung in Binärbild 3.Entfernen von störenden Pixeln 4.&5. Auschneiden und skalieren der Ziffern 6.Geschwindigkeit erkannt und Bild aus Templates erstellt]]
Hier wird zum einen festgelegt, dass der rote Pixelanteil einen größeren Wert haben muss als die anderen und des anderen muss er einen gewissen Abstand zu den anderen Teilen haben, damit man den Pixel als roten Punkt wahrnimmt. Wenn die Kriterien erfüllt sind schafft es der Pixel in die neue Matrix "Pic". Wenn diese Matrix vervollständigt ist wandelt man diese in das Binärformat von Matlab um. Am einfachsten ist dies mit dem Befehl "im2bw". Nun ist man mit der Farberkennung fertig und sucht auf dem Bild nach Bereichen, die zusammenliegen. Damit man dabei nicht viele unnötige Informationen bekommt stopft man die Löcher von zusammenliegenden Formationen um deren Salt&Pepper-Inhalt zu entfernen mit "bwareopen". Darauf kann man nun den wichtigeren Befehl "bwboundaries"  ausführen um zusammenliegende Bereiche zu finden und somit auch das Verkehrszeichen. Dieser Befehl ist zwar ein rechenintensiverer aber in diesem Konzept nicht wegzudenken. Aus diesem bekommt man nun die Umrissinformationen der Bereiche und kann daraus die Minimal- und Maximal-Pixel des ausgewählten Bereichs herausfinden. Da die Zahlen auf dem Stoppschild nur aus gewisser Entfernung gelesen werden kann und man einen Mindestabstand zu solchem hat, kann man die Bereiche ausklammern lassen die einen zu hohen oder zu niedrigen Umfang haben. Am Ende dieses Schrittes kann es aber immer noch sein, dass man etwas falsches gefunden hat. Dies klärt sich aber im nun folgenden TemplateMatching.
Hier wird zum einen festgelegt, dass der rote Pixelanteil einen größeren Wert haben muss als die anderen und des anderen muss er einen gewissen Abstand zu den anderen Teilen haben, damit man den Pixel als roten Punkt wahrnimmt. Wenn die Kriterien erfüllt sind schafft es der Pixel in die neue Matrix "Pic". Wenn diese Matrix vervollständigt ist wandelt man diese in das Binärformat von Matlab um. Am einfachsten ist dies mit dem Befehl "im2bw". Nun ist man mit der Farberkennung fertig und sucht auf dem Bild nach Bereichen, die zusammenliegen. Damit man dabei nicht viele unnötige Informationen bekommt stopft man die Löcher von zusammenliegenden Formationen um deren Salt&Pepper-Inhalt zu entfernen mit "bwareopen". Darauf kann man nun den wichtigeren Befehl "bwboundaries"  ausführen um zusammenliegende Bereiche zu finden und somit auch das Verkehrszeichen. Dieser Befehl ist zwar ein rechenintensiverer aber in diesem Konzept nicht wegzudenken. Aus diesem bekommt man nun die Umrissinformationen der Bereiche und kann daraus die Minimal- und Maximal-Pixel des ausgewählten Bereichs herausfinden. Da die Zahlen auf dem Stoppschild nur aus gewisser Entfernung gelesen werden kann und man einen Mindestabstand zu solchem hat, kann man die Bereiche ausklammern lassen die einen zu hohen oder zu niedrigen Umfang haben. Am Ende dieses Schrittes kann es aber immer noch sein, dass man etwas falsches gefunden hat. Dies klärt sich aber im nun folgenden TemplateMatching.
Dazu kann man nun das Bild erst mal von allen Dingen befreien, die nichts mit der aufgedruckten Zahlen auf dem Schild zu tun haben beziehungsweise das Bild verwerfen, wenn es von den Proportionen nicht passt, denn schließlich sollten bei einem Kreis die x- und y-Breite des gefundenen Bereichs gleich sein. Nun verkleinert man das Bild um einen gewissen Prozentsatz, sodass der rote Kreis so gut wie nicht mehr zu sehen ist aber noch die Zahlen. Als nächsten Schritt misst man nun den Abstand zwischen dem rechten Rand des Bildes und der 0. Dies kann man gut realisieren, da rechts immer eine Null ist sodass man immer den richtigen Abstand bekommt. Diesen zieht man dann von allen Seiten ab und schon hat man fast ein Bild, wo nur Zahlen abgebildet sind. Nun löscht man nur noch Pixel aus den Ecken und man kann nun eine Funktion ausführen, die Zahlen aufteilt in zwei bzw drei Bilder mit jeweils einer Ziffer. Dadurch werden die Pixel von oben nach unten über das Bild aufsummiert(also alle Pixel in einer Spalte) und wo nur Nullen im Binärbild gefunden wurden wird das Bild durchgeschnitten. Da man nun seine Ziffern vereinzelt hat, kann man die Bildern mit den Ziffern auf die Templategröße bringen mit "imresize" und das Template mit größter Korrelation hat gewonnen. "corr2" ist an dieser Stelle eine geeignete Funktion.
Dazu kann man nun das Bild erst mal von allen Dingen befreien, die nichts mit der aufgedruckten Zahlen auf dem Schild zu tun haben beziehungsweise das Bild verwerfen, wenn es von den Proportionen nicht passt, denn schließlich sollten bei einem Kreis die x- und y-Breite des gefundenen Bereichs gleich sein. Nun verkleinert man das Bild um einen gewissen Prozentsatz, sodass der rote Kreis so gut wie nicht mehr zu sehen ist aber noch die Zahlen. Als nächsten Schritt misst man nun den Abstand zwischen dem rechten Rand des Bildes und der 0. Dies kann man gut realisieren, da rechts immer eine Null ist sodass man immer den richtigen Abstand bekommt. Diesen zieht man dann von allen Seiten ab und schon hat man fast ein Bild, wo nur Zahlen abgebildet sind. Nun löscht man nur noch Pixel aus den Ecken und man kann nun eine Funktion ausführen, die Zahlen aufteilt in zwei bzw drei Bilder mit jeweils einer Ziffer. Dadurch werden die Pixel von oben nach unten über das Bild aufsummiert(also alle Pixel in einer Spalte) und wo nur Nullen im Binärbild gefunden wurden wird das Bild durchgeschnitten. Da man nun seine Ziffern vereinzelt hat, kann man die Bildern mit den Ziffern auf die Templategröße bringen mit "imresize" und das Template mit größter Korrelation hat gewonnen. "corr2" ist an dieser Stelle eine geeignete Funktion.
Wie der aufmerksame Leser nun bemerkt hat ist man nun nicht mehr weit entfernt von der Lösung.
Wie der aufmerksame Leser nun bemerkt hat ist man nun nicht mehr weit entfernt von der Lösung.


[[Datei:2Bereiche.jpg|500px|thumb|right|Hier wurden rote Bereiche gefunden(Dies ist nur der linke obere Teil des Bildes)]]
<br /><br /><br /><br /><br /><br />
[[Datei:Ziffern.png|1000px|thumb|right|1.Position Schild 2.Umwandlung in Binärbild 3.Entfernen von störenden Pixeln 4.&5. Auschneiden und skalieren der Ziffern 6.Geschwindigkeit erkannt und Bild aus Templates erstellt]]  <br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />


=== Letzte Schritte und anzeigen der Geschwindigkeit ===
=== Letzte Schritte und anzeigen der Geschwindigkeit ===
[[Datei:Endbild.jpg|800px|thumb|right|Die Geschwindigkeit wurde erkannt und wird nun im Bild angezeigt]]
Nun ist noch zu überprüfen, ob die herausgegebenen Zahlen Stimmen. Dazu kann man als letzten Schritt noch überprüfen ob es nur noch zwei oder drei Zahlen sind, die am Ende übrig geblieben sind. Als letzten Schritt muss man nun also noch irgendwie die Geschwindigkeit ins Livebild zaubern. Dazu kann man die sowieso verwendeten Templates zur Hilfe nehmen und diese Binärbilder in das RGB-Bild einbauen. Mit dem Befehl "uint8()"  kann man sich hier eine eigene Matrix bauen für zum Beispiel den Rotanteil des Bildes. Hier wird das Graubild in die rote Matrix geschrieben:
Nun ist noch zu überprüfen, ob die herausgegebenen Zahlen Stimmen. Dazu kann man als letzten Schritt noch überprüfen ob es nur noch zwei oder drei Zahlen sind, die am Ende übrig geblieben sind. Als letzten Schritt muss man nun also noch irgendwie die Geschwindigkeit ins Livebild zaubern. Dazu kann man die sowieso verwendeten Templates zur Hilfe nehmen und diese Binärbilder in das RGB-Bild einbauen. Mit dem Befehl "uint8()"  kann man sich hier eine eigene Matrix bauen für zum Beispiel den Rotanteil des Bildes. Hier wird das Graubild in die rote Matrix geschrieben:
  RGB{k}(1000:999+length(speed(:,1)),1800:1799+length(speed(1,:)),1)=speedgrey;
  RGB{k}(1000:999+length(speed(:,1)),1800:1799+length(speed(1,:)),1)=speedgrey;
 
[[Datei:Endbild.jpg|800px|thumb|left|Die Geschwindigkeit wurde erkannt und wird nun im Bild angezeigt]]
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />



Version vom 21. Juni 2014, 16:05 Uhr

Autor: Michael Deitel
Betreuer: Prof. Schneider

Motivation

Bei monotonen Autofahrten entgeht einem Fahrer gelegentlich ein Verkehrszeichen. Diese Matlab-"App" soll den Fahrer über eine Anzeige an das aktuell gültige Verkehrszeichen erinnern.

Ziel

Darstellung des aktuell gültigen Verkehrszeichens während einer aufgezeichneten Fahrt.

Aufgabe

  1. Lesen Sie das aufgezeichnete Video in Matlab ein.
  2. Zerlegen Sie diesen Film in Einzelframes.
  3. Extrahieren Sie die Verkehrszeichen auf diesen Frames mit Matlab.
  4. Schreiben Sie eine Schleife über alle Frames und zeigen Sie das aktuell gültige Verkehrszeichen automatisch neben dem Video an.

Hinweis: Die Verkehrszeichenerkennung muss robust für beliebige am Tag gefilmte Sequenzen funktionieren.

Lösung

Einlesen und Zerlegen des Videos

Ursprungsbild das analysiert werden soll

Zum Einlesen eines Bildes in Matlab kann man das Tool VideoReader benutzen. Dazu navigiert man als aller erstes zum Speicherort des Videos und kann dann durch das Tool die Videodatei in den Workspace laden. Dies kann wie folgt aussehen:

cd C:\Users\IronMan
obj = VideoReader('Schilder.MTS');

Die Funktion VideoReader unterstützt relativ viele Formate und speichert diese auch meist zuverlässig ab. Das MTS-Format, das hier eingelesen wird, ist ein sehr rechenintensives Format und umfasst in diesem Fall 50 Frames pro Sekunde. Das hat in diesem Fall ein Volllaufen des für Matlab reservierten Arbeitsspeichers geführt und es wurden nicht alle Frames eingelesen und auch nicht ganz in der richtigen Reihenfolge. Die erwähnten 50fps sind natürlich mehr als genug für die Verkehrszeichenerkennung. Daher sollte man nun den Datenstrom mit Matlab verringern, indem man nur alle 20 Bilder abspeichert. Damit diese auch gescheit geordnet werden, ist dies eine gute Lösung:

for k = 1 : 380
  this_frame = read(obj,k+p);
  p=p+20;
  if k<100 && k>9
      imwrite(this_frame,sprintf('Schilder0%u.jpg' ,k));
  end
 
  if k<10
      imwrite(this_frame,sprintf('Schilder00%u.jpg' ,k));
  end
  
  if k>99
      imwrite(this_frame,sprintf('Schilder%u.jpg' ,k));
  end
end

Mit "read" wird aus obj das Frame k+p ausgelesen und "imwrite" schreibt dieses Frame in eine jpg-Datei. "sprintf" hilft uns bei der Namensgebung.

Finden des Verkehrszeichens

Im eigentlichen Programm können nun die abgespeicherten Bilder aufgerufen werden und in einer Datenbank abgespeichert werden um dann mit der Verkehrszeichenerkennung beginnen zu können. In diesem Projekt sollen dabei Geschwindigkeitsschilder erkannt werden und die Geschwindigkeit ausgelesen werden.

70er Verkehrszeichen

Wenn man sich nun so ein Geschwindigkeitsschild beschreibt, kann man einen roten Kreis erkennen und zwei oder drei schwarze Ziffern. Also könnte man nach Zahlen,Kreisen oder einer Farbe im Bild suchen suchen. Zahlen kann man sehr gut durch TemplateMatching finden, allerdings ist es hier am besten, wenn die Größe und die Rotation des Templates mit der Zahl im Bild übereinstimmt. Also sollte man diesen Schritt nicht zuerst durchführen, da dies zu rechenaufwendig wär,weil man in diesem Fall das Template auf verschiedene Größen ziehen würde um eine Zahl zu erkennen. Wahrscheinlich wäre es auch zu ungenau. Kreise zu finden könnte man durchaus auch in Betracht ziehen, allerdings wie soll gewährleistet werden dass dies wirklich ein Verkehrszeichen ist und nicht ein ungünstig liegender Fußball. Eine Farberkennung führt zum Ziel, wie man in den folgenden Zeilen erkennen wird. Der RGB-Farbraum teilt sich in drei Bereiche ein. Es gibt eine rote, eine grüne und eine blaue Matrix. Erst könnte man denken es würde reichen nur die rote Matrix zu betrachten, allerdings ist in der Farbe weiß jeder Farbanteil zu 100 Prozent enthalten, weshalb es von Vorteil ist die Farben miteinander zu vergleichen. Im Matlabcode kann dies folgendermaßen aussehen:

if Rot(x,y)>Blau(x,y) && Rot(x,y)>Gruen(x,y) && abs(Rot(x,y) - Gruen(x,y))>40 && abs(Rot(x,y) - Blau(x,y))>40
    Pic(x,y)=1;
end
Hier wurden rote Bereiche gefunden(Dies ist nur der linke obere Teil des Bildes)
1.Position Schild 2.Umwandlung in Binärbild 3.Entfernen von störenden Pixeln 4.&5. Auschneiden und skalieren der Ziffern 6.Geschwindigkeit erkannt und Bild aus Templates erstellt

Hier wird zum einen festgelegt, dass der rote Pixelanteil einen größeren Wert haben muss als die anderen und des anderen muss er einen gewissen Abstand zu den anderen Teilen haben, damit man den Pixel als roten Punkt wahrnimmt. Wenn die Kriterien erfüllt sind schafft es der Pixel in die neue Matrix "Pic". Wenn diese Matrix vervollständigt ist wandelt man diese in das Binärformat von Matlab um. Am einfachsten ist dies mit dem Befehl "im2bw". Nun ist man mit der Farberkennung fertig und sucht auf dem Bild nach Bereichen, die zusammenliegen. Damit man dabei nicht viele unnötige Informationen bekommt stopft man die Löcher von zusammenliegenden Formationen um deren Salt&Pepper-Inhalt zu entfernen mit "bwareopen". Darauf kann man nun den wichtigeren Befehl "bwboundaries" ausführen um zusammenliegende Bereiche zu finden und somit auch das Verkehrszeichen. Dieser Befehl ist zwar ein rechenintensiverer aber in diesem Konzept nicht wegzudenken. Aus diesem bekommt man nun die Umrissinformationen der Bereiche und kann daraus die Minimal- und Maximal-Pixel des ausgewählten Bereichs herausfinden. Da die Zahlen auf dem Stoppschild nur aus gewisser Entfernung gelesen werden kann und man einen Mindestabstand zu solchem hat, kann man die Bereiche ausklammern lassen die einen zu hohen oder zu niedrigen Umfang haben. Am Ende dieses Schrittes kann es aber immer noch sein, dass man etwas falsches gefunden hat. Dies klärt sich aber im nun folgenden TemplateMatching. Dazu kann man nun das Bild erst mal von allen Dingen befreien, die nichts mit der aufgedruckten Zahlen auf dem Schild zu tun haben beziehungsweise das Bild verwerfen, wenn es von den Proportionen nicht passt, denn schließlich sollten bei einem Kreis die x- und y-Breite des gefundenen Bereichs gleich sein. Nun verkleinert man das Bild um einen gewissen Prozentsatz, sodass der rote Kreis so gut wie nicht mehr zu sehen ist aber noch die Zahlen. Als nächsten Schritt misst man nun den Abstand zwischen dem rechten Rand des Bildes und der 0. Dies kann man gut realisieren, da rechts immer eine Null ist sodass man immer den richtigen Abstand bekommt. Diesen zieht man dann von allen Seiten ab und schon hat man fast ein Bild, wo nur Zahlen abgebildet sind. Nun löscht man nur noch Pixel aus den Ecken und man kann nun eine Funktion ausführen, die Zahlen aufteilt in zwei bzw drei Bilder mit jeweils einer Ziffer. Dadurch werden die Pixel von oben nach unten über das Bild aufsummiert(also alle Pixel in einer Spalte) und wo nur Nullen im Binärbild gefunden wurden wird das Bild durchgeschnitten. Da man nun seine Ziffern vereinzelt hat, kann man die Bildern mit den Ziffern auf die Templategröße bringen mit "imresize" und das Template mit größter Korrelation hat gewonnen. "corr2" ist an dieser Stelle eine geeignete Funktion. Wie der aufmerksame Leser nun bemerkt hat ist man nun nicht mehr weit entfernt von der Lösung.







Letzte Schritte und anzeigen der Geschwindigkeit

Nun ist noch zu überprüfen, ob die herausgegebenen Zahlen Stimmen. Dazu kann man als letzten Schritt noch überprüfen ob es nur noch zwei oder drei Zahlen sind, die am Ende übrig geblieben sind. Als letzten Schritt muss man nun also noch irgendwie die Geschwindigkeit ins Livebild zaubern. Dazu kann man die sowieso verwendeten Templates zur Hilfe nehmen und diese Binärbilder in das RGB-Bild einbauen. Mit dem Befehl "uint8()" kann man sich hier eine eigene Matrix bauen für zum Beispiel den Rotanteil des Bildes. Hier wird das Graubild in die rote Matrix geschrieben:

RGB{k}(1000:999+length(speed(:,1)),1800:1799+length(speed(1,:)),1)=speedgrey;
Die Geschwindigkeit wurde erkannt und wird nun im Bild angezeigt























Siehe auch

Weblinks

Kein Blitzer-Bußgeld mit Verkehrszeichen Erkennung

BSD-Lizenzbedingung BSD-Lizenz

Copyright (c) 2014, Hochschule Hamm-Lippstadt, Dep. Lip. 1, Prof. Schneider
Hochschule Hamm-Lippstadt. Alle Rechte vorbehalten.



→ zurück zum Hauptartikel: Digitale Signal- und Bildverarbeitung SoSe2014