Lignes fixes

Résumé

Les lignes terrestres sont une expérience qui vous permet d'explorer des images satellite Google Earth d'un simple geste. En combinant le machine learning, l'optimisation des données et la puissance d'une carte graphique, le test peut s'exécuter efficacement dans le navigateur Web de votre téléphone, sans avoir besoin de serveurs backend. Voici un aperçu de notre processus de développement et des différentes approches que nous avons essayées qui nous ont mené au résultat final.

https://g.co/LandLines

Lorsque l'équipe Data Arts m'a demandé d'explorer un ensemble de données d'images de la Terre, j'étais très enthousiaste. Les images étaient belles, révélant toutes sortes de structures et de textures, naturelles et humaines, et j'ai été curieuse de savoir comment relier cet ensemble de données. J'ai effectué plusieurs tests initiaux sur la similarité des images, ainsi que les différentes façons de les filtrer et de les organiser.

Mise en page de similarité t-sne
Mise en page avec similarité t-sne, 50 Mo haute résolution

En tant que groupe, nous avons continué à revenir aux belles lignes dominantes des images. Ces lignes étaient faciles à repérer : autoroutes, rivières, lisières de montagnes et parcelles de terre. Nous avons donc conçu quelques projets pour les explorer. En tant qu'artiste, j'ai été inspiré par les belles choses que vous pouvez faire avec les collections de lignes (voir par exemple le travail de Cassandra C Jones avec la foudre), et j'étais enthousiaste à l'idée de travailler avec cet ensemble de données.

Détection de ligne

L'un des premiers défis était de détecter les lignes dans les images. Il est facile d'enlever un morceau de papier dessiné, de le jeter sur une impression de l'une de ces photos et de tracer les lignes que votre œil voit, mais en général, les algorithmes de vision par ordinateur permettant de trouver des lignes ont tendance à ne pas fonctionner correctement sur des images très variées.

J'ai développé une version précédente de la recherche en dessinant un algorithme sur un projet avec des projets locaux et pour cela, nous avons annoté manuellement les lignes à rechercher. C'était amusant de dessiner sur des œuvres d'art, mais fastidieux lorsque l'on passe de dizaines d'images à des milliers. je voulais essayer d'automatiser le processus de recherche de lignes.

Avec ces images aériennes, j'ai essayé d'utiliser des algorithmes de détection de lignes traditionnels, tels que l'algorithme de détection d'arêtes canny d'openCv, mais j'ai constaté qu'ils donnaient soit des segments de ligne très discontinus, soit, si le seuil était trop détendu, des tonnes de fausses lignes. De plus, les seuils permettant d'obtenir de bons résultats étaient différents selon les ensembles d'images, et je voulais un algorithme pour trouver un ensemble cohérent de bonnes lignes sans supervision.

J'ai expérimenté divers algorithmes de détection de ligne, y compris des algorithmes récents comme gPb (PDF) qui, bien que produisaient des résultats incroyables, nécessitaient des minutes pour s'exécuter par image. Finalement, j'ai opté pour la détection de bordure de forêt structurée, un algorithme qui intègre openCV.

Une fois que j'avais une bonne "image de ligne", j'avais encore le problème d'obtenir les lignes et d'identifier les lignes individuelles les unes des autres : comment convertir ces données matricielles en données vectorielles ? Souvent, lorsque j'étudie des problèmes de vision par ordinateur, j'étudie imageJ, un environnement de traitement d'images Open Source basé sur Java, utilisé par les scientifiques et les chercheurs, et qui dispose d'un écosystème sain de plug-ins. J'ai trouvé un plug-in appelé crête détection, qui permet de transformer une image d'intensité en un ensemble de segments de ligne. (Notez également que ce code de détection et d'étiquetage de périphérie de Matlab est également utile.)

Image avec segments de ligne détectés
Image avec des segments de ligne détectés

Sans serveur

Je voulais également voir s'il était possible de créer une application de visualisation des données essentiellement sans serveur, où le travail de mise en correspondance et de connexion se fait côté client. Je travaille généralement dans openFrameworks, un framework C++ qui permet de coder des créations. En plus du projet de node, je n'ai pas beaucoup de code côté serveur. Je voulais savoir s'il était possible d'effectuer tout le calcul côté client et de n'utiliser le serveur que pour diffuser des données JSON et des données d'image.

Pour l'application de dessin, la mise en correspondance est une opération très lourde. Lorsque vous tracez une ligne, nous devons trouver la correspondance la plus proche parmi plus de dizaines de milliers de segments de ligne. Pour calculer la distance d'un dessin à un autre, nous utilisons une métrique de l'outil de reconnaissance de gestes en dollars, qui implique lui-même de nombreux calculs de distance. Dans le passé, j'ai utilisé l'exécution de threads et d'autres astuces, mais pour qu'elle fonctionne en temps réel sur un appareil client (y compris les téléphones mobiles), j'avais besoin de mieux. J'ai examiné les arbres de métriques pour trouver les voisins les plus proches/les plus proches et je me suis penché sur les arbres de points de vue (implémentation JavaScript). L'arborescence de points de vue se base essentiellement sur un ensemble de données et une métrique de distance. Lorsque vous ajoutez un nouvel élément de données, il vous fournit assez rapidement une liste des valeurs les plus proches. La première fois que j'ai vu ce travail sur un téléphone portable, j'étais tout de suite stupéfait. L'un des grands avantages de cette implémentation d'arborescence de point de vue est que vous pouvez enregistrer l'arbre après son calcul et réaliser des économies sur les coûts de calcul.

Résultats les plus proches Résultats tirés
Exemples de résultats issus de l'arborescence de points de vue. Les entrées dessinées se trouvent à droite et les résultats les plus proches se trouvent à gauche.

Un autre défi pour le faire fonctionner sans serveur est de charger les données sur un appareil mobile : pour le dessin, les données des arbres et des segments de ligne dépassaient 12 Mo, et les images étaient assez volumineuses. Nous voulions que l'expérience soit rapide et réactive, et l'objectif était d'essayer de réduire la taille du téléchargement. Notre solution consistait à charger progressivement les données. Dans l'application de dessin, nous divisons l'ensemble de données de l'arborescence de points de vue en cinq éléments. Lorsque l'application charge, elle ne charge que le premier fragment, puis, toutes les 10 secondes, elle charge un autre bloc de données en arrière-plan. Ainsi, l'application s'améliore de manière générale dès la première minute d'utilisation. Nous avons également travaillé dur pour mettre en cache les images dans l'application de déplacement, de sorte que de nouvelles images soient chargées en arrière-plan lorsque vous les faites glisser.

Enfin, une chose que j'ai trouvée plus difficile que prévu était de créer un pré-chargeur pour les deux applications. Il serait donc compréhensible de définir le délai initial pour le chargement des données. J'ai utilisé le rappel de progression pour les requêtes ajax et, du côté de pixi.js, des images vérifiées qui étaient chargées de manière asynchrone et qui s'en servaient pour générer le message de préchargement.

Ligne connectée

Pour le déplacement, je voulais créer une ligne infinie à partir des lignes détectées dans la détection des bords. La première étape consistait à filtrer les lignes de l'algorithme de détection de ligne et à identifier les longues lignes qui commencent sur une arête et se terminent sur l'un des trois autres.

Les lignes appropriées pour se connecter sont indiquées en rouge. Les lignes appropriées pour se connecter sont indiquées en rouge.
Les lignes indiquant une bonne connexion sont indiquées en rouge

Une fois que j'ai eu un ensemble de longues lignes (ou, pour utiliser un terme plus précis, les polylignes, un ensemble de points reliés) pour les relier, j'ai converti ces lignes en un ensemble de changements d'angle. En général, lorsqu'on pense à une polyligne, on l'imagine comme un ensemble de points: le point a est relié au point b, lequel est relié au point c. Au lieu de cela, vous pouvez considérer la ligne comme un ensemble de changements d'angle: avancez et faites pivoter une certaine mesure, avancez et faites pivoter un peu. Pour visualiser cela, pensez aux cinteuses de circonférence, qui prennent un morceau de fil et effectuent des rotations lors de son extrusion. La forme du dessin vient de tourner.

Si vous considérez que la ligne change d'angle et non de point, il devient plus facile de combiner les lignes en une ligne plus grande avec moins de discontinuités. Au lieu d'assembler des points, vous ajoutez essentiellement des changements d'angle relatif. Pour ajouter une ligne, vous devez prendre l'angle actuel de la ligne principale et y ajouter les modifications relatives de la ligne à ajouter.

Par ailleurs, j'ai utilisé cette technique de conversion d'une ligne en un ensemble de changements d'angle à des fins d'exploitation artistique. Vous pouvez créer des dessins "dérouler" de la même manière qu'un fil peut être ondulé et déroulé. Quelques exemples : un, deux, trois

Ce calcul d'angle nous permet de diriger la ligne lorsque vous faites glisser votre doigt. Nous calculons l'écart de l'angle principal par rapport à l'endroit souhaité et nous recherchons une image qui nous aidera le plus à diriger la ligne dans la bonne direction. Il s'agit de réfléchir relativement.

Enfin, je veux juste dire que c'était un projet vraiment amusant à réaliser. C'est passionnant en tant qu'artiste de se voir demander d'utiliser un jeu de données aussi charmant que ces images et je suis honoré que l'équipe Data Arts m'ait contacté. J’espère que vous avez un bon plaisir à l’expérimenter !