Skip to content

SamGIS - Segment Anything adattato ai sistemi geografici informativi (GIS)

Questo progetto, composto da una parte frontend (samgis-fe) e da una parte backend (samgis-be), è un tentativo di effettuare riconoscimento d'immagine basato sul machine learning su immagini derivanti da dati geo-spaziali anche senza l'utilizzo di capacità computazionali particolari.

Il backend è basato su un adattamento di SAM Exporter semplificando l'utilizzo di segment anything al fine di migliorare il riconoscimento di poligoni in applicazioni web GIS.

Questi sono i link alle risorse del progetto:

Tieni presente che la demo dello spazio HuggingFace ha i suoi file frontend statici nella cartella /static.

Chiunque desideri una spiegazione dettagliata sul funzionamento di questo progetto oppure voglia testare la demo sotto autenticazione può contattarmi tramite linkedin.

SamGIS rimpiazza anche SurferDTM

SurferDTM è un tentativo di trovare stratovulcani all'interno di modelli digitali del terreno (DEM/DTM). Come nuova funzionalità, SamGIS ora può utilizzare anche DEM di input (come la prima immagine in questa galleria):

Si tenga conto che il provider dei dati "terrarium" codifica le immagini come RGB, quindi il backend le elabora per ottenere le quote di terreno effettive (come nella seconda immagine in questa galleria) utilizzando questa formula (dalla pagina del provider, mapzen/nextzen):

(red * 256) + green + (blue / 256) - 32768

I also added a custom elaboration step to create an intermediate RGB image composed by channels:

  • ROSSO - immagine DEM normalizzata
  • VERDE - immagine 2d normalizzata composta dalla risultante di
    • immagine DEM normalizzata
    • slope
    • curvatura
  • BLU - curvatura

Quest'immagine RGB infine sarà sottoposta a Segment Anything per l'inferenza.

Apri questo elemento di dettaglio per visualizzare il json usato per creare le immagini intermedie DEM e RGB.
json
{
   "bbox": {
         "ne": {"lat": 46.203706648934954, "lng": 9.401906739170105},
         "sw": {"lat": 46.12464369105346, "lng": 9.231103669101747}},
   "prompt": [
         {"id": 238, "type": "point", "data": {"lat": 46.158760519552146, "lng": 9.306795638666486}, "label": 1},
         {"id": 250, "type": "point", "data": {"lat": 46.152693546080975, "lng": 9.289288652508679}, "label": 0},
         {"id": 264, "type": "point", "data": {"lat": 46.16613515509541, "lng": 9.319840059725284}, "label": 0},
         {"id": 272, "type": "point", "data": {"lat": 46.161377438862836, "lng": 9.288087192674299}, "label": 0},
         {"id": 285, "type": "point", "data": {"lat": 46.174103408003454, "lng": 9.308340372739261}, "label": 0},
         {"id": 293, "type": "point", "data": {"lat": 46.17005996124035, "lng": 9.298042145587583}, "label": 0}
   ],
   "zoom": 13,
   "source_type": "nextzen.terrarium"
}

Architettura del progetto

  1. L'utente interagisce con una WebMap (nel mio esempio è una mappa leaflet che utilizza i dati cartografici di OpenStreetMap).

  2. L'utente invia una POST ad un'API utilizzando

    1. le coordinate estreme della vista corrente della mappa
    2. lo zoom corrente della mappa
    3. un prompt contenente
    • un marker "inclusivo", marcando quindi la posizione come inclusa (a couple of float - latitude and longitude)
    • un marker "escludente", marcando quindi la posizione come esclusa (a couple of float - latitude and longitude)
    • a "include" rectangle (a couple of marker positions - north-east and south-west)
  3. a causa del vincoli posti dai CORS è difficile inviare direttamente richieste a risorse remote su domini diversi da quello di origine: per evitare questo problema ho preparato una semplice funzione proxy su Cloudflare (questo sito funziona con le Cloudflare Pages) che inoltra la richiesta dell'utente all'API remota

  4. Il API Gateway inoltra la richiesta al backend serverless

  5. La API Lambda serverless elabora la richiesta:

    1. analizza la richiesta e in particolare traduce il prompt con le coordinate di latitudine/longitudine in uno di coordinate x/y mappate sull'origine dell'immagine
    2. scarica le tiles georeferenziate per poi unirle e ritagliarle
    3. crea un'istanza del modello MobileSam se non esistente utilizzando OnnxRuntime come runtime
    4. prepara il embedding delle immagini e...
    5. ...avvia il processo di inferenza
    6. trasforma il array di maschere di oggetti riconosciuti in un'unica immagine binaria quindi vettorializza la maschera binaria riconosciuta:
      1. innanzitutto converte la maschera in un GeoDataframe GeoPandas utilizzando rasterio.features.shapes e GeoDataFrame.from_features
      2. quindi esporta il nuovo Geodataframe in un geojson utilizzando GeoDataFrame.to_json
  6. la funzione proxy Cloudflare elabora la risposta e la inoltra al frontend

  7. il frontend estrae dalla risposta il geojson che sarà poi caricato all'interno della WebMap. Sono anche aggiunte alcune informazioni come la durata non relativistica della risposta

    datetime-diff

Per evitare abusi la webmap dedicata a questo progetto sul mio sito personale è sotto autenticazione (utilizzo auth0.com).

AWS lambda, una soluzione serverless: alcuni pro

  • Può funzionare anche con immagini docker, molto utile nel caso di progetti complessi
  • Integrazione abbastanza semplice con altri servizi AWS e sistemi di autenticazione di terze parti
  • Servizio a consumo

...e alcuni svantaggi

Apprezzi il mio sito? Pagami un caffè
Referenze disponibili su richiesta. Autorizzo il trattamento dei miei dati personali in conformità al D. Lgs. n. 196/2003, art. 13, allo scopo di farmi proposte lavorative.