Stanchi dei codici QR? Costruisci il tuo segnalatore fiduciario

Stanchi dei codici QR? Crea il tuo dispositivo di fiducia

I codici QR sono ovunque: vuoi creare una soluzione più originale? Costruiamo il nostro marchio fiduciario e impariamo come rilevarlo e decodificarlo.

Foto di Michael Dziedzic su Unsplash

In questo post, impariamo come costruire un nuovo marchio fiduciario e come rilevarlo allenando un modello di rilevamento oggetti. Successivamente, impariamo come decodificare il nostro marchio usando tecniche di elaborazione delle immagini.

<p+scomponiamolo fasi:

  • Creazione di un marchio fiduciario
  • Rilevare il marchio in un’immagine
  • Decodificare il marchio

Creazione di un marchio fiduciario

Esistono molti marchi fiduciari per la visione artificiale già esistenti, il più famoso è il codice QR. Ci sono altri codici QR, più o meno utilizzati, più o meno robusti, che possono essere utilizzati. Di seguito è riportato un elenco non esaustivo di codici.

Alcuni dei marchi fiduciari più famosi con i loro nomi e date di creazione (fonte https://www.mdpi.com/1424-8220/21/16/5407, sotto licenza CC-BY)

Come possiamo vedere nell’immagine sopra, i marchi fiduciari possono essere molto diversi ma hanno tutti lo stesso scopo: contenere informazioni facilmente decodificabili.

Che cos’è un buon marchio fiduciario?

Idealemente, un buon marchio fiduciario ha le seguenti caratteristiche:

  • Facile da rilevare: prima di poter decodificare un marchio, devi essere in grado di rilevarlo accuratamente in un’immagine
  • Facile da decodificare: deve essere facile decodificare un marchio e senza ambiguità (cioè un marchio decodificato fornisce un valore unico)

In base a queste caratteristiche, costruiamo il nostro marchio personalizzato a partire da quelli esistenti.

Progettazione del nostro marchio fiduciario

Personalmente mi piace il RUNE-tag (per motivi molto arbitrari):

    <li+la ai="" che="" circolare="" e="" forma="" hanno="" i="" li="" lo="" marchi="" morbido="" più="" punti="" quadrati

  • Sembra molto distinguibile, rendendolo molto probabilmente facile da rilevare per un modello di rilevamento oggetti
  • E’ facilmente personalizzabile: possiamo modificare il numero di punti per cerchio e il numero di cerchi per adattarlo alle nostre esigenze ed estetica desiderata

Ma non è perfetto nella sua forma originale: due marchi ruotati possono o meno portare alla stessa decodifica.

L'unica differenza tra questi due tag è una rotazione di 90°: non possono essere discriminati. Immagine dell'autore.

Per mitigare questo problema, aggiungeremo una condizione al marchio: un solo quadrante non avrà punti neri, come mostrato di seguito.

Un tag con una sola riga senza un punto nero, permettendo di risolvere il problema della rotazione. Immagine dell'autore.

Tale marcatore può essere decodificato facilmente: consideriamo che ogni quadrante può assumere tre possibili valori: 0, 1 o 2 a seconda dei tre casi possibili:

  • Un piccolo punto nero: 0
  • Un grande punto nero: 1
  • Entrambi i punti: 2
Rappresentazione di alcuni quadranti: il quadrante 0 è l'unico senza punti neri, mentre gli altri hanno sempre almeno un punto nero. Immagine dell'autore.

In generale, considerando un marcatore con C livelli di cerchi, un quadrante può assumere fino a 2ᶜ−1 valori (perché la situazione senza punti neri è riservata al quadrante 0).

Alla fine, per un marcatore con d+1 punti, il numero di combinazioni possibili è uguale a (2ᶜ— 1)ᵈ. Per un marcatore con 2 livelli di cerchi e 20 punti per cerchio, ci sono circa 3¹⁹ ~ 1,16 miliardi di possibili valori.

Costruzione del nostro marcatore fiduciario

Spieghiamo qui un pezzo di codice utilizzato per generare un’immagine casuale di marcatore fiduciario.

Sintesi del metodo utilizzato per generare il tag casuale. Vedere il link al codice completo funzionante alla fine dell’articolo.

Come si può vedere, il primo passo consiste nel generare una lista di valori casuali. Considerando C il numero di livelli di cerchi e d+1 il numero di punti per cerchio, generiamo una lista di d valori compresi tra 0 e 2ᶜ−1 utilizzando numpy.

Basandoci su questa lista di valori casuali, calcoliamo i valori dei punti: 0 per un punto bianco, 1 per un punto nero. Infine, disegniamo il tag finale, dato un formato di pixel, e salviamo l’output come un’immagine. Naturalmente, è disponibile un link al repository del codice completo e documentato alla fine dell’articolo.

Abbiamo scelto un design per il marcatore e sappiamo come generarne uno. Per essere in grado di utilizzare un marcatore del genere in condizioni reali, dobbiamo avere una soluzione in grado di rilevare e decodificare un marcatore in un’immagine. Questo è davvero semplice, un flusso di lavoro sequenziale a 2 passaggi:

  • Rilevamento del marcatore con la rilevazione degli oggetti
  • Decodifica del marcatore rilevato

Passiamo ora al primo passaggio di questo flusso di lavoro.

Rilevamento del marcatore

Il primo passo consiste nel rilevare la presenza e la posizione di un marcatore in un’immagine data. A tal scopo, ci sono molti modelli di rilevamento degli oggetti disponibili. Utilizzeremo qui un modello YOLOv8, che è molto facile da allenare e utilizzare in un ambiente di produzione.

Ma prima di poter effettivamente allenare un modello di rilevamento degli oggetti, abbiamo bisogno di dati: immagini con sfondi e ambienti diversi contenenti tag da diversi livelli di zoom e prospettive.

Invece di raccogliere e etichettare i dati, che può richiedere molto tempo, genereremo qui dati sintetici da utilizzare per addestrare un modello su questi dati.

Generazione dei dati

Abbiamo bisogno solo di due ingredienti per generare dati sintetici per addestrare un modello di rilevamento degli oggetti:

  • Diverse immagini di sfondo, senza restrizioni, che possono essere prese da Unsplash, ad esempio.
  • Immagini dei marcatori, che genereremo casualmente al volo.

Con questi due ingredienti, tutto quello che dobbiamo fare è applicare alcune trasformazioni utilizzando Albumentations per generare molte immagini uniche generate sinteticamente con le relative etichette associate.

Forniamo qui un pezzo di codice che consente di generare immagini, date un percorso alle immagini di sfondo e le caratteristiche del marcatore, come il numero di strati circolari e punti per cerchio.

Ecco un riassunto del codice utilizzato per generare dati sintetici. Vedete il link al codice completamente funzionante alla fine dell’articolo.

Questo è un codice piuttosto lungo, sentiti libero di approfondirlo, ma in poche parole fa quanto segue:

  • Genera un tag casuale, i limiti dell’immagine sono le etichette del riquadro di delimitazione
  • Applica trasformazioni come affini, di prospettiva o di scala, grazie ad Albumentations
  • Inserisce casualmente questo tag in un’immagine di sfondo selezionata casualmente
  • Fallo tante volte quante necessario

Con questo metodo, possiamo generare facilmente un dataset sufficientemente ampio con centinaia o migliaia di immagini. Di seguito ci sono alcuni esempi delle immagini create con etichette dei riquadri di delimitazione di colore rosso.

Alcune immagini generate con le etichette dei riquadri di delimitazione di colore rosso. Immagine dell'autore.

Come possiamo vedere, le immagini generate sono piuttosto varie, poiché abbiamo sfondi e aumenti come sfocatura e prospettiva.

Ovviamente, non utilizziamo le stesse immagini di sfondo per i set di addestramento e di convalida, in modo che la valutazione del modello rimanga il più imparziale possibile.

Uno script di Python che consente di generare immagini ed etichette associate nelle cartelle corrette per l’addestramento del modello YOLO è disponibile nel repository Github.

Addestramento e valutazione del modello

Utilizzando il dataset precedentemente creato, possiamo ora addestrare un modello di rilevamento degli oggetti su questi dati. Grazie alla libreria YOLOv8, bastano poche righe di codice per addestrare un nuovo modello.

Riepilogo del codice per l’addestramento del modello YOLOv8 small su 100 epoche. Vedete il link al codice completamente funzionante alla fine dell’articolo.

Come possiamo vedere, tutto quello che dobbiamo fare è istanziare un modello e addestrarlo sui dati. Dopo 100 epoche (o meno se si raggiunge la condizione di interruzione anticipata durante l’addestramento, come ho fatto dopo circa 80 epoche qui), ho ottenuto un mAP@50 di circa 0,5, come possiamo vedere dai risultati generati di seguito.

Risultati generati dalla libreria YOLOv8. Il mAP@50 risultante è di circa 0,5. Immagine dell'autore.

Sebbene i risultati siano lontani dall’essere perfetti, sono abbastanza buoni per un dataset addestrato solo con dati sintetici. Ora testiamo questo modello nelle condizioni reali con un feed della webcam.

Per farlo, possiamo utilizzare il codice nel seguente riepilogo:

Riepilogo del codice per l’inferenza del modello YOLOv8 sul feed della webcam. Vedete il link al codice completamente funzionante alla fine dell’articolo.

Questo codice è piuttosto semplice:

  • Carichiamo il modello e otteniamo il feed della webcam
  • Per ogni nuova immagine, calcoliamo l’inferenza del modello e visualizziamo qualsiasi riquadro delimitatore rilevato
  • Interrompiamo il feed premendo il tasto di escape

Ho eseguito questo codice con un’immagine di un marcatore sul mio telefono e, come possiamo vedere nell’immagine qui sotto, ha funzionato molto bene.

Risultato del rilevamento di un modello YOLO addestrato solo con dati sintetici e testato con il feed della mia webcam. Immagine dell'autore.

Anche se non rileva perfettamente il marcatore in tutte le configurazioni, funziona abbastanza bene per un modello addestrato solo con dati sintetici. Per ottenere risultati migliori, credo che si possa ottimizzare un po’ l’aumento dei dati e, naturalmente, dati reali etichettati sarebbero molto utili.

Ora che abbiamo completato la prima parte del processo, passiamo al secondo step: decodifica dei tag.

Decodifica del marcatore

Ora abbiamo dei codici perfettamente funzionanti sia per generare che per rilevare il nostro nuovo marcatore fiduciario.

Una volta che puoi rilevare un tag in un’immagine, il passo successivo è naturalmente decodificarlo. Partiamo da un’immagine ritagliata di un marcatore rilevato, grazie al nostro modello di addestramento precedente.

Immagine ritagliata dal nostro modello di rilevamento degli oggetti. Proviamo a decodificare questo marcatore.

Ho sviluppato un algoritmo di decodifica composto dai seguenti passaggi:

  • Rilevamento dei blob per rilevare i punti
  • Rilevamento del cerchio esterno e adattamento all’ellisse
  • Selezione dei punti per il calcolo dell’omografia
  • Calcolo della matrice di omografia e raddrizzamento dell’immagine
  • E infine, decodifica del marcatore

L’idea principale è la seguente: non appena posso associare un marcatore rilevato con un marcatore di riferimento (conoscendo il numero di strati circolari e punti per cerchio), posso decodificarlo abbastanza facilmente controllando se l’immagine è bianca o nera. Ma per farlo, devo prima raddrizzare l’immagine in modo che corrisponda al marcatore di riferimento.

Andiamo insieme attraverso questi passaggi.

Rilevamento dei punti

Il primo compito è rilevare i punti nell’immagine rilevata dal modello YOLO.

Dall’immagine ritagliata in input, applicheremo la seguente lista di elaborazioni dell’immagine utilizzando OpenCV:

  • Convertire l’immagine in scala di grigi
  • Binare l’immagine con l’algoritmo di Otsu
  • Trovare i punti con un rilevatore di blob

Ecco cosa fa il codice nel seguente riferimento:

Codice per rilevare i punti dall’immagine ritagliata. Vedi il link al codice completamente funzionante alla fine dell’articolo.

Come possiamo vedere, sono impostati molti parametri per il rilevatore di blob, come una superficie minima e massima, così come una circularità minima, al fine di massimizzare il rilevamento effettivo dei punti del marcatore stesso. Ci è voluto un po’ di tempo per perfezionare questi parametri, ma sentiti libero di sperimentare con essi.

Utilizzando questo codice sulla nostra immagine ritagliata in input, otteniamo il seguente rilevamento di blob.

Rilevamento dei blob risultante sull'immagine ritagliata in input: i punti sono ben rilevati. Immagine dell'autore.

Come possiamo vedere, i punti sono ben rilevati. Il passo successivo è rilevare il cerchio esterno.

Rilevamento del cerchio esterno

Ora dobbiamo rilevare lo strato di cerchio più esterno (indipendentemente dal numero di cerchi in un tag, questa soluzione sarebbe generalizzabile). Ciò ci consentirà quindi di trovare i punti sul cerchio esterno, in modo da poter infine raddrizzare l’immagine.

Per calcolare l’ellisse, tutto ciò che facciamo è mantenere i punti più grandi (chiamati punti chiave in OpenCV) e calcolare un’equazione ellittica da quei punti. Questo è ciò che fa il seguente codice:

Codice che consente di calcolare l’equazione ellittica dai punti rilevati. Nota che questo codice calcola sempre una stima del centro, che sarà utile in alcuni passaggi successivi.

Quando applico questo codice e visualizzo i punti rilevati come un grafico a dispersione in cui mostro l’ellisse adattata, ottengo il seguente risultato:

Grafico a dispersione dei blob rilevati e l'ellisse adattata del cerchio esterno. Immagine dell'autore.

Come possiamo vedere, l’ellisse adattata è ben definita e coerente con le posizioni dei punti. Nota che, poiché stiamo adattando un’ellisse, non importa quanto deformato sia il marcatore rilevato a causa della prospettiva, sarebbe comunque in grado di funzionare.

Ora dobbiamo trovare i punti che si trovano effettivamente su questa ellisse. È abbastanza facile: dobbiamo solo trovare le posizioni dei punti che soddisfano l’equazione dell’ellisse (con una soglia data) che abbiamo appena calcolato. Questo viene fatto con il seguente pezzo di codice:

Sommario del codice utilizzato per restituire i punti chiave sull’ellisse. Vedi il link per il codice completamente funzionante alla fine dell’articolo.

Ora che sappiamo dove sono i punti e quali sono sul cerchio esterno, possiamo usarli per calcolare la matrice di omografia e sbloccare l’immagine.

Selezione dei punti per il calcolo dell’omografia

L’obiettivo ora è trovare alcuni punti corrispondenti con l’immagine di riferimento, al fine di calcolare la matrice di omografia.

Immagine di un tag di riferimento, con tutti i punti riempiti. Immagine dell'autore.

Basandoci su questa immagine di riferimento sopra, dobbiamo sbloccare la macchia rilevata con la matrice di omografia corretta.

Per calcolare la matrice di omografia, possiamo semplicemente usare la funzione di OpenCV findHomography. Questa funzione richiede come input almeno 4 punti corrispondenti nell’immagine di riferimento e nell’immagine di input, in modo da poter trovare la matrice di omografia. Questa matrice di omografia ci permetterebbe quindi di sbloccare l’immagine rilevata e abbinarla al riferimento.

Dai nostri blob rilevati sul cerchio esterno, è impossibile sapere dove si trovavano i punti nell’immagine di riferimento originale. Quindi selezioneremo solo la catena più lunga di punti vicini sul cerchio esterno, in modo da poterli abbinare al riferimento. Per farlo, ci sono due passaggi:

  • Calcolare la matrice di adiacenza, in modo che sappiamo, per ogni punto, quali sono i punti adiacenti (se ce ne sono)
  • Dalla matrice di adiacenza, calcolare la catena più lunga di punti adiacenti

Per il primo passaggio, possiamo usare il seguente codice:

Codice per il calcolo della matrice di adiacenza. Vedi il link per il codice completamente funzionante alla fine dell’articolo.

Questo codice calcolerà la matrice di adiacenza, come un dizionario Python: per ogni indice di punto esistente sul cerchio esterno come chiave, un elenco di indici di punti adiacenti trovati è il valore.

Dalla matrice di adiacenza, è ora piuttosto facile trovare la catena più lunga di vicini adiacenti. Per farlo, ho usato il seguente codice:

Sommario del codice utilizzato per il calcolo della catena più lunga di punti adiacenti. Vedi il link per il codice completamente funzionante alla fine dell’articolo.

Questo codice troverà efficientemente la catena più lunga di punti adiacenti e restituirà l’elenco dei loro indici.

Se abbiamo almeno 4 punti in questo output, teoricamente possiamo calcolare la matrice di omografia. Purtroppo, nella maggior parte dei casi non sarà molto accurato, poiché i punti sono quasi sulla stessa linea, non permettendo di calcolare accuratamente la matrice di omografia. Per risolvere questo problema, aggiungeremo un altro punto: un punto posizionato in modo simmetrico rispetto al centro: questo fornirà un calcolo della matrice di omografia molto più accurato.

Possiamo trovare un punto simmetrico rispetto al centro (calcolato durante l’adattamento dell’ellisse) con il seguente codice:

Codice per trovare un punto simmetrico, dato l’input della catena più lunga e tutti i punti chiave sull’ellisse. Vedi il link per il codice completamente funzionante alla fine dell’articolo.

NB: dato che siamo su un’ellisse, utilizzare l’estimazione del centro per trovare il punto simmetrico di un dato punto non è un metodo affidabile al 100%: potrebbe restituire un punto sbagliato. Questa è una cosa che terremo presente durante il calcolo della decodifica.

Alla fine, otteniamo i risultati nell’immagine seguente, in cui i cerchi blu sono quelli della catena più lunga, e quelli rossi sono i punti simmetrici supposti (uno di essi fa parte della catena più lunga).

Risultato della selezione dei punti. Nel cerchio blu ci sono i punti della catena più lunga (eccetto il più a sinistra). Nel cerchio rosso sono stati rilevati punti simmetrici. Il punto rosso centrale è il centro dell'ellisse stimato. Immagine dell'autore.

Come possiamo vedere, abbiamo effettivamente selezionato la catena di 7 punti adiacenti e abbiamo selezionato un altro punto per essere simmetrico rispetto al punto più a sinistra nella catena.

Scommentare l’immagine

Ora che abbiamo selezionato alcuni punti nell’immagine di input, cerchiamo i punti corrispondenti nell’immagine di riferimento e calcoliamo la matrice di omografia. Per fare ciò, abbiamo bisogno dei seguenti input:

  • Le posizioni dei punti selezionati nell’immagine ritagliata: è quello che abbiamo appena calcolato
  • Le posizioni equivalenti di questi punti nell’immagine di riferimento: cioè deve essere calcolato, conoscendo il marcatore di riferimento

Per calcolare le posizioni di questi punti, useremo il seguente codice, che consente di calcolare le posizioni dei punti.

Snippet del codice utilizzato per generare le posizioni dei punti di riferimento per il calcolo dell’omografia. Vedere il link al codice completo alla fine dell’articolo.

Si noti che abbiamo dato un grado di libertà in più con un parametro chiamato symmetry_index_offset: ciò consentirà di gestire possibili errori nel calcolo dei punti simmetrici, aggiungendo un offset alla posizione del punto simmetrico.

Con le posizioni corrette dei punti sia nell’immagine ritagliata che nell’immagine di riferimento, possiamo ora calcolare la matrice di omografia e scommentare l’immagine. Per assicurarci di non commettere errori con il punto simmetrico, lo faremo per un valore di offset compreso tra -2 e 2 con un passo di 1, come possiamo vedere nel frammento di codice qui sotto:

Snippet del codice per il calcolo dell’omografia e lo srotolamento dell’immagine. Vedere il link al codice completo alla fine dell’articolo.

Cosa facciamo qui è semplicemente calcolare la matrice di omografia con la funzione findHomography di OpenCV e quindi srotolare l’immagine con warpPerspective. E lo facciamo per 5 valori di offset, in modo da ottenere 5 immagini srotolate.

Le immagini risultanti sono le seguenti:

Immagini srotolate risultanti. Solo quella con un offset -1 è srotolata correttamente. Immagine dell'autore.

Come possiamo vedere, a seconda dell’offset il risultato dello srotolamento è piuttosto diverso. Anche se è abbastanza facile con un’ispezione visiva capire che l’offset di -1 è quello giusto, vogliamo che questo controllo sia automatizzato. Gestiremo questo nel prossimo passaggio: la decodifica effettiva del marcatore.

Decodifica del marcatore

Da un’immagine srotolata data, l’ultimo passaggio consiste nel decodificare il marcatore. Siamo davvero vicini, e questo passaggio è probabilmente il più facile.

Tutto ciò che dobbiamo fare è controllare, per ogni posizione di punto prevista, il colore dell’immagine srotolata. Poiché l’immagine è stata sottoposta a una binarizzazione di Otsu, questo è abbastanza semplice. Controlleremo semplicemente se c’è un pixel nero in un’area di 3×3 pixel intorno a una posizione di punto prevista: se sì, allora c’è un punto; se no, allora non c’è alcun punto.

Snippet del codice utilizzato per calcolare il codice di lista dall’immagine srotolata. Vedere il link al codice completo alla fine dell’articolo.

Questo è fondamentalmente quello che fa il codice sopra. Quindi, a seconda della posizione, assegnamo un valore. Pertanto, l’output di questa funzione è semplicemente una lista di valori. Infine, cerchiamo un valore -1 (che significa il quadrante previsto senza punto nero, controllare la sezione Progettazione del nostro marcatore fiduciario per un promemoria in merito), e riorganizziamo l’array per posizionarlo alla fine dell’indice.

Ad esempio, ecco i codici calcolati per ciascuna delle 5 immagini srotolate:

  • Offset -2: [0, 2, 0, -1, 1, -1, 0, 0, 0, 2, 2, 1, 2, 2, 0, 2, 2, 2, 0, -1]
  • Offset -1: [2, 2, 2, 0, 2, 0, 1, 1, 1, 2, 2, 1, 2, 2, 0, 2, 2, 2, 0, -1]
  • Offset 0: [0, -1, 2, 2, 0, 0, -1, 0, 0, -1, 0, 1, 2, 2, 0, 2, 2, 2, 0, -1]
  • Offset 1: [-1, 2, 2, 2, 2, 0, -1, -1, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, 0, -1]
  • Offset 2: [-1, 2, 1, 2, 1, 0, 1, -1, -1, -1, -1, 0, 0, 0, 2, 2, 0, 0, 2, -1]

Come possiamo vedere, c’è solo un’immagine con un valore -1, nella posizione dell’ultimo indice: l’immagine non distorta utilizzando un offset di -1. Questa è la nostra immagine ben non distorta (come abbiamo potuto vedere con un’ispezione visiva), che ci permette di decodificare effettivamente il marcatore.

Questo elenco di codici è unico per ogni possibile marcatore, quindi puoi fermarti qui o calcolare un valore intero unico. Un valore unico può essere calcolato molto facilmente con il seguente frammento di codice:

Riassunto del codice usato per calcolare il valore finale decodificato dall’elenco di codici. Vedi il link al codice completamente funzionante alla fine dell’articolo.

Nel nostro caso, questo restituirebbe -1 per tutte le immagini non distorte in modo errato e un valore di 377667386 per il marcatore effettivo.

Ecco fatto, siamo arrivati dall’immagine di input a un codice unico effettivo! Ora facciamo un riassunto e riflettiamo sulle limitazioni di ciò che abbiamo fatto.

Creazione di un processo completo

Ora che abbiamo tutti i blocchi di costruzione, dobbiamo solo metterli insieme per ottenere un bel decodificatore di marcatore fiduciale personalizzato, che può sostituire un codice QR!

Come riassunto, ecco i passaggi in un processo completamente funzionante:

  • A partire da un’immagine di input, individua i marcatore con il rilevamento degli oggetti
  • Per ogni oggetto rilevato, ritaglia l’immagine e continua con i passaggi successivi
  • Rileva i punti con binarizzazione di Otsu e rilevamento dei blob
  • Trova i punti più esterni con adattamento di ellipse
  • Calcola la matrice di omografia utilizzando la catena più lunga dei punti più vicini e un punto simmetrico
  • Appiattisci l’immagine utilizzando la matrice di omografia
  • Decodifica il marcatore utilizzando l’immagine di riferimento

Ecco fatto! Non ti farò scrivere tutto il codice da solo, tutto è disponibile nel repository GitHub, così come un modello di rilevamento degli oggetti preaddestrato.

Troverai in questo repository script python per eseguire sottopassi (ad esempio, generare immagini sintetiche, addestrare un modello di rilevamento degli oggetti, ecc…) così come uno script python che esegue il processo completo con la tua webcam come input, in modo da poterlo testare!

Considerazioni finali

Spero che tu abbia apprezzato questo post e che tu abbia imparato qualcosa da esso! Personalmente ho adorato questo progetto, perché utilizza l’apprendimento automatico così come il buon vecchio elaborazione delle immagini.

Tuttavia, l’algoritmo che ho sviluppato ha alcune limitazioni che mi piacerebbe superare. Infatti, non tutti i marcatori possono essere decodificati:

  • Un marcatore con non più di 2 punti adiacenti sul cerchio più esterno non sarebbe decodificato correttamente
  • Lo stesso vale per un marcatore senza punti simmetrici dalla catena più lunga: darebbe risultati non affidabili a causa di una matrice di omografia imprecisa

Un’altra limitazione è il fatto che a volte l’omografia riflette l’immagine durante il processo di sgonfiamento, causando l’inversione dell’elenco di codici e quindi un valore intero decodificato finale diverso.

Se hai qualche idea per superare queste limitazioni, sei più che invitato a inviarmi un messaggio o addirittura proporre una richiesta di pull!

Su un altro argomento, la decodifica qui fornisce solo un valore intero. Sta a te abbinare questo valore intero con qualcosa di rilevante (un link, un oggetto, un’immagine…) nella tua app per renderlo veramente utile. Credo che sarebbe possibile decodificare un marcatore del genere come un elenco di caratteri ASCII direttamente, ma non l’ho provato personalmente: di nuovo, ogni contributo è più che benvenuto.

Riferimenti

Articolo originale di RUNE-Tag:

F. Bergamasco, A. Albarelli, E. Rodolà e A. Torsello, “RUNE-Tag: A high accuracy fiducial marker with strong occlusion resilience,” CVPR 2011, Colorado Springs, CO, USA, 2011, pp. 113–120, doi: 10.1109/CVPR.2011.5995544.

Repository originale di RUNE-Tag: https://github.com/artursg/RUNEtag