MASK-RCNN zum Auffinden von Dächern aus Drohnenbildern


In einer weiß-weißen Stadt in einer weiß-weißen Straße gab es weiß-weiße Häuser ... Und wie schnell können Sie alle Dächer von Häusern auf diesem Foto finden?

Zunehmend kann man von den Plänen der Regierung hören, eine vollständige Bestandsaufnahme der Immobilien durchzuführen, um die Katasterdaten zu klären. Für die primäre Lösung dieses Problems kann eine einfache Methode angewendet werden, die auf der Berechnung der Dachfläche von Hauptgebäuden anhand von Luftbildern und dem weiteren Vergleich mit Katasterdaten basiert. Leider nimmt die manuelle Suche und Berechnung viel Zeit in Anspruch, und da ständig neue Häuser abgerissen und gebaut werden, muss die Berechnung immer wieder wiederholt werden. Es stellt sich sofort die Hypothese, dass dieser Prozess mithilfe von Algorithmen für maschinelles Lernen, insbesondere Computer Vision, automatisiert werden kann. In diesem Artikel werde ich darüber sprechen, wie wir bei NORBIT sind löste dieses Problem und welche Schwierigkeiten sie stießen.

Spoiler - wir haben es geschafft . Der entwickelte ML-Dienst basiert auf einem tiefen maschinellen Lernmodell, das auf Faltungs-Neuronalen Netzen basiert. Der Dienst akzeptiert Bilder von unbemannten Luftfahrzeugen als Eingabe und generiert am Ausgang eine GeoJSON-Datei mit dem Markup gefundener Kapitalbauobjekte unter Bezugnahme auf geografische Koordinaten.

Infolgedessen sieht es so aus:


Probleme


Beginnen wir mit den technischen Problemen, auf die wir gestoßen sind:

  • Es gibt einen signifikanten Unterschied zwischen Winter- und Sommerluftbildern (ein Modell, das nur für Sommerfotos ausgebildet wurde, kann im Winter keine Dächer finden).
  • , ;
  • , ( ), ( ) , ;
  • , , ( ). ;
  • (, ) .

Und Drohnen bringen manchmal diese Fotos:


Ich möchte auch die Probleme erwähnen, die hätten sein können, aber sie haben uns nicht betroffen:

  • Wir hatten keine Aufgabe, für eine begrenzte Zeit (zum Beispiel direkt zum Zeitpunkt des Fluges) Rückschlüsse zu ziehen, wodurch alle möglichen Leistungsprobleme sofort gelöst wurden.
  • Am Eingang für die Verarbeitung erhielten wir sofort hochauflösende Bilder in hoher Qualität (unter Verwendung von Objektiven mit einer Brennweite von 21 mm in einer Höhe von 250 m, was 5 cm / px entspricht) von unserem Kunden, der Firma Shakhty, die ihr Fachwissen bei der Geolokalisierung von Objekten auf Karten nutzen konnten Sie hatten auch die Möglichkeit, spezifische Anforderungen für zukünftige UAV-Flüge festzulegen, was letztendlich die Wahrscheinlichkeit sehr einzigartiger Kacheln, die nicht im Trainingssatz enthalten waren, erheblich verringerte.

Die erste Lösung für das Problem ist das Streichen mit der Begrenzungsbox 


Ein paar Worte darüber, mit welchen Tools wir die Lösung erstellt haben.

  • Anaconda ist ein praktisches Paketverwaltungssystem für Python und R.
  • Tensorflow ist eine Open Source-Softwarebibliothek für maschinelles Lernen, die von Google entwickelt wurde.
  • Keras ist ein Add-On für die Frameworks Deeplearning4j, TensorFlow und Theano.
  • OpenCV ist eine Bibliothek von Algorithmen für Computer Vision, Bildverarbeitung und allgemeine numerische Open-Source-Algorithmen.
  • Flask ist ein Framework zum Erstellen von Webanwendungen in der Programmiersprache Python.

Als Betriebssystem verwendet Ubuntu 18.04. Mit Treibern auf der GPU (NVIDIA) in Ubuntu ist alles in Ordnung, sodass die Aufgabe normalerweise mit einem Befehl gelöst wird:

> sudo apt install nvidia-cuda-toolkit

Fliesenvorbereitung


Die erste Aufgabe bestand darin, die Vorbeiflugbilder in Kacheln (2048 x 2048 Pixel) aufzuteilen. Sie könnten Ihr eigenes Skript schreiben, aber dann müssten Sie darüber nachdenken, die geografische Position jeder Kachel beizubehalten. Es war einfacher, eine vorgefertigte Lösung zu verwenden, beispielsweise GeoServer - eine Open-Source-Software, mit der Sie Geodaten auf dem Server veröffentlichen können. Darüber hinaus hat GeoServer ein weiteres Problem für uns gelöst - die bequeme Anzeige des Ergebnisses der automatischen Markierung auf der Karte. Dies kann lokal erfolgen, z. B. in qGIS. Für einen verteilten Befehl und eine Demonstration ist eine Webressource jedoch bequemer.

Um Kacheln durchzuführen, müssen Sie in den Einstellungen den erforderlichen Maßstab und die erforderliche Größe angeben.


Für Übersetzungen zwischen Koordinatensystemen haben wir die pyproj-Bibliothek verwendet:

from pyproj import Proj, transform

class Converter:
    P3857 = Proj(init='epsg:3857')
    P4326 = Proj(init='epsg:4326')
...
    def from_3857_to_GPS(self, point):
        x, y = point
        return transform(self.P3857, self.P4326, x, y)
    def from_GPS_to_3857(self, point):
        x, y = point
        return transform(self.P4326, self.P3857, x, y)
...

Infolgedessen war es möglich, leicht eine große Schicht aus allen Polygonen zu bilden und sie auf das Substrat zu legen. 


Um die GeoServer-Software zu installieren, müssen Sie die folgenden Schritte ausführen.
  1. Java 8.
  2. GeoServer.
  3. , , /usr/share/geoserver
  4.  

    echo «export GEOSERVER_HOME=/usr/share/geoserver» >> ~/.profile
  5. :

    sudo groupadd geoserver
  6. , , :

    sudo usermod -a -G geoserver <user_name>
  7. - :

    sudo chown -R :geoserver /usr/share/geoserver/
  8. :

    sudo chmod -R g+rwx /usr/share/geoserver/
  9. GeoServer 

    cd geoserver/bin && sh startup.sh

GeoServer ist nicht die einzige Anwendung, mit der wir unser Problem lösen können. Alternativ können Sie beispielsweise ArcGIS for Server in Betracht ziehen. Dieses Produkt ist jedoch proprietär, sodass wir es nicht verwendet haben.

Als nächstes musste jeder Ziegel alle sichtbaren Dächer finden. Der erste Ansatz zur Lösung des Problems bestand darin, die object_detection aus dem Tensorflow-Set models / research zu verwenden. Auf diese Weise können Klassen auf Bildern gefunden und mit einer rechteckigen Auswahl (Begrenzungsrahmen) lokalisiert werden. 

Markup für Trainingsdaten 


Für das Training des Modells benötigen Sie natürlich einen beschrifteten Datensatz. Durch einen glücklichen Zufall wurde in unseren Behältern nicht nur das Umkreisen, sondern auch der Datensatz für 50.000 Dächer aus der guten alten Zeit erhalten, als alle Datensätze für das Training noch überall öffentlich zugänglich waren.

Die genaue Größe der Trainingsprobe, die erforderlich ist, um eine akzeptable Modellgenauigkeit zu erzielen, ist im Voraus nur schwer vorherzusagen. Dies kann abhängig von der Qualität der Bilder, ihrem Grad an Unähnlichkeit und den Bedingungen, unter denen das Modell in der Produktion verwendet wird, variieren. Wir hatten Fälle, in denen 200 Stück ausreichten und manchmal auch 50.000 markierte Proben fehlten. Bei einem Mangel an markierten Bildern fügen wir normalerweise Erweiterungsmethoden hinzu: Drehungen, Spiegelreflexionen, Farbkorrekturen usw.

Jetzt sind viele Dienste verfügbar, mit denen Sie Bilder markieren können - sowohl mit Open Source-Code für die Installation auf Ihrem Computer / Server als auch mit Unternehmenslösungen, die die Arbeit externer Prüfer umfassen, z. B. Yandex.Tolok. In diesem Projekt haben wir den einfachsten VGG Image Annotator verwendet . Alternativ können Sie Coco-Annotator oder Label-Studio ausprobieren . Letzteres verwenden wir normalerweise zum Markieren von Text- und Audiodateien.


Für das Training zum Markup verschiedener Annotatoren müssen Sie normalerweise eine kleine Feldverschiebung durchführen, ein Beispiel für VGG .

Um die Fläche des Daches, die in die Fläche der rechteckigen Zuordnung gefallen ist, korrekt zu berechnen, müssen verschiedene Bedingungen beachtet werden:

  • / . :


  • , , :


Um das zweite Problem zu lösen, können Sie versuchen, ein separates Modell zu trainieren, das den richtigen Drehwinkel der Fliese zum Markieren bestimmt, aber alles ist etwas einfacher geworden. Die Menschen selbst bemühen sich, die Entropie zu reduzieren, und richten daher alle vom Menschen geschaffenen Strukturen in Bezug zueinander aus, insbesondere bei dichten Gebäuden. Wenn Sie von oben schauen, sind Zäune, Gehwege, Pflanzungen, Gewächshäuser und Lauben in einem bestimmten Bereich parallel oder senkrecht zu den Grenzen der Dächer. Es bleibt nur, alle klaren Linien zu finden und den häufigsten Neigungswinkel zur Vertikalen zu berechnen. Dafür hat OpenCV ein großartiges HoughLinesP-Tool. 

...

lines = cv2.HoughLinesP(edges, 1, np.pi/180, 50, minLineLength=minLineLength, maxLineGap=5)
if lines is not None:
    length = image.shape[0]
    angles = []
    for x1, y1, x2, y2 in lines[0]:
        angle = math.degrees(math.atan2(y2 — y1, x2 - x1))
        angles.append(angle)
    parts_angles.append(angles)
    median_angle = np.median(angles)
...

#     

for x in range(0, image.shape[0]-1, image.shape[0] // count_crops):
    for y in range(0, image.shape[1]-1, image.shape[1] // count_crops):
        get_line(image[x:x+image.shape[0]//count_crops, y:y+image.shape[1]//count_crops, :])
...

#      

np.median([a if a>0 else 90+a for a in np.array(parts_angles).flatten()])

Nachdem wir den Winkel gefunden haben, drehen wir das Bild mithilfe der affinen Transformation:


h, w = image.shape[:2]
image_center = (w/2, h/2)

if size is None:
    radians = math.radians(angle)
    sin = math.sin(radians)
    cos = math.cos(radians)
    size = (int((h * abs(sin)) + (w * abs(cos))), int((h * abs(cos)) + (w * abs(sin))))
    rotation_matrix = cv2.getRotationMatrix2D(image_center, angle, 1)
    rotation_matrix[0, 2] += ((size[0] / 2) — image_center[0])
    rotation_matrix[1, 2] += ((size[1] / 2) — image_center[1])
else:
    rotation_matrix = cv2.getRotationMatrix2D(image_center, angle, 1)

cv2.warpAffine(image, rotation_matrix, size)

Der vollständige Beispielcode ist hier . So sieht es aus:



Die Methode zum Drehen von Ziegeln und Markieren mit Rechtecken funktioniert schneller als das Markieren mit Masken. Fast alle Dächer werden gefunden. In der Produktion wird diese Methode jedoch aufgrund mehrerer Nachteile nur als Hilfsmethode verwendet:

  • Es gibt viele Überflüge, bei denen es eine große Anzahl nicht rechteckiger Dächer gibt. Aus diesem Grund ist zu viel Handarbeit erforderlich, um den Bereich zu verfeinern.
  • manchmal zu Hause mit unterschiedlichen Ausrichtungen auf derselben Fliese gefunden,
  • Manchmal gibt es viele falsche Linien auf den Kacheln, was letztendlich zu einer falschen Kurve führt. Es sieht aus wie das:



Die endgültige Lösung basiert auf Mask-RCNN


Der zweite Versuch bestand darin, die Dächer Pixel für Pixel nach Masken zu suchen und hervorzuheben und dann automatisch die Konturen der gefundenen Masken zu skizzieren und Vektorpolygone zu erstellen.  

Es gibt bereits genügend Materialien zu den Funktionsprinzipien, Typen und Aufgaben von Faltungsnetzwerken, einschließlich der auf Russisch, daher werden wir in diesem Artikel nicht darauf eingehen. Lassen Sie uns nur auf eine bestimmte Implementierung eingehen, Mask-RCNN - eine Architektur zum Lokalisieren und Hervorheben der Konturen von Objekten in Bildern. Es gibt andere hervorragende Lösungen mit ihren Vor- und Nachteilen, zum Beispiel UNet, aber es war möglich, mit Mask-RCNN eine bessere Qualität zu erzielen.

Im Verlauf seiner Entwicklung durchlief es mehrere Phasen. Die erste Version von R-CNN wurde 2014 entwickelt. Das Prinzip seiner Arbeit besteht darin, kleine Bereiche im Bild hervorzuheben, für die jeweils eine Schätzung der Wahrscheinlichkeit des Vorhandenseins eines Zielobjekts in diesem Bereich vorgenommen wird. R-CNN hat bei dieser Aufgabe hervorragende Arbeit geleistet, aber seine Geschwindigkeit ließ zu wünschen übrig. Die logische Entwicklung waren die Fast R-CNN- und Faster R-CNN-Netzwerke, die Verbesserungen beim Bildcrawl-Algorithmus erhielten, wodurch die Geschwindigkeit erheblich erhöht werden konnte. Am Ausgang zu Faster R-CNN erscheint eine Markierung mit einer rechteckigen Auswahl, die die Grenzen des Objekts angibt, was nicht immer ausreicht, um das Problem zu lösen. 

Maske R-CNN fügt außerdem eine pixelweise Maskenüberlagerung hinzu, um den genauen Umriss des Objekts zu erhalten.

Der Begrenzungsrahmen und die Masken sind am Ergebnis der Modelloperation deutlich zu erkennen (der Filter nach der minimalen Gebäudefläche ist eingeschaltet):


Herkömmlicherweise gibt es 4 Phasen im Betrieb dieses Netzwerks:

  • Standard für alle Faltungs-Neuronalen Netze, die Zuordnung von Merkmalen im Bild, wie Linien, Biegungen, kontrastierenden Grenzen und anderen;
  • Das Region Proposal Network (RPN) scannt kleine Fragmente des Bildes, die als Anker (Anker) bezeichnet werden, und ermittelt, ob dieser Anker für die Zielklasse spezifische Zeichen enthält (in unserem Fall das Dach).
  • Region of Interest Klassifizierung und Begrenzungsrahmen. In dieser Phase versucht das Netzwerk, basierend auf den Ergebnissen der vorherigen Phase, große rechteckige Bereiche auf dem Foto hervorzuheben, die vermutlich das Zielobjekt enthalten.
  • Segmentierungsmasken. In diesem Stadium wird die Maske des gewünschten Objekts aus dem rechteckigen Bereich erhalten, der durch Anwenden des Begrenzungsrahmens erhalten wird.

Darüber hinaus erwies sich das Netzwerk als sehr flexibel in der Konfiguration, und wir konnten es neu erstellen, um Bilder mit zusätzlichen Informationsebenen zu verarbeiten.

Die Verwendung ausschließlich von RGB-Bildern ermöglichte es uns nicht, die erforderliche Erkennungsgenauigkeit zu erreichen (das Modell verfehlte ganze Gebäude, es gab einen durchschnittlichen Fehler von 15% bei der Berechnung der Dachfläche), sodass wir dem Modell zusätzliche nützliche Daten lieferten, z. B. Höhenkarten, die durch Photogrammetrie erhalten wurden. 


Metriken zur Bewertung der Modellqualität


Bei der Bestimmung der Qualität von Modellen haben wir am häufigsten die IoU-Metrik (Intersection over Union) verwendet


Beispielcode für die Berechnung der IoU mithilfe der library.shapely-Bibliothek:

from shapely.geometry import Polygon

true_polygon = Polygon([(2, 2), (2, 6), (5, 6), (5, 2)])
predicted_polygon = Polygon([(3, 3), (3, 7), (6, 7), (6, 3)])
print(true_polygon.intersection(predicted_polygon).area / true_polygon.union(predicted_polygon).area)

>>> 0.3333333333333333

Die Verfolgung des Trainingsprozesses von Modellen wird bequem mit Tensorboard gesteuert, einem praktischen Tool zur Metriksteuerung, mit dem Sie Echtzeitdaten zur Modellqualität empfangen und mit anderen Modellen vergleichen können.


Tensorboard liefert Daten zu vielen verschiedenen Metriken. Die interessantesten für uns sind:

  • val_mrcnn_bbox_loss - zeigt an, wie gut das Modell Objekte lokalisiert (d. h. eine Grenzbox auferlegt);
  • val_mrcnn_mask_loss - zeigt an, wie gut das Modell Objekte segmentiert (d. h. eine Maske auferlegt).

Modellschulung und Validierung


Während des Trainings verwendeten wir die Standardpraxis, einen Datensatz zufällig in drei Teile zu unterteilen - Training, Validierung und Test. Während des Lernprozesses wird die Qualität des Modells anhand einer Validierungsstichprobe bewertet und besteht nach Abschluss den endgültigen Test für Testdaten, die im Lernprozess daraus geschlossen wurden. 

Wir haben unser erstes Training mit einer kleinen Anzahl von Sommeraufnahmen begonnen und als wir uns entschlossen zu prüfen, wie gut unser Modell im Winter sein wird, haben wir erwartungsgemäß ein enttäuschendes Ergebnis erhalten. Die Möglichkeit, verschiedene Modelle für verschiedene Jahreszeiten zu verwenden, ist natürlich ein hervorragender Ausweg aus der Situation, würde jedoch eine Reihe von Unannehmlichkeiten mit sich bringen. Daher haben wir uns entschlossen, das Modell universell zu gestalten. Durch Experimentieren mit verschiedenen Konfigurationen der Ebenen und Schließen des Gewichts einzelner Ebenen aufgrund von Gewichtsänderungen haben wir die optimale Strategie für das Training des Modells gefunden, indem abwechselnd Sommer- und Winterbilder auf die Eingabe angewendet wurden.

Erstellen eines Hintergrunddienstes zur Erkennung


Nachdem wir nun ein funktionierendes Modell haben, können wir einen Hintergrund-API-Dienst aus einem Erkennungsskript erstellen, das ein Bild als Eingabe akzeptiert und json mit Dachpolygonen generiert, die an der Ausgabe gefunden werden. Dies wirkt sich nicht direkt auf die Lösung des Problems aus, kann jedoch für jemanden nützlich sein. 

Ubuntu verwendet systemd, und ein Beispiel wird speziell für dieses System gegeben. Der Code des Dienstes selbst kann hier eingesehen werden . Benutzereinheiten befinden sich im Verzeichnis / etc / systemd / system, wo wir unsere Servicedatei erstellen. Bearbeiten Sie die Datei:

cd /etc/systemd/system

sudo touch my_srv.service




sudo vim my_srv.service

Die systemd-Einheit besteht aus drei Abschnitten:

  • [Einheit] - beschreibt die Reihenfolge und den Zustand des Starts (Sie können beispielsweise den Prozess anweisen, auf den Start eines bestimmten Dienstes zu warten und ihn erst dann selbst zu starten).
  • [Service] - beschreibt Startparameter;
  • [Installieren] - beschreibt das Verhalten des Dienstes beim Hinzufügen zum Start.

Infolgedessen sieht unsere Datei folgendermaßen aus:

[Unit]
Description=my_test_unit

[Service]
WorkingDirectory=/home/user/test_project
User=root
ExecStart=/home/user/test_project/venv/bin/python3 /home/user/test_project/script.py

[Install]
WantedBy=multi-user.target

Laden Sie nun die systemd-Konfiguration neu und führen Sie unseren Service aus:

sudo systemctl daemon-reload
sudo systemctl start my_srv.service

Dies ist ein einfaches Beispiel für einen Hintergrundprozess. Systemd unterstützt viele verschiedene Parameter, mit denen Sie das Verhalten des Dienstes flexibel konfigurieren können. Für unsere Aufgabe ist jedoch nichts Komplizierteres erforderlich.

Ergebnisse


Das Hauptergebnis des Projekts war die Fähigkeit, automatisch Inkonsistenzen in der tatsächlichen Entwicklung und Informationen in den Katasterdaten zu erkennen.

Als Ergebnis der Bewertung der Genauigkeit des Modells anhand der Testdaten wurden die folgenden Werte erhalten: Anzahl der gefundenen Dächer - 91%, Genauigkeit der Dachkonturpolygone - 94%.

Bei Sommer- und Winterflügen konnte eine akzeptable Qualität der Modelle erreicht werden, die Erkennungsqualität in den Bildern kann jedoch unmittelbar nach einem Schneefall abnehmen.

Jetzt wird auch das Sydney Opera House nicht aus den Augen unseres Modells entkommen. 


Wir planen, diesen Service mit einem geschulten Modell auf unseren Demostand zu stellen. Wenn Sie den Service auf Ihren eigenen Fotos ausprobieren möchten, senden Sie Ihre Bewerbung an ai@norbit.ru.

All Articles