Start- und Stopplinienerkennung: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
(→Video) |
||
(7 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt) | |||
Zeile 3: | Zeile 3: | ||
== Motivation == | == Motivation == | ||
Eine Aufgabe beim Carolo Cup ist der "Rundkurs mit Hindernissen". Hierbei ist eine Startlinie zu überfahren und an eienr Stopplinie zu halten. | |||
== Ziel == | == Ziel == | ||
Die Start- und Stoppline soll robust erkannt und unterschieden werden. | |||
== Aufgabe == | == Aufgabe == | ||
# Zeichnen Sie die Kamerasicht eines Rundkurses auf. | |||
# Lesen Sie diesen als Endlosschleife in Matlab ein. | |||
# Identifizieren Sie während der virtuellen Fahrt Start- und Stopplinien mit Matlab. | |||
# Vermeiden Sie Fehler ("false-positives"). | |||
# Optimieren Sie die Rechenzeit Ihres Algorithmus. | |||
<!-- | |||
== Siehe auch == | |||
--> | |||
== | == Lösung von Jan Kifmann == | ||
Vorab wurde ein Rundkurs in beide Richtungen aufgezeichnet und das Video auf die wesentlichen Teile gekürzt. Zur Lösung der Aufgabe wurde ein Algorithmus entwickelt, der eine horizontale Linie erkennt und anhand der Breite der Linie beurteilt, ob es eine Stoplinie ist oder nicht. Der Algorithmus gibt die Position der Linie als Pixelabstand vom oberen Bildrand (topPx) aus. Für den Fall, dass keine Linie erkannt wurde, wird topPx=0 ausgegeben, damit ist bei schräg nach unten geneigter Kamera der am weitesten Entfernte Punkt markiert. Außerdem wird ein Parameter (isStopLine) ausgegeben, der Start- von Stoplinie unterscheidet. Im Folgenden wird die Verarbeitung eines Bildes aus dem Video beschrieben. | |||
=== Vorverarbeitung des Bildes === | |||
Das Bild wird in Simulink zu Graustufen und dann in ein Binärbild gewandelt, anschließend wird mittels einer Maske die Fahrzeuggeometrie ausgeblendet. Aus diesem Bild wird ein Ausschnitt ausgewählt, um die durch die anschließende Kantenerkennung (Canny) zu verarbeitenden Pixel und damit die Rechenzeit zu reduzieren. Das vorverarbeitete Bild wird an eine Matlab-Funktion übergeben, in der die Start/Stoplinienerkennung durchgeführt wird. | |||
[[Datei:Stoplib.png]] | |||
=== Beschreibung des Algorithmus === | |||
Im Folgenden wird im Suchbereich eine Linie gesucht und die gefundenen Punkte werden gespeichert. | |||
<source lang="matlab"> | |||
% Initialisiere Speicher für Stoplinie | |||
stopline = zeros(count,3); | |||
counter = 1; | |||
% Suche von links nach rechts im Suchbereich | |||
for x=leftOffset:increment:leftOffset+increment*(count-1) | |||
lineBegin = 0; | |||
lineEnd = 0; | |||
% Suche 1. und 2. weißes Pixel von unten nach oben | |||
for y=h:-1:maxLineHeight | |||
if frame(y,x) == 1 && lineBegin == 0 | |||
lineBegin = y; | |||
end | |||
if lineBegin > 0 && frame(y,x) == 1 && lineEnd == 0 && lineBegin-y > 1 | |||
lineEnd = y; | |||
end | |||
end | |||
% Speichere Pixel-Positionen | |||
stopline(counter,:) = [x,lineBegin,lineEnd]; | |||
counter = counter+1; | |||
end | |||
</source> | |||
Hier wird geprüft, ob die gefundenen Pixel eine Quer-Linie ergeben: | |||
<source lang="matlab"> | |||
% Lege Gerade duch die vordere Kante der Pixel | |||
[p,S] = polyfit(stopline(:,1),stopline(:,2),1); | |||
% Falls die Gerade ausreichend horizontal ist und die Punkte | |||
% gut auf eine Gerade passen, wurde eine Stoplinie gefunden. | |||
if abs(p(1)) < horzLimit && S.normr < linearLimit | |||
</source> | |||
Falls die Bedingung zutrifft, wird getestet, ob es sich um eine Start- oder Stoplinie handelt: | |||
<source lang="matlab"> | |||
% Stoplinie gefunden | |||
% Berechne die Pixel vom oberen Bildrand bis zur Mitte der Stoplinie | |||
topPx = round(polyval(p, double(midPx))) + topOffset; | |||
% Teste ob Start- oder Stoplinie | |||
% Laufe an beiden Querlinien nach links | |||
linewidth = [0;0]; | |||
for linenr=2:3 | |||
x = stopline(1,1); | |||
y = stopline(1,linenr); | |||
nowhite = 0; | |||
leftincrement = 2; | |||
% Laufe solange nach links, bis eine große schwarze Lücke kommt | |||
for left=x-1:-leftincrement:1 | |||
if frame( y, left ) | |||
% Weiß gefunden, weiterlaufen | |||
nowhite = 0; | |||
overlayFrame(y,left,2) = 0; | |||
overlayFrame(y,left,[1;3]) = 1; | |||
x = left; | |||
continue; | |||
else | |||
% Kein Weiß gefunden | |||
ytemp = 0; | |||
% Erhöhe y-Suchebreich stufenweise, je länger | |||
% kein Weiß mehr gefunden wurde | |||
ySearchRange = 1; | |||
if nowhite > 0 | |||
ySearchRange = 2; | |||
elseif nowhite > 5 | |||
ySearchRange = 3; | |||
end | |||
% Suche an aktuelle x-Position vertikal | |||
for yt=y-ySearchRange:1:y+ySearchRange | |||
if frame( yt, left) | |||
ytemp = yt; | |||
break; | |||
end | |||
end | |||
if ytemp > 0 | |||
% Nach Vergrößerung des Y-Suchbereichs wurde Weiß | |||
% gefunden | |||
y = ytemp; | |||
overlayFrame(y,left,2) = 0; | |||
overlayFrame(y,left,[1;3]) = 1; | |||
x = left; | |||
else | |||
% Kein weiß gefunden, erhöhe Zähler | |||
nowhite = nowhite + 1; | |||
end | |||
if nowhite > 10 | |||
% Zu lange kein Weiß gefunden, Linie zu Ende | |||
x = left + 10*leftincrement; | |||
overlayFrame(y,x,2:3) = 0; | |||
overlayFrame(y,x,1) = 1; | |||
break; | |||
end | |||
end | |||
end | |||
% Speichere Linienbreite | |||
linewidth(linenr-1) = stopline(count, 1) - x; | |||
end | |||
</source> | |||
Abschließend wird die Linie je nach Typ farbig im Originalbild eingefärbt: | |||
<source lang="matlab"> | |||
% Wenn die Linie unter 300 Pixel breit ist, ist es eine Stoplinie | |||
maximumLineWidth = max(linewidth); | |||
isStopLine = maximumLineWidth < 300; | |||
% Stelle die Stoplinie dar | |||
if isStopLine | |||
overlayFrame(topPx-topOffset-1:topPx-topOffset+1,leftOffset:(leftOffset + increment * count),1) = 1; | |||
overlayFrame(topPx-topOffset-1:topPx-topOffset+1,leftOffset:(leftOffset + increment * count),2:3) = 0; | |||
else | |||
overlayFrame(topPx-topOffset-1:topPx-topOffset+1,leftOffset:(leftOffset + increment * count),3) = 1; | |||
overlayFrame(topPx-topOffset-1:topPx-topOffset+1,leftOffset:(leftOffset + increment * count),1:2) = 0.2; | |||
end | |||
</source> | |||
Falls keine Linie gefunden wurde, wird der topPx-Wert auf 0 gesetzt: | |||
<source lang="matlab"> | |||
else | |||
% Keine Stoplinie gefunden | |||
% Wert wird auf 0 gesetzt, da dies bei nach unten geneigter Kamera | |||
% dem am weitesten entfernten Punkt entspricht. | |||
topPx = 0; | |||
isStopLine = false; | |||
maximumLineWidth = 0; | |||
end | |||
</source> | |||
=== Auswertung der Kennwerte === | |||
* topPx: Pixel vom oberen Bildrand bis zum Beginn der Stoplinie | |||
* isStopLine: Boolscher Wert, der Start- und Stoplinie unterscheidet | |||
* linewidth: Breite der gefundenen Linie | |||
* p1: Steigung der Geradengleichung | |||
* Snormr: Abweichung der Pixel-Linie von der Geradengleichung | |||
Wenn p1 und Snormr nahe an Null sind, wurde eine horizontale Linie gefunden. In dem folgenden Plot der Kennwerte sind die 4 Stoplinien und die abschließende Startlinie deutlich zu erkennen, ebenso wie die Annäherung des Autos an die Linien bei steigendem topPx: | |||
[[Datei:Scope_Stopline.png]] | |||
<! -- === Video === | |||
Das Video des Funktionsnachweises findet sich auf [http://www.youtube.com/watch?v=kt2deGYYJbo&feature=share&list=PLoyKJifb3ROe_sKfT3y3paswSyiQ8xqm1&index=6 YouTube]. | |||
--> | |||
=== Selbstreflexion === | |||
Der Algorithmus wurde auf dem vorhandenen Rundkurs in beiden Richtungen getestet und hat ohne Fehler bestanden. Ein Video zum Beleg findet sich im SVN unter dem Namen "StartStopLinienerkennung.mp4". Die gewählte Schnittstelle "topPx" eignet sich hervorragend, um mittels externer Koordinatentransformation in eine Entfernung umgewandelt zu werden. So muss die Koordinatentransformation nicht auf das gesamte Bild, sondern nur auf genau ein Pixel angewendet werden. | |||
== Weblinks == | == Weblinks == | ||
[http://youtu.be/JL7NSKzF-ik Carolo Cup 2012 - Spatzenhirn (Uni Ulm)] | |||
---- | ---- | ||
→ zurück zum Hauptartikel: [[DSB_SoSe2014| Digitale Signal- und Bildverarbeitung SoSe2014]] | → zurück zum Hauptartikel: [[DSB_SoSe2014| Digitale Signal- und Bildverarbeitung SoSe2014]] |
Aktuelle Version vom 16. Dezember 2014, 09:50 Uhr
Autor: Jan Kifmann
Betreuer: Prof. Schneider
Motivation
Eine Aufgabe beim Carolo Cup ist der "Rundkurs mit Hindernissen". Hierbei ist eine Startlinie zu überfahren und an eienr Stopplinie zu halten.
Ziel
Die Start- und Stoppline soll robust erkannt und unterschieden werden.
Aufgabe
- Zeichnen Sie die Kamerasicht eines Rundkurses auf.
- Lesen Sie diesen als Endlosschleife in Matlab ein.
- Identifizieren Sie während der virtuellen Fahrt Start- und Stopplinien mit Matlab.
- Vermeiden Sie Fehler ("false-positives").
- Optimieren Sie die Rechenzeit Ihres Algorithmus.
Lösung von Jan Kifmann
Vorab wurde ein Rundkurs in beide Richtungen aufgezeichnet und das Video auf die wesentlichen Teile gekürzt. Zur Lösung der Aufgabe wurde ein Algorithmus entwickelt, der eine horizontale Linie erkennt und anhand der Breite der Linie beurteilt, ob es eine Stoplinie ist oder nicht. Der Algorithmus gibt die Position der Linie als Pixelabstand vom oberen Bildrand (topPx) aus. Für den Fall, dass keine Linie erkannt wurde, wird topPx=0 ausgegeben, damit ist bei schräg nach unten geneigter Kamera der am weitesten Entfernte Punkt markiert. Außerdem wird ein Parameter (isStopLine) ausgegeben, der Start- von Stoplinie unterscheidet. Im Folgenden wird die Verarbeitung eines Bildes aus dem Video beschrieben.
Vorverarbeitung des Bildes
Das Bild wird in Simulink zu Graustufen und dann in ein Binärbild gewandelt, anschließend wird mittels einer Maske die Fahrzeuggeometrie ausgeblendet. Aus diesem Bild wird ein Ausschnitt ausgewählt, um die durch die anschließende Kantenerkennung (Canny) zu verarbeitenden Pixel und damit die Rechenzeit zu reduzieren. Das vorverarbeitete Bild wird an eine Matlab-Funktion übergeben, in der die Start/Stoplinienerkennung durchgeführt wird.
Beschreibung des Algorithmus
Im Folgenden wird im Suchbereich eine Linie gesucht und die gefundenen Punkte werden gespeichert.
% Initialisiere Speicher für Stoplinie
stopline = zeros(count,3);
counter = 1;
% Suche von links nach rechts im Suchbereich
for x=leftOffset:increment:leftOffset+increment*(count-1)
lineBegin = 0;
lineEnd = 0;
% Suche 1. und 2. weißes Pixel von unten nach oben
for y=h:-1:maxLineHeight
if frame(y,x) == 1 && lineBegin == 0
lineBegin = y;
end
if lineBegin > 0 && frame(y,x) == 1 && lineEnd == 0 && lineBegin-y > 1
lineEnd = y;
end
end
% Speichere Pixel-Positionen
stopline(counter,:) = [x,lineBegin,lineEnd];
counter = counter+1;
end
Hier wird geprüft, ob die gefundenen Pixel eine Quer-Linie ergeben:
% Lege Gerade duch die vordere Kante der Pixel
[p,S] = polyfit(stopline(:,1),stopline(:,2),1);
% Falls die Gerade ausreichend horizontal ist und die Punkte
% gut auf eine Gerade passen, wurde eine Stoplinie gefunden.
if abs(p(1)) < horzLimit && S.normr < linearLimit
Falls die Bedingung zutrifft, wird getestet, ob es sich um eine Start- oder Stoplinie handelt:
% Stoplinie gefunden
% Berechne die Pixel vom oberen Bildrand bis zur Mitte der Stoplinie
topPx = round(polyval(p, double(midPx))) + topOffset;
% Teste ob Start- oder Stoplinie
% Laufe an beiden Querlinien nach links
linewidth = [0;0];
for linenr=2:3
x = stopline(1,1);
y = stopline(1,linenr);
nowhite = 0;
leftincrement = 2;
% Laufe solange nach links, bis eine große schwarze Lücke kommt
for left=x-1:-leftincrement:1
if frame( y, left )
% Weiß gefunden, weiterlaufen
nowhite = 0;
overlayFrame(y,left,2) = 0;
overlayFrame(y,left,[1;3]) = 1;
x = left;
continue;
else
% Kein Weiß gefunden
ytemp = 0;
% Erhöhe y-Suchebreich stufenweise, je länger
% kein Weiß mehr gefunden wurde
ySearchRange = 1;
if nowhite > 0
ySearchRange = 2;
elseif nowhite > 5
ySearchRange = 3;
end
% Suche an aktuelle x-Position vertikal
for yt=y-ySearchRange:1:y+ySearchRange
if frame( yt, left)
ytemp = yt;
break;
end
end
if ytemp > 0
% Nach Vergrößerung des Y-Suchbereichs wurde Weiß
% gefunden
y = ytemp;
overlayFrame(y,left,2) = 0;
overlayFrame(y,left,[1;3]) = 1;
x = left;
else
% Kein weiß gefunden, erhöhe Zähler
nowhite = nowhite + 1;
end
if nowhite > 10
% Zu lange kein Weiß gefunden, Linie zu Ende
x = left + 10*leftincrement;
overlayFrame(y,x,2:3) = 0;
overlayFrame(y,x,1) = 1;
break;
end
end
end
% Speichere Linienbreite
linewidth(linenr-1) = stopline(count, 1) - x;
end
Abschließend wird die Linie je nach Typ farbig im Originalbild eingefärbt:
% Wenn die Linie unter 300 Pixel breit ist, ist es eine Stoplinie
maximumLineWidth = max(linewidth);
isStopLine = maximumLineWidth < 300;
% Stelle die Stoplinie dar
if isStopLine
overlayFrame(topPx-topOffset-1:topPx-topOffset+1,leftOffset:(leftOffset + increment * count),1) = 1;
overlayFrame(topPx-topOffset-1:topPx-topOffset+1,leftOffset:(leftOffset + increment * count),2:3) = 0;
else
overlayFrame(topPx-topOffset-1:topPx-topOffset+1,leftOffset:(leftOffset + increment * count),3) = 1;
overlayFrame(topPx-topOffset-1:topPx-topOffset+1,leftOffset:(leftOffset + increment * count),1:2) = 0.2;
end
Falls keine Linie gefunden wurde, wird der topPx-Wert auf 0 gesetzt:
else
% Keine Stoplinie gefunden
% Wert wird auf 0 gesetzt, da dies bei nach unten geneigter Kamera
% dem am weitesten entfernten Punkt entspricht.
topPx = 0;
isStopLine = false;
maximumLineWidth = 0;
end
Auswertung der Kennwerte
- topPx: Pixel vom oberen Bildrand bis zum Beginn der Stoplinie
- isStopLine: Boolscher Wert, der Start- und Stoplinie unterscheidet
- linewidth: Breite der gefundenen Linie
- p1: Steigung der Geradengleichung
- Snormr: Abweichung der Pixel-Linie von der Geradengleichung
Wenn p1 und Snormr nahe an Null sind, wurde eine horizontale Linie gefunden. In dem folgenden Plot der Kennwerte sind die 4 Stoplinien und die abschließende Startlinie deutlich zu erkennen, ebenso wie die Annäherung des Autos an die Linien bei steigendem topPx: <! -- === Video === Das Video des Funktionsnachweises findet sich auf YouTube. -->
Selbstreflexion
Der Algorithmus wurde auf dem vorhandenen Rundkurs in beiden Richtungen getestet und hat ohne Fehler bestanden. Ein Video zum Beleg findet sich im SVN unter dem Namen "StartStopLinienerkennung.mp4". Die gewählte Schnittstelle "topPx" eignet sich hervorragend, um mittels externer Koordinatentransformation in eine Entfernung umgewandelt zu werden. So muss die Koordinatentransformation nicht auf das gesamte Bild, sondern nur auf genau ein Pixel angewendet werden.
Weblinks
Carolo Cup 2012 - Spatzenhirn (Uni Ulm)
→ zurück zum Hauptartikel: Digitale Signal- und Bildverarbeitung SoSe2014