Con il riconoscimento a inchiostro digitale di ML Kit, puoi riconoscere il testo scritto a mano su un superficie digitale in centinaia di lingue, oltre a classificare gli schizzi.
Prova
- Prova l'app di esempio per per vedere un esempio di utilizzo di questa API.
Prima di iniziare
- Nel file
build.gradle
a livello di progetto, assicurati di includere il Repository Maven di Google in entrambe le sezionibuildscript
eallprojects
. - Aggiungi le dipendenze per le librerie Android ML Kit al file Gradle a livello di app del modulo, che in genere è
app/build.gradle
:
dependencies {
// ...
implementation 'com.google.mlkit:digital-ink-recognition:18.1.0'
}
Ora puoi iniziare a riconoscere il testo negli oggetti Ink
.
Crea un oggetto Ink
Il modo principale per creare un oggetto Ink
è disegnarlo su un touchscreen. Attivato
Android, puoi utilizzare
Canvas per
per questo scopo. Il tuo
Gestori di eventi touch
deve chiamare addNewTouchEvent()
mostrato il seguente snippet di codice per memorizzare i punti nei tratti che
l'utente disegna nell'oggetto Ink
.
Questo pattern generale viene dimostrato nel seguente snippet di codice. Consulta le Esempio di guida rapida di ML Kit per un esempio più completo.
Kotlin
var inkBuilder = Ink.builder() lateinit var strokeBuilder: Ink.Stroke.Builder // Call this each time there is a new event. fun addNewTouchEvent(event: MotionEvent) { val action = event.actionMasked val x = event.x val y = event.y var t = System.currentTimeMillis() // If your setup does not provide timing information, you can omit the // third paramater (t) in the calls to Ink.Point.create when (action) { MotionEvent.ACTION_DOWN -> { strokeBuilder = Ink.Stroke.builder() strokeBuilder.addPoint(Ink.Point.create(x, y, t)) } MotionEvent.ACTION_MOVE -> strokeBuilder!!.addPoint(Ink.Point.create(x, y, t)) MotionEvent.ACTION_UP -> { strokeBuilder.addPoint(Ink.Point.create(x, y, t)) inkBuilder.addStroke(strokeBuilder.build()) } else -> { // Action not relevant for ink construction } } } ... // This is what to send to the recognizer. val ink = inkBuilder.build()
Java
Ink.Builder inkBuilder = Ink.builder(); Ink.Stroke.Builder strokeBuilder; // Call this each time there is a new event. public void addNewTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); long t = System.currentTimeMillis(); // If your setup does not provide timing information, you can omit the // third paramater (t) in the calls to Ink.Point.create int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: strokeBuilder = Ink.Stroke.builder(); strokeBuilder.addPoint(Ink.Point.create(x, y, t)); break; case MotionEvent.ACTION_MOVE: strokeBuilder.addPoint(Ink.Point.create(x, y, t)); break; case MotionEvent.ACTION_UP: strokeBuilder.addPoint(Ink.Point.create(x, y, t)); inkBuilder.addStroke(strokeBuilder.build()); strokeBuilder = null; break; } } ... // This is what to send to the recognizer. Ink ink = inkBuilder.build();
Recupera un'istanza di DigitalInkRecognition
Per eseguire il riconoscimento, invia l'istanza Ink
a un
Oggetto DigitalInkRecognizer
. Il codice seguente mostra come creare un'istanza di un
di riconoscimento da un tag BCP-47.
Kotlin
// Specify the recognition model for a language var modelIdentifier: DigitalInkRecognitionModelIdentifier try { modelIdentifier = DigitalInkRecognitionModelIdentifier.fromLanguageTag("en-US") } catch (e: MlKitException) { // language tag failed to parse, handle error. } if (modelIdentifier == null) { // no model was found, handle error. } var model: DigitalInkRecognitionModel = DigitalInkRecognitionModel.builder(modelIdentifier).build() // Get a recognizer for the language var recognizer: DigitalInkRecognizer = DigitalInkRecognition.getClient( DigitalInkRecognizerOptions.builder(model).build())
Java
// Specify the recognition model for a language DigitalInkRecognitionModelIdentifier modelIdentifier; try { modelIdentifier = DigitalInkRecognitionModelIdentifier.fromLanguageTag("en-US"); } catch (MlKitException e) { // language tag failed to parse, handle error. } if (modelIdentifier == null) { // no model was found, handle error. } DigitalInkRecognitionModel model = DigitalInkRecognitionModel.builder(modelIdentifier).build(); // Get a recognizer for the language DigitalInkRecognizer recognizer = DigitalInkRecognition.getClient( DigitalInkRecognizerOptions.builder(model).build());
Elabora un oggetto Ink
Kotlin
recognizer.recognize(ink) .addOnSuccessListener { result: RecognitionResult -> // `result` contains the recognizer's answers as a RecognitionResult. // Logs the text from the top candidate. Log.i(TAG, result.candidates[0].text) } .addOnFailureListener { e: Exception -> Log.e(TAG, "Error during recognition: $e") }
Java
recognizer.recognize(ink) .addOnSuccessListener( // `result` contains the recognizer's answers as a RecognitionResult. // Logs the text from the top candidate. result -> Log.i(TAG, result.getCandidates().get(0).getText())) .addOnFailureListener( e -> Log.e(TAG, "Error during recognition: " + e));
Il codice campione sopra riportato presuppone che il modello di riconoscimento sia già stato scaricato, come descritto nella sezione successiva.
Gestione dei download dei modelli
L'API di riconoscimento dell'inchiostro digitale supporta centinaia di lingue,
richiede il download di alcuni dati prima di qualsiasi riconoscimento. Vicino
Sono necessari 20 MB di spazio di archiviazione per lingua. Ciò viene gestito dal
RemoteModelManager
oggetto.
Scarica un nuovo modello
Kotlin
import com.google.mlkit.common.model.DownloadConditions import com.google.mlkit.common.model.RemoteModelManager var model: DigitalInkRecognitionModel = ... val remoteModelManager = RemoteModelManager.getInstance() remoteModelManager.download(model, DownloadConditions.Builder().build()) .addOnSuccessListener { Log.i(TAG, "Model downloaded") } .addOnFailureListener { e: Exception -> Log.e(TAG, "Error while downloading a model: $e") }
Java
import com.google.mlkit.common.model.DownloadConditions; import com.google.mlkit.common.model.RemoteModelManager; DigitalInkRecognitionModel model = ...; RemoteModelManager remoteModelManager = RemoteModelManager.getInstance(); remoteModelManager .download(model, new DownloadConditions.Builder().build()) .addOnSuccessListener(aVoid -> Log.i(TAG, "Model downloaded")) .addOnFailureListener( e -> Log.e(TAG, "Error while downloading a model: " + e));
Controllare se un modello è già stato scaricato
Kotlin
var model: DigitalInkRecognitionModel = ... remoteModelManager.isModelDownloaded(model)
Java
DigitalInkRecognitionModel model = ...; remoteModelManager.isModelDownloaded(model);
Eliminare un modello scaricato
Se rimuovi un modello dallo spazio di archiviazione del dispositivo, viene liberato spazio.
Kotlin
var model: DigitalInkRecognitionModel = ... remoteModelManager.deleteDownloadedModel(model) .addOnSuccessListener { Log.i(TAG, "Model successfully deleted") } .addOnFailureListener { e: Exception -> Log.e(TAG, "Error while deleting a model: $e") }
Java
DigitalInkRecognitionModel model = ...; remoteModelManager.deleteDownloadedModel(model) .addOnSuccessListener( aVoid -> Log.i(TAG, "Model successfully deleted")) .addOnFailureListener( e -> Log.e(TAG, "Error while deleting a model: " + e));
Suggerimenti per migliorare la precisione del riconoscimento del testo
La precisione del riconoscimento del testo può variare a seconda della lingua. La precisione dipende anche sullo stile di scrittura. La funzione di riconoscimento inchiostro digitale è addestrata per gestire molti tipi di stili di scrittura, i risultati possono variare da utente a utente.
Di seguito sono riportati alcuni modi per migliorare la precisione di un riconoscimento del testo. Tieni presente che queste tecniche non si applica ai classificatori dei disegni per emoji, autoDraw e forme.
Area di scrittura
Molte applicazioni dispongono di un'area di scrittura ben definita per l'input dell'utente. Il significato di un simbolo è determinato parzialmente dalle sue dimensioni rispetto all'area di scrittura che lo contiene. Ad esempio, la differenza tra la lettera "o" e quella minuscola o "c" e una virgola rispetto a barra obliqua.
Indicare al riconoscimento la larghezza e l'altezza dell'area di scrittura può migliorare la precisione. Tuttavia, il riconoscimento presuppone che l'area di scrittura contenga solo una singola riga di testo. Se l'ordine fisico che l'area di scrittura sia abbastanza grande da consentire all'utente di scrivere due o più righe, la visualizzazione risultati passando in un'area di scrittura con un'altezza che rappresenta la stima migliore dell'altezza di riga di testo singola. L'oggetto WriteArea che passi al riconoscimento non deve corrispondere esattamente con l'area di scrittura fisica sullo schermo. Modifica l'altezza dell'area di scrittura in questo modo funziona meglio in alcune lingue rispetto ad altre.
Quando specifichi l'area di scrittura, specifica la larghezza e l'altezza utilizzando le stesse unità del tratto coordinate. Gli argomenti delle coordinate x,y non hanno requisiti di unità: l'API normalizza tutti Unità di misura, perciò l'unica cosa che conta è la dimensione e la posizione relative dei tratti. Sei libero di passare le coordinate nella scala più adatta al tuo sistema.
Pre-contesto
Il pre-contesto è il testo che precede immediatamente i tratti nel Ink
che
gli utenti che tentano di riconoscere. Puoi aiutare il riconoscimento parlando del pre-contesto.
Ad esempio, le lettere corsie "n" e "u" spesso scambiati l'uno per l'altro. Se l'utente ha già inserito la parola parziale "arg", potrebbero continuare con tratti riconoscibili come "ument" o "nment". Specificare l'"arg" del pre-contesto risolve l'ambiguità, poiché la parola "argomento" è più probabile di "argnment".
Il pre-contesto può anche aiutare il riconoscimento a identificare le interruzioni di parola, ovvero gli spazi tra le parole. Puoi digita uno spazio ma non riesci a disegnarne uno, come fa un sistema di riconoscimento a determinare quando termina una parola e inizia la successiva? Se l'utente ha già scritto "hello" e continua con la parola scritta "world", senza pre-contesto il riconoscimento restituisce la stringa "world". Tuttavia, se specifichi pre-contesto "hello", il modello restituisce la stringa " mondiale", con uno spazio iniziale, poiché "hello mondo" ha più senso di "helloword".
Devi fornire la stringa di pre-contesto più lunga possibile, fino a 20 caratteri, tra cui: spazi di archiviazione. Se la stringa è più lunga, il riconoscimento utilizza solo gli ultimi 20 caratteri.
L'esempio di codice seguente mostra come definire un'area di scrittura e utilizzare un
RecognitionContext
oggetto per specificare il pre-contesto.
Kotlin
var preContext : String = ...; var width : Float = ...; var height : Float = ...; val recognitionContext : RecognitionContext = RecognitionContext.builder() .setPreContext(preContext) .setWritingArea(WritingArea(width, height)) .build() recognizer.recognize(ink, recognitionContext)
Java
String preContext = ...; float width = ...; float height = ...; RecognitionContext recognitionContext = RecognitionContext.builder() .setPreContext(preContext) .setWritingArea(new WritingArea(width, height)) .build(); recognizer.recognize(ink, recognitionContext);
Ordinazione tratto
La precisione del riconoscimento dipende dall'ordine dei tratti. I responsabili del riconoscimento si aspettano che avvengono nell'ordine in cui le persone scrivono in modo naturale; ad esempio da sinistra a destra per l'inglese. Qualsiasi caso che si discosta da questo schema, ad esempio scrivere una frase in inglese che inizia con l'ultima parola, fornisce risultati meno precisi.
Un altro esempio è quando una parola al centro di un Ink
viene rimossa e sostituita
un'altra parola. La revisione probabilmente si trova nel bel mezzo di una frase, ma i tratti relativi alla revisione
si trovano alla fine della sequenza del tratto.
In questo caso consigliamo di inviare la parola appena scritta separatamente all'API e di unire la
il risultato con i riconoscimenti precedenti
utilizzando la tua logica.
Gestire forme ambigue
Esistono casi in cui il significato della forma fornita al riconoscimento è ambiguo. Per Ad esempio, un rettangolo con bordi molto arrotondati può essere visto come un rettangolo o un'ellisse.
Questi casi non chiari possono essere gestiti utilizzando i punteggi di riconoscimento, se disponibili. Solo
classificatori di forme forniscono punteggi. Se il modello è molto sicuro, il punteggio del miglior risultato sarà
molto meglio del secondo migliore. In caso di incertezza, i punteggi dei primi due risultati
essere vicini. Inoltre, tieni presente che i classificatori di forma interpretano l'intero Ink
come un
singola forma. Ad esempio, se Ink
contiene un rettangolo e un'ellisse accanto a ogni
il riconoscimento potrebbe restituire l'uno o l'altro (o qualcosa di completamente diverso) come
dato che un singolo candidato al riconoscimento non può rappresentare due forme.