Cosa ho imparato da un progetto fallito

Come addestrare un modello a riconoscere oggetti personalizzati legarlo con la realtà aumentata in unity e fallire miseramente

Introduzione #

Per il mio esame di Computer Vision dovevo fare un progetto in una tecnologia che sfruttasse la Computer Vision. Poteva trattarsi di un modello di Machine Learning (da ora in avanti ML), riconoscimento di volti…

Tuttavia una delle mie passioni più grandi, sin dal 2014, è sempre stata la realtà aumentata. Siccome i modelli di ML spopolano al giorno d’oggi, basti pensare a Deepseek a GPT e chi più ne ha più ne metta, mi sono venute in mente diverse idee.

L’idea #

Ciò che però ha conquistato la mia scimmia, è stata un’idea tanto semplice quanto complessa.

A Roma abbiamo un grande problema: gli autobus e i mezzi pubblici. Noi li odiamo, loro odiano noi, quindi la cosa è reciproca, ma c’è una cosa insopportabile che non ho riscontrato in quasi nessuna altra città: le fermate dell’autobus (o paline) sono senza le tabelle degli orari previsti e delle partenze da capolinea.

Questa grave mancanza fa sì che certamente una persona si affida alle app online, ma fattuariamente le app online mostrano solo il prossimo o i prossimi orari previsti o dei bus in arrivo.

Senza contare che ogni volta bisogna geolocalizzarsi o inserire il codice della fermata a mano, o i nomi delle fermate. Non tutte le app infatti supportano l’inserimento del numero identificativo della fermata.

Quanto sarebbe bella un’app che la apri, inquadri la fermata, lui ci pensa qualche secondo e ti dice in tempo reale che fine ha fatto il tuo autobus, se arriva o meno, prossime partenze da capolinea e… insomma tutte le informazioni del quale potresti avere bisogno ma proiettate direttamente sulla fermata?

E da qui inizia l’odissea.

Un inizio difficile #

La nostra storia comincia con Unity: questo strumento permette infatti, stando alle informazioni che si trovano online di creare esperienze per la XR, la cosiddetta Extended Reality che comprende Realtà Aumentata e Realtà Virtuale, in maniera abbastanza semplice.

Inoltre è gratuito.

Perché non approfittarne?

Bè perché…

NON ESISTE un altro modo per fare esperienze AR con un motore grafico!

O meglio, esistono altri motori grafici, che però non hanno implementato tutte le funzionalità come Unity. Va da sé che per creare esperienze di questo genere si ha bisogno di Unity.

Non l’ho mai usato, non conosco i principi del game design e della programmazione dei videogiochi in 3D, ma voglio dire, se Godot provato il giorno prima è così semplice, immagino sarà come bere un bicchier d’acqua.

La curva di apprendimento è altissima: non consiglierei mai Unity ad uno sviluppatore alle prime armi, ma neanche ad un programmatore con molta esperienza. Non si capisce dove sono le cose, devi aggiungere componenti intermedi per eseguire qualsiasi azione, insieme a Unity ti viene installato Visual Studio (non Code) che è pesantissimo e scomodo, ogni volta che cambi qualcosa all’interno del progetto (assets) deve ricaricare tutto e ci mette del tempo, ed infine utilizza C# che non è un grossissimo problema venendo da Python e Java, ma se stai lavorando in velocità lo è eccome se non conosci il linguaggio.

Unity funziona a scene, e in ogni scena ci sono gli oggetti. Gli oggetti possono avere delle proprietà, altri oggetti a loro volta (es. Canvas, una tela, può avere al suo interno un’immagine o anche un bottone).

Workflow iniziale #

L’idea alla base è molto semplice: un’app che preso il flusso della fotocamera, riconosce che si tratta della fermata del bus, estrae il testo, fa una ricerca online della fermata e restituisce tutte le informazioni necessarie.

Scompattiamola in più problemi e soluzioni:

  1. Prendere il flusso della fotocamera: qui Unity ci viene in aiuto, basta inserire un oggetto nella scena del gioco già preimpostato.

  2. Riconoscere la fermata del bus: qui mi viene da dire che o usiamo delle immagini di riferimento e la libreria opencv in modo tale da riuscire a estrapolare l’immagine, oppure usiamo un modello di Machine Learning opportunamente addestrato.

  3. Estrarre il testo: idem, usiamo un altro modello di ML

  4. Cercare e restituire le informazioni: serve un endpoint intermedio o una chiamata a OpenData. Niente che non possa essere gestito.

Iniziamo? #

Già iniziare a settare la camera già fatta e impostata è un’impresa. Inizialmente avrei dovuto usare OpenXR e AndroidXR salvo poi scoprire che si tratta di un ecosistema non rilasciato. Ho speso la parte iniziale per configurare il progetto e cercare di far funzionare quelle cose, salvo poi scoprire che non servivano. Dopo un po’ di peripezie e ricerche online riesco a capire come fare: basta aggiungere AR Session e AR Camera Manager.

Riconoscere la fermata del bus #

E come? Abbiamo detto prima di usare OpenCV la libreria ricca di strumenti per computer vision. Gli unici due risultati che trovo sono questo tool a 50$ e quest’altra libreria qui emgucv che però la prima costa 50$ e la seconda non si trovano esempi.

Devo passare ad un modello di Machine Learning.

Mi imbatto in questo articolo e questa guida che spiegano come creare un riconoscitore di oggetti personalizzato. Proprio ciò che serve a me!

È il momento di cercare le immagini delle fermate dell’autobus di Roma: online se ne trovano a bizzeffe per fortuna quindi faccio presto. Ma come faccio a dire al modello di ML che quella è una fermata del bus? Semplice, bisogna riquadrare gli oggetti nelle immagini, usando tool come cvat.ai.

La fase di labeling, questo è il nome tecnico, dura 2 ore, ma devo rifare il lavoro 3 volte.

La prima perché l’ho fatto in maniera non consistente inquadrando un po’ la fermata e un po’ il contenuto della fermata, la seconda perché non ho pulito il dataset da eventuali immagini a bassa risoluzione e un’altra cosa fondamentale: YOLO supporta, solo rettangoli, e non forme personalizzate.

Di conseguenza, siccome non sapevo di questa cosa e ho pensato di selezionare tutta l’area del bus, devo fare di nuovo labelling delle immagini.

La terza è quella giusta.

Modello ML fatto! Finalmente! #

Dopo qualche giorno riesco finalmente ad addestrare un modello in 300 epoch, con una precisione altissima. Sono molto soddisfatto ma c’è un problema: Unity supporta solo file onnx, non pt, il formato predefinito di pytorch. Decido di convertire il modello e noto che gli output sono sbagliati: che fare?

Dopo moltissime ricerche vengo a scoprire che bisogna applicare dei “controlayer”: ma io non ho la più pallidea idea di cosa applicare.

Così armato di pazienza e motori di ricerca cerco e cerco e cero, finchè non mi imbatto in questo link dagli sviluppatori. La manna dal cielo: basta copiare questo, modificarlo leggermente e… FUNZIONA TUTTO!

Il risultato è un disastro: lo script è stato sviluppato per la versione 1.4.0 di Sentis, ma ora siamo alla 2.1, e nonostante ci siano delle guide per modernizzare il codice, cerco di scrivere il codice aggiornato diverse volte, fallendo miseramente.

Mi viene in mente allora una cosa semplice tanto banale: passare a una versione inferiore di Sentis, così che quell’esempio possa girare senza problemi. Per mia fortuna funziona proprio così!

Alla ricerca della fermata nascosta #

Armato di forbici dalla punta arrotondata, capisco che ora il problema è fargli riconoscere la fermata.

Ecco cosa provo:

  • riaddestrare facendo labelling nuovamente per la quarta volta, questa volta cercando di fargli riconoscere fermata e numero
  • addestrare 4 modelli diversi su tempi diversi
  • integrare un altro modello che riconosca le cifre

Inutile dirvi che nessuna di queste funziona: il testo è troppo piccolo nelle foto.

Su unity inoltre, poiché c’è bisogno di quel formato onnx, non riesco ad usare nessun altro modello e tesseract non si può usare perché non c’è una guida su come usarlo su sentis.

Decido di fare una cosa: delegare a un sistema esterno il compito di tradurre il testo dall’immagine, mentre all’app lasciare il compito di riconoscere la fermata.

OCR: riconoscimento di testo #

Anche questa cosa si rivela un buco nell’acqua: il sistema esterno è pronto, metto su una piccola app in Flask in Python con la libreria tesseract per l’OCR, ma l’app non riesce a rilevare cifre su immagini piccole.

Se invece gli dò tutta l’immagine l’OCR avviene, ma non molto correttamente e i numeri non li rivela mai.

The end? #

Ecco cosa ho imparato grazie a questa esperienza:

  1. prima di iniziare o proporre un progetto valutarne attentamente la fattibilità

  2. quando si gestisce un esempio, sarebbe bene aggiornarlo all’ultima versione man mano che le versioni avanzano

  3. YOLOv8 è ottimo per riconoscere oggetti personalizzati

  4. se non hai una GPU potente, linux, e un bel disco capiente, scordati di fare qualunque cosa con il machine learning. L’alternativa è Copilot ma devi assumere che il modello venga addestrato in tempi brevi.

Yes, the end, vicolo cieco.

Via verso un altro progetto!