OdoKeep è ora su App Store. Scaricala gratis.

Tutti gli articoli

Riconoscimento delle ricevute

OCR di ricevute offline in Expo: il lavoro inizia dopo il riconoscimento del testo

Interpretare ricevute sul telefono con Expo, Vision e ML Kit: candidati, controlli aritmetici, unità esplicite e revisione dei dati.

Aggiornato il

In questo articolo

Su una ricevuta, 1,899 può essere un prezzo unitario, 95 il tipo di carburante e 04 il numero della pompa. Il motore OCR può leggerli tutti perfettamente e lasciarmi comunque un rifornimento sbagliato.

Ho aggiunto la scansione delle ricevute a OdoKeep, il mio diario dei veicoli in React Native ed Expo. Il riconoscimento avviene sul telefono: Vision di Apple su iOS e riconoscitori Google ML Kit inclusi nell'app su Android. Questa funzione non carica la fotografia o il testo riconosciuto su un server.

Il modulo nativo gestisce acquisizione, preparazione dell'immagine, riconoscimento e fotografia temporanea. L'interpretazione vive in TypeScript dentro lib/receipt-scan. Il parser può così essere testato senza fotocamera o dispositivo specifico.

Conservare le prove insieme al testo

Il risultato nativo contiene righe, riquadri di origine, informazioni di confidenza disponibili e, quando il motore le espone, trascrizioni alternative. Il parser usa le posizioni per collegare un campo al punto della fotografia da cui proviene.

Il percorso è questo:

Fotografia
  -> righe e riquadri del riconoscimento nativo
  -> token numerici con unità e posizioni
  -> candidati ordinati per campo
  -> verifica aritmetica
  -> bozza controllata
  -> normale modulo carburante o ricarica

Non avvengono scritture tra riconoscimento e modulo originale. La scansione propone valori che la persona può correggere e salvare con lo stesso percorso dell'inserimento manuale.

Ordinare le letture prima di scegliere un numero

Le ricevute possono usare virgole o punti decimali, spazi di raggruppamento, apostrofi svizzeri e diversi sistemi di cifre. La stampa termica può perdere un separatore o far sembrare una cifra una lettera.

Il tokenizer conserva più letture plausibili. Non deve risolvere 1,899 prima di averne visto etichetta, unità e vicini. Una correzione ipotetica ha una priorità minore di una lettura ordinaria e mantiene la propria posizione nell'immagine.

La graduatoria parte dalle prove stampate. Un'unità esplicita sostiene la quantità. Una tariffa come EUR/L sostiene il prezzo unitario. L'etichetta del totale sostiene l'importo di riferimento.

Date, percentuali, distanze e riferimenti amministrativi sono esclusi dai campi degli importi. Un numero senza etichetta non diventa quantità solo perché rende comodo il calcolo. Ogni campo conserva al massimo venti candidati per limitare le combinazioni.

La moltiplicazione è una conferma circoscritta

L'aritmetica sembra facile:

quantity * unitPrice = printedTotal

Una corrispondenza sostiene una lettura candidata. Non dimostra che l'immagine sia corretta o che tutti e tre i campi descrivano la transazione attesa.

Il parser confronta il prodotto con una tolleranza di mezza unità monetaria minima, più un margine per i numeri in virgola mobile. Con due decimali, la base è mezzo centesimo. Non ammette una percentuale della spesa, che lascerebbe passare errori OCR maggiori sugli importi più alti.

Questo caso è nei test:

31.93 L x 1.899 EUR/L
TOTAL 60.84 EUR

Il prodotto è circa 60,635. Una tolleranza percentuale larga potrebbe accettare 60,84. Il confronto basato sulla valuta lo rifiuta.

Un altro test ha quantità e prezzo leggibili, un subtotale coerente e un pagamento inferiore:

40 L x 1.80 EUR/L
Subtotal 72 EUR
Discount 4 EUR
Total 68 EUR

Il parser conserva 68 come totale stampato di riferimento. Non promuove 72 a totale finale solo perché torna la moltiplicazione. Quantità e prezzo restano utili anche con uno sconto.

OdoKeep calcola il costo salvato moltiplicando quantità e prezzo e sottraendo un eventuale sconto controllato. Il totale stampato non viene copiato nel costo salvato. Non può nemmeno fornire per divisione una quantità o un prezzo mancanti.

Se si riconosce solo il totale, gli importi vanno ancora inseriti. Se manca il prezzo, il campo resta vuoto. Un risultato parziale può rimanere parziale.

Se la verifica aritmetica non passa, l'app può richiedere una lettura con più contrasto. Confronta le due letture prima per coerenza aritmetica, poi per campi degli importi recuperati. A parità conserva la prima. Data, ora, stazione e altri campi non monetari possono colmare le lacune usando l'altra lettura: entrambe provengono dalla stessa foto.

Anche la lettura migliore passa dalla revisione. Più prove cambiano la graduatoria, non eliminano la possibilità di correggere.

Scegliere esplicitamente unità e valute

Litri, galloni statunitensi, galloni imperiali, chilogrammi, metri cubi e kilowattora sono validi nel dominio di carburante e ricarica. Non sono intercambiabili.

La sola scritta gal non identifica il gallone. L'importatore chiede una scelta. Nel convertire volumi compatibili, moltiplica la quantità e divide il prezzo per lo stesso fattore:

convertedQuantity = printedQuantity * factor
convertedUnitPrice = printedUnitPrice / factor

Il prodotto si conserva prima dell'arrotondamento. I valori convertiti hanno al massimo tre decimali: il costo ricalcolato dal modulo può quindi differire leggermente dal riferimento stampato. Conservare l'unità originale evita questo arrotondamento.

I conflitti di dimensione fisica richiedono più prudenza. Litri e un prezzo esplicitamente per kilowattora non possono formare un costo di carburante. Il parser mantiene quantità e unità e lascia vuoto il prezzo.

Anche la valuta è esplicita. Se il documento ne indica un'altra, la persona può mantenerla. Se sceglie invece quella configurata, l'importatore conserva la quantità e cancella il prezzo, senza ipotizzare un cambio. Visualizzare in seguito un costo in valuta estera compete al livello di conversione dell'app, che considera la data del pagamento.

Il contesto regionale viene dalla regione del dispositivo, indipendentemente dalla lingua dell'interfaccia. Usare l'inglese in Portogallo non deve trasformare tutte le ricevute in documenti americani. Unità e codici valuta espliciti prevalgono sui valori regionali predefiniti.

Riconoscimento e ciclo di vita della foto

Su iOS, Vision usa il riconoscimento accurato senza correzione linguistica. Numeri e abbreviazioni non traggono beneficio da tutte le ipotesi utili per correggere la prosa. I suggerimenti di lingua vengono verificati rispetto alla richiesta Vision configurata prima di essere forniti.

Android include i riconoscitori latino, cinese, devanagari, giapponese e coreano descritti nella documentazione ML Kit. Aumenta il binario, ma rende disponibili offline quei modelli. L'acquisizione tramite scanner documenti ha requisiti separati di Google Play services e può richiedere un download iniziale; selettore immagini e OCR incluso offrono un'alternativa. Non significa coprire ogni sistema di scrittura.

L'orientamento viene normalizzato nei pixel e i riquadri OCR devono corrispondere alla foto mostrata. Entrambe le implementazioni possono provare rotazioni quando la prima lettura è scarsa, ma pochi frammenti aggiuntivi non giustificano da soli una rotazione.

Le copie temporanee appartengono a una sessione. Una sessione annullata non può scrivere una foto tardiva dopo la pulizia, né una revisione eliminare l'immagine di un'altra. La bozza appartiene al modulo che l'ha chiesta e può essere consumata una sola volta. Tornare al modulo non deve sostituire le correzioni con il vecchio risultato.

Testare separatamente l'interpretazione

I test includono due trascrizioni reali e casi sintetici per formati regionali, unità ambigue, sconti, date errate, letture alternative e trasferimenti parziali. Verificano le decisioni sul testo OCR, non un tasso di riconoscimento su un corpus di immagini. Luce scarsa, stampa sbiadita e copertura delle scritture richiedono ancora prove sui dispositivi.

La separazione facilita l'indagine. Se i caratteri sono sbagliati, controllo acquisizione e riconoscimento. Se sono corretti ma il dato no, controllo le prove del parser e il passaggio al modulo. Un JSON apparentemente completo nasconderebbe la differenza.

La scansione fa parte di OdoKeep. Se registri carburante o ricariche, puoi provarla nell'app iOS: fotografare, controllare quanto recuperato e completare il modulo abituale.