Straßenerkennung durch semantische Segmentierung

In der vorherigen Serie habe ich ein Experiment mit der autonomen Bewegung meines Heimtanks durchgeführt . Die Straße wurde unter Verwendung eines Farbfilters erkannt, und die resultierende Maske ging zum Eingang eines speziell trainierten neuronalen Klassifikator-Netzwerks, das sich für rechts, links oder gerade entschied.

Der Schwachpunkt war das Erkennen der Fahrbahn selbst aufgrund der Variabilität der Farbtöne, weshalb das entscheidende neuronale Netzwerk zu seltsamen Ergebnissen führte. In den Kommentaren zu diesem Artikel wurde empfohlen, auf die semantische Segmentierung zu achten. Das Thema erwies sich als vielversprechend und die Verwendung segmentierter neuronaler Netze brachte seine Vor- und Nachteile mit sich, wo es ohne sie wäre.

Aber das Wichtigste zuerst und ein bisschen Ausrüstung.

Segmentierung


Bei der Segmentierung werden einige Teile eines Bildes hervorgehoben. Die einfachste und offensichtlichste Art der Segmentierung ist die Farbe. Mit dieser Methode ist es jedoch unmöglich zu verstehen, was und wo auf dem Bild dargestellt ist.

Hier ist ein guter Artikel , der primitive Ansätze beschreibt.

Semantische Segmentierung


Semantische Segmentierung - Aufteilen eines Bildes in Objekte mit Bestimmung der Typen dieser Objekte.

Es sieht ungefähr so ​​aus:



Die Ergebnisse sind sehr beeindruckend. Mal sehen, was es wert ist, in das wirkliche Leben übersetzt zu werden.

U-net


Das bekannteste neuronale Netz, ursprünglich für die Medizin entwickelt.
Primärquelle

Die Leute erkannten schnell, dass der Ansatz für alle Gelegenheiten verwendet werden kann.

Es gibt viele Artikel im Internet, wie man Daten aufbereitet und U-Net-Netzwerke trainiert:


Ich fand jedoch kein fertiges U-Net-Netzwerk, das ich schnell nutzen und experimentieren konnte.

E-Net


Ein jüngeres und weniger bekanntes Netzwerk. Entwickelt nur zum Erkennen von Stadtstraßen.


Daten


Die beliebtesten Datensätze für die Straßensegmentierung (sie lehrten ursprünglich E-Net):


Auf denselben Datensätzen wird U-net jetzt trainiert.

Implementierungsauswahl


Die Flut neuer Informationen zur Segmentierung war ziemlich überwältigend. Instinktiv wollte ich etwas Einfacheres verstehen. Ich hatte nicht das Gefühl, die Architektur von Netzwerken zu verstehen und Zeit mit Lernen zu verbringen. In dem Artikel von PyImageSearch gab es jedoch ein vorgefertigtes und geschultes neuronales Netzwerk in einem mit OpenCV-DNN kompatiblen Format.

Also wurde die Wahl zum geringsten Widerstand getroffen.

Die Verwendung ist sehr einfach:
(Am besorgniserregendsten ist, dass das Netzwerk auf 1024 x 512 Bilder trainiert ist - dies ist zum einen mehr als die Kamera bei Raspberry ausgibt, und zum anderen ist die erforderliche Leistung für die Verarbeitung dieser Datenmenge etwas verwirrend. Infolgedessen ist das Hauptproblem genau das.)

Wir lesen das neuronale Netzwerk aus den Dateien (in einem das Modell selbst, in den anderen Klassennamen in den dritten Farben).

def load_segment_model(): try: classes = None with open(PiConf.SEGMENT_CLASSES) as f: classes = f.read().strip().split("\n") colors = None with open(PiConf.SEGMENT_COLORS) as f: colors= f.read().strip().split("\n") colors = [np.array(c.split(",")).astype("int") for c in colors] colors = np.array(colors, dtype="uint8") print("[INFO] loading model...") net = cv2.dnn.readNet(PiConf.SEGMENT_MODEL) return net, classes, colors except Exception as e: logging.exception("Cannot load segment model") return None, None, None 

Wir segmentieren das Bild und markieren gleichzeitig Segmente über dem Originalbild
(In meinem Fall sind alle Klassen außer der Straße unsichtbar).

 def segment_image(image_path, seg_net, seg_classes, seg_colors): image0 = cv2.imread(image_path) image = cv2.resize(image0, (1024, 512),interpolation=cv2.INTER_NEAREST) blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (1024, 512), 0, swapRB=True, crop=False) seg_net.setInput(blob) start = time.time() output = seg_net.forward() end = time.time() print("[INFO] inference took {:.4f} seconds".format(end - start)) (numClasses, height, width) = output.shape[1:4] classMap = np.argmax(output[0], axis=0) mask = seg_colors[classMap] mask = cv2.resize(mask, (image0.shape[1], image0.shape[0]),interpolation=cv2.INTER_NEAREST) classMap = cv2.resize(classMap, (image0.shape[1], image0.shape[0]), interpolation=cv2.INTER_NEAREST) gmask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY) gmask = cv2.resize(gmask, (128, 64), interpolation=cv2.INTER_NEAREST) gmask = gmask[0:64,32:96] output = ((0.6 * image0) + (0.4 * mask)).astype("uint8") return output, gmask 

Überprüfen Sie


Wir machen fertige Bilder aus dem Tank und setzen ein segmentiertes neuronales Netzwerk darauf.

1



Nur die linke Seite des Bürgersteigs wird als teuer erkannt.

Wir komprimieren das Bild und nehmen daraus eine Mittengröße von 64x64:
(Diese Größe wird vom neuronalen Netzwerk erwartet, das beschließt, die Richtung zu ändern.)



Das neuronale Netzwerk der Richtung (in der Tat - der Klassifikator) befiehlt, nach links zu nehmen. Nicht sehr korrekt, aber erträglich.

2



Eine ähnliche Situation ist wiederum die untere rechte Ecke verloren (es gibt auch Asphalt nass).
Der größte Teil der Straße wird jedoch noch erkannt.



Der Klassifikator bietet an, geradeaus zu fahren.

3

Die Situation, als sich der Roboter mitten auf dem Bürgersteig befand.



Die Straße ist fast perfekt erkannt.



Der Klassifikator befiehlt, nach rechts zu nehmen (um beim nächsten Mal den Straßenrand zu finden).

Anwendung


Nachdem ich ein wenig über die Tank-Firmware gezaubert hatte, ersetzte ich den Farbstraßendetektor durch ein segmentierendes neuronales Netzwerk.

Als all dies auf dem Raspberry Pi gestartet wurde, war das erste, was herauskam, eine deprimierende Leistung.
Es dauert 6 Sekunden, um ein Bild zu segmentieren - während dieser Zeit schafft es der Panzer, mit einem kräftigen Trab durch alle Kurven zu rutschen.

In realen Tests geschah dies - trotz der nahezu perfekten Erkennung des Bürgersteigs und der korrekten Befehle des neuronalen Kontrollnetzwerks - während der Zeit, in der das Bild verarbeitet wurde, gelang es dem Panzer, zur Seite zu gehen.



Im Allgemeinen können Bilder dieser Größe auf Raspberry nicht verdaut werden.
Es scheint, dass Sie noch ein spezielles neuronales Netzwerk trainieren müssen.

Referenzen


Source: https://habr.com/ru/post/de452088/


All Articles