SamGIS - Segment Anything adattato ai sistemi geografici informativi (GIS)
Questo progetto, composto da frontend SPA 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. Di recente ho aggiunto la possibilità di partire da prompt testuali in linguaggio naturale.
La prima versione del backend era modificata da SAM Exporter semplificando l'utilizzo di segment anything al fine di migliorare il riconoscimento di poligoni in applicazioni web GIS.
Dalla versione 1.5.1 il backend integra modifiche mutuate da sam_onnx_full_export, in modo da supportare OnnxRuntime 1.17.x e versioni successive. Si noti che su MacOS l'esecuzione diretta da linea di comando soffre di memory leak, rendendo le operazioni di inferenza più lente di quanto sarebbe normale. Si consiglia quindi l'esecuzione del progetto dentro ad un container docker, a meno di voler fare attività di sviluppo e debug.
Questi sono i link alle risorse del progetto:
- una demo di HuggingFace Space pubblica
- una pagina demo sotto autenticazione
- la documentazione e le specifiche AWS lambda OpenAPI
Si tenga 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.
LISA e SamGIS
Ho anche aggiunto il supporto alla segmentazione d'immagine tramite prompt testuali in linguaggio naturale: qui i dettagli a proposito dell'integrazione di SamGIS con LISA.
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. La request sarà fatta usando questo payload in formato 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 (vecchia demo su AWS)
- L'utente interagisce con una WebMap (nel mio esempio è una mappa leaflet che utilizza i dati cartografici di OpenStreetMap).
- L'utente invia una POST ad un'API utilizzando
- le coordinate estreme della vista corrente della mappa
- lo zoom corrente della mappa
- 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)
- 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
- Il API Gateway inoltra la richiesta al backend serverless
- La API Lambda serverless elabora la richiesta:
- 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
- scarica le tiles georeferenziate per poi unirle e ritagliarle
- crea un'istanza del modello MobileSam se non esistente utilizzando OnnxRuntime come runtime
- prepara il embedding delle immagini e...
- ...avvia il processo di inferenza
- trasforma il array di maschere di oggetti riconosciuti in un'unica immagine binaria quindi vettorializza la maschera binaria riconosciuta:
- innanzitutto converte la maschera in un GeoDataframe GeoPandas utilizzando
rasterio.features.shapes
eGeoDataFrame.from_features
- quindi esporta il nuovo Geodataframe in un geojson utilizzando
GeoDataFrame.to_json
- innanzitutto converte la maschera in un GeoDataframe GeoPandas utilizzando
- la funzione proxy Cloudflare elabora la risposta e la inoltra al frontend
- 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
Per evitare abusi la webmap dedicata a questo progetto sul mio sito personale è sotto autenticazione (utilizzo auth0.com).
Architettura della demo basata su Fastapi
Questa variante del progetto funziona in maniera abbastanza simile a questa. Queste le differenze principali:
-
opencv-python
non è più fra le dipendenze di SamGIS dalla versione 1.5.1 - il backend salva e riutilizza gli embedding delle immagini per evitare sprechi di potenza di calcolo e velocizzare il processo di inferenza
- il frontend SPA (Single Page Application) è esposto direttamente dall'applicazione Fastapi
Frontend e backend quindi risiedono sullo stesso dominio. Non servirà più quindi un proxy (la demo su AWS usava una Page function di Cloudflare) per fare richieste ad API su un dominio diverso.
Inoltre, posso mantenere online questa demo usando HuggingFace gratuitamente, rimuovendo la necessità di us sistema di autenticazione.
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
- Configurazione non sempre facile (ho utilizzato Powertools for AWS Lambda (Python) per migliorare la configurazione del mio logger)
- Il modello serverless suggerito da AWS non sempre è la soluzione migliore
- Le istanze Arm graviton EC2 che eseguono AWS lambda sono notevolmente limitate (OnnxRuntime al momento non può essere eseguito su AWS lambda Arm e probabilmente non verrà mai eseguito).
Top comments (0)