MASK-RCNN pour trouver des toits Ă  partir d'images de drones


Dans une ville blanc-blanc sur une rue blanc-blanc il y avait des maisons blanches-blanches ... Et Ă  quelle vitesse pouvez-vous trouver tous les toits des maisons sur cette photo?

De plus en plus, on peut entendre parler des plans du gouvernement de procéder à un inventaire complet des biens immobiliers afin de clarifier les données cadastrales. Pour la solution principale à ce problème, une méthode simple peut être appliquée basée sur le calcul de la surface du toit des bâtiments d'immobilisations à partir de photographies aériennes et une comparaison plus approfondie avec les données cadastrales. Malheureusement, la recherche et le calcul manuels prennent beaucoup de temps, et comme les nouvelles maisons sont démolies et construites en continu, le calcul doit être répété encore et encore. L'hypothèse se pose immédiatement que ce processus peut être automatisé à l'aide d'algorithmes d'apprentissage automatique, en particulier, la vision par ordinateur. Dans cet article, je parlerai de notre situation à NORBIT résolu ce problème et quelles difficultés ils ont rencontrées.

Spoiler - nous l'avons fait . Le service ML développé est basé sur un modèle d'apprentissage machine profond basé sur des réseaux de neurones à convolution. Le service accepte en entrée des images de véhicules aériens sans pilote; en sortie, il génère un fichier GeoJSON avec le balisage des objets de construction en capital trouvés en référence aux coordonnées géographiques.

En conséquence, cela ressemble à ceci:


Problèmes


Commençons par les problèmes techniques que nous avons rencontrés:

  • il existe une diffĂ©rence significative entre les photographies aĂ©riennes d'hiver et d'Ă©tĂ© (un modèle formĂ© uniquement aux photographies d'Ă©tĂ© est totalement incapable de trouver des toits en hiver);
  • , ;
  • , ( ), ( ) , ;
  • , , ( ). ;
  • (, ) .

Et les drones apportent parfois ces photos:


Je voudrais également noter les problèmes qui auraient pu être, mais ils ne nous concernaient pas:

  • nous n'avons eu aucune tâche pour effectuer l'infĂ©rence pendant un temps limitĂ© (par exemple, directement au moment du vol), ce qui a immĂ©diatement rĂ©solu tous les problèmes de performances possibles;
  • Ă  l'entrĂ©e pour le traitement, nous avons immĂ©diatement reçu des images haute rĂ©solution de haute qualitĂ© (en utilisant des objectifs avec une focale de 21 mm Ă  une hauteur de 250 m, soit 5 cm / px) de notre client, la sociĂ©tĂ© Shakhty, pourrait utiliser leur expertise dans la gĂ©olocalisation des objets sur les cartes, et ils ont Ă©galement eu l'occasion d'Ă©tablir un ensemble spĂ©cifique d'exigences pour les futurs vols d'UAV, ce qui a finalement considĂ©rablement rĂ©duit la probabilitĂ© de carreaux très uniques qui n'Ă©taient pas dans l'ensemble de formation;

La première solution au problème, l'AVC Ă  l'aide de la boĂ®te Boundary 


Quelques mots sur les outils que nous avons utilisés pour créer la solution.

  • Anaconda est un système de gestion de paquets pratique pour Python et R.
  • Tensorflow est une bibliothèque de logiciels d'apprentissage automatique open source dĂ©veloppĂ©e par Google.
  • Keras est un module complĂ©mentaire pour les frameworks Deeplearning4j, TensorFlow et Theano.
  • OpenCV est une bibliothèque d'algorithmes pour la vision par ordinateur, le traitement d'image et les algorithmes numĂ©riques open source Ă  usage gĂ©nĂ©ral.
  • Flask est un framework pour crĂ©er des applications web dans le langage de programmation Python.

Comme le système d'exploitation a utilisé Ubuntu 18.04. Avec les pilotes sur le GPU (NVIDIA) dans Ubuntu, tout est en ordre, donc la tâche est généralement résolue avec une seule commande:

> sudo apt install nvidia-cuda-toolkit

Préparation des carreaux


La première tâche à laquelle nous avons été confrontés a été de diviser les images de survol en tuiles (2048x2048 px). Vous pouvez écrire votre propre script, mais vous devrez alors penser à maintenir l'emplacement géographique de chaque tuile. Il était plus facile d'utiliser une solution prête à l'emploi, par exemple, GeoServer - c'est un logiciel open source qui vous permet de publier des géodonnées sur le serveur. De plus, GeoServer a résolu un autre problème pour nous: l'affichage pratique du résultat du marquage automatique sur la carte. Cela peut être fait localement, par exemple, dans qGIS, mais pour une commande et une démonstration distribuées, une ressource Web est plus pratique.

Pour effectuer le carrelage, vous devez spécifier l'échelle et la taille requises dans les paramètres.


Pour les traductions entre les systèmes de coordonnées, nous avons utilisé la bibliothèque pyproj:

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)
...

En consĂ©quence, il a Ă©tĂ© possible de former facilement une grande couche Ă  partir de tous les polygones et de la dĂ©poser sur le substrat. 


Pour installer le logiciel GeoServer, vous devez effectuer les Ă©tapes suivantes.
  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 n'est pas la seule application qui nous permet de résoudre notre problème. Par exemple, vous pouvez envisager ArcGIS for Server, mais ce produit est propriétaire, nous ne l'avons donc pas utilisé.

Ensuite, chaque tuile devait trouver tous les toits visibles. La première approche pour rĂ©soudre le problème a Ă©tĂ© d'utiliser la dĂ©tection d' objet de l'ensemble modèles / recherche Tensorflow. De cette façon, les classes sur les images peuvent ĂŞtre trouvĂ©es et localisĂ©es avec une sĂ©lection rectangulaire (encadrĂ©). 

Balisage des donnĂ©es de formation 


Évidemment, pour former le modèle, vous avez besoin d'un ensemble de données étiqueté. Par une heureuse coïncidence, en plus de tourner autour, dans nos bacs, l'ensemble de données pour 50 000 toits a été préservé du bon vieux temps, lorsque tous les ensembles de données pour la formation étaient toujours dans le domaine public partout.

La taille exacte de l'échantillon d'apprentissage nécessaire pour obtenir une précision acceptable du modèle est assez difficile à prévoir à l'avance. Il peut varier en fonction de la qualité des images, de leur degré de dissemblance entre elles et des conditions d'utilisation du modèle en production. Nous avons eu des cas où 200 pièces étaient suffisantes, et parfois 50 000 échantillons marqués manquaient également. En cas de pénurie d'images balisées, nous ajoutons généralement des méthodes d'augmentation: virages, reflets miroir, dégradés de couleurs, etc.

Il existe maintenant de nombreux services qui vous permettent de baliser des images - à la fois avec du code open source pour l'installation sur votre ordinateur / serveur, et des solutions d'entreprise, y compris le travail d'évaluateurs externes, par exemple Yandex.Toloka. Dans ce projet, nous avons utilisé l' annotateur d'image VGG le plus simple . Alternativement, vous pouvez essayer coco-annotator ou label-studio . Nous utilisons généralement ce dernier pour baliser le texte et les fichiers audio.


Pour la formation sur le balisage de divers annotateurs, vous devez généralement effectuer un petit décalage de champs, un exemple pour VGG .

Afin de calculer correctement la surface de la toiture tombée dans la zone d'allocation rectangulaire, il est nécessaire de respecter plusieurs conditions:

  • / . :


  • , , :


Pour rĂ©soudre le deuxième problème, vous pouvez essayer de former un modèle sĂ©parĂ© qui dĂ©terminerait l'angle de rotation correct de la tuile pour le marquage, mais tout s'est avĂ©rĂ© un peu plus facile. Les gens eux-mĂŞmes s'efforcent de rĂ©duire l'entropie, ils alignent donc toutes les structures artificielles les unes par rapport aux autres, en particulier avec les bâtiments denses. Si vous regardez d'en haut, alors dans une zone localisĂ©e, les clĂ´tures, les allĂ©es, les plantations, les serres, les tonnelles seront parallèles ou perpendiculaires aux limites des toits. Il ne reste plus qu'Ă  trouver toutes les lignes nettes et Ă  calculer l'angle d'inclinaison le plus courant par rapport Ă  la verticale. Pour cela, OpenCV dispose d'un excellent outil HoughLinesP. 

...

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()])

Après avoir trouvé l'angle, nous faisons pivoter l'image en utilisant la transformation affine:


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)

L'exemple de code complet est ici . Voici à quoi ça ressemble:



La méthode de retournement des tuiles et de marquage avec des rectangles fonctionne plus rapidement que le marquage avec des masques, presque tous les toits sont trouvés, mais en production, cette méthode n'est utilisée que comme auxiliaire en raison de plusieurs inconvénients:

  • il y a beaucoup de survols oĂą il y a un grand nombre de toits non rectangulaires, Ă  cause de cela il y a trop de travail manuel pour affiner la zone,
  • parfois trouvĂ© Ă  la maison avec des orientations diffĂ©rentes sur la mĂŞme tuile,
  • parfois il y a beaucoup de fausses lignes sur les tuiles, ce qui conduit finalement Ă  un mauvais virage. Cela ressemble Ă  ceci:



La solution finale basée sur Mask-RCNN


La deuxième tentative a consistĂ© Ă  rechercher et Ă  mettre en Ă©vidence les toits par masques pixel par pixel, puis Ă  dĂ©finir automatiquement les contours des masques trouvĂ©s et Ă  crĂ©er des polygones vectoriels.  

Il existe déjà suffisamment de documents sur les principes de fonctionnement, les types et les tâches des réseaux de neurones convolutifs, y compris ceux en russe, nous ne les aborderons donc pas dans cet article. Arrêtons-nous sur une seule implémentation spécifique, Mask-RCNN - une architecture pour localiser et mettre en évidence les contours des objets dans les images. Il existe d'autres excellentes solutions avec leurs avantages et leurs inconvénients, par exemple UNet, mais il était possible d'obtenir une meilleure qualité sur Mask-RCNN.

Au cours de son dĂ©veloppement, il est passĂ© par plusieurs Ă©tapes. La première version de R-CNN a Ă©tĂ© dĂ©veloppĂ©e en 2014. Le principe de son travail est de mettre en Ă©vidence de petites zones de l'image, pour chacune desquelles est estimĂ©e la probabilitĂ© de prĂ©sence d'un objet cible dans cette zone. R-CNN a fait un excellent travail avec la tâche, mais sa vitesse laissait beaucoup Ă  dĂ©sirer. Le dĂ©veloppement logique a Ă©tĂ© les rĂ©seaux Fast R-CNN et Faster R-CNN, qui ont reçu des amĂ©liorations dans l'algorithme d'exploration d'image, ce qui a permis d'augmenter considĂ©rablement la vitesse. Ă€ la sortie de Faster R-CNN, un marquage apparaĂ®t avec une sĂ©lection rectangulaire indiquant les limites de l'objet, ce qui n'est pas toujours suffisant pour rĂ©soudre le problème. 

Le masque R-CNN ajoute Ă©galement une superposition de masque pixel par pixel pour obtenir le contour exact de l'objet.

Le cadre de délimitation et les masques sont clairement visibles sur le résultat de l'opération du modèle (le filtre par la surface minimale du bâtiment est activé):


Classiquement, le fonctionnement de ce réseau se déroule en 4 étapes:

  • standard pour tous les rĂ©seaux de neurones convolutifs, l'allocation de caractĂ©ristiques dans l'image, telles que les lignes, les virages, les frontières contrastĂ©es et autres;
  • Le rĂ©seau de propositions de rĂ©gion (RPN) scanne de petits fragments de l'image, appelĂ©s ancres (ancres) et dĂ©termine si cette ancre contient des signes spĂ©cifiques Ă  la classe cible (dans notre cas, le toit);
  • Classification des rĂ©gions d'intĂ©rĂŞt et cadre de dĂ©limitation. Ă€ ce stade, le rĂ©seau, sur la base des rĂ©sultats de l'Ă©tape prĂ©cĂ©dente, tente de mettre en Ă©vidence de grandes zones rectangulaires dans la photographie, contenant vraisemblablement l'objet cible;
  • Masques de segmentation. A ce stade, le masque de l'objet souhaitĂ© est obtenu Ă  partir de la zone rectangulaire obtenue en appliquant la boĂ®te frontière.

De plus, la configuration du réseau s'est avérée très flexible et nous avons pu le reconstruire pour traiter des images avec des couches d'informations supplémentaires.

L'utilisation d'images exclusivement RVB ne nous a pas permis d'obtenir la prĂ©cision de reconnaissance nĂ©cessaire (le modèle a ratĂ© des bâtiments entiers, il y avait une erreur moyenne de 15% dans le calcul de la surface du toit), nous avons donc fourni au modèle des donnĂ©es utiles supplĂ©mentaires, par exemple, des cartes de hauteur obtenues par photogrammĂ©trie. 


Mesures utilisées pour évaluer la qualité du modèle


Pour déterminer la qualité des modèles, nous avons le plus souvent utilisé la métrique Intersection over Union (IoU)


Exemple de code pour calculer l'IoU à l'aide de la bibliothèque geometry.shapely:

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

Le suivi du processus de formation des modèles est facilement contrôlé à l'aide de Tensorboard, un outil de contrôle métrique pratique qui vous permet de recevoir des données en temps réel sur la qualité du modèle et de les comparer avec d'autres modèles.


Tensorboard fournit des données sur de nombreuses mesures différentes. Les plus intéressants pour nous sont:

  • val_mrcnn_bbox_loss - montre Ă  quel point le modèle localise les objets (c.-Ă -d. impose une boĂ®te frontière);
  • val_mrcnn_mask_loss - montre Ă  quel point le modèle segmente les objets (c'est-Ă -dire impose un masque).

Formation et validation des modèles


Lors de la formation, nous avons utilisĂ© la pratique standard de diviser au hasard un ensemble de donnĂ©es en 3 parties - formation, validation et test. Dans le processus d'apprentissage, la qualitĂ© du modèle est Ă©valuĂ©e sur un Ă©chantillon de validation et, Ă  la fin, rĂ©ussit le test final sur les donnĂ©es de test qui en ont Ă©tĂ© fermĂ©es dans le processus d'apprentissage. 

Nous avons fait nos premiers démarrages d'entraînement sur une petite série de clichés d'été et, décidant de vérifier la qualité de notre modèle en hiver, nous nous attendions à un résultat décevant. L'option d'utiliser différents modèles pour différentes saisons, bien sûr, est un excellent moyen de sortir de la situation, mais cela entraînerait un certain nombre d'inconvénients, nous avons donc décidé d'essayer de rendre le modèle universel. En expérimentant différentes configurations des couches et en fermant également le poids des couches individuelles des changements de poids, nous avons trouvé la stratégie optimale pour entraîner le modèle en appliquant alternativement des images d'été et d'hiver à l'entrée.

Création d'un service d'arrière-plan pour la reconnaissance


Maintenant que nous avons un modèle fonctionnel, nous pouvons crĂ©er un service d'API en arrière-plan Ă  partir d'un script de reconnaissance qui prend une image en entrĂ©e et gĂ©nère json avec des polygones de toit trouvĂ©s en sortie. Cela n'affecte pas directement la solution du problème, mais cela peut ĂŞtre utile Ă  quelqu'un. 

Ubuntu utilise systemd, et un exemple sera donné spécifiquement pour ce système. Le code du service lui-même peut être consulté ici . Les unités utilisateur sont situées dans le répertoire / etc / systemd / system, où nous allons créer notre fichier de service. Modifiez le fichier:

cd /etc/systemd/system

sudo touch my_srv.service




sudo vim my_srv.service

L'unité systemd se compose de trois sections:

  • [UnitĂ©] - dĂ©crit l'ordre et la condition du dĂ©marrage (par exemple, vous pouvez dire au processus d'attendre le dĂ©marrage d'un certain service et de le dĂ©marrer ensuite vous-mĂŞme);
  • [Service] - dĂ©crit les paramètres de dĂ©marrage;
  • [Installer] - dĂ©crit le comportement du service lors de son ajout au dĂ©marrage.

En conséquence, notre fichier ressemblera à ceci:

[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

Rechargez maintenant la configuration systemd et exécutez notre service:

sudo systemctl daemon-reload
sudo systemctl start my_srv.service

Ceci est un exemple simple d'un processus d'arrière-plan, systemd prend en charge de nombreux paramètres différents qui vous permettent de configurer de manière flexible le comportement du service, mais rien de plus compliqué n'est requis pour notre tâche.

résultats


Le principal résultat du projet a été la capacité de détecter automatiquement les incohérences dans le développement réel et les informations contenues dans les données cadastrales.

À la suite de l'évaluation de la précision du modèle sur les données de test, les valeurs suivantes ont été obtenues: le nombre de toits trouvés - 91%, la précision des polygones de contour de toit - 94%.

Il était possible d'obtenir une qualité acceptable des modèles lors des vols d'été et d'hiver, mais la qualité de reconnaissance peut diminuer dans les images immédiatement après une chute de neige.

Maintenant, mĂŞme l'opĂ©ra de Sydney ne se dĂ©robera pas aux yeux de notre modèle. 


Nous prévoyons de mettre ce service avec un modèle formé sur notre demostand. Si vous êtes intéressé à essayer le service sur vos propres photos, envoyez vos candidatures à ai@norbit.ru.

All Articles