Start- und Stopplinienerkennung

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen

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

  1. Zeichnen Sie die Kamerasicht eines Rundkurses auf.
  2. Lesen Sie diesen als Endlosschleife in Matlab ein.
  3. Identifizieren Sie während der virtuellen Fahrt Start- und Stopplinien mit Matlab.
  4. Vermeiden Sie Fehler ("false-positives").
  5. 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