Grazie al riconoscimento dell'inchiostro digitale di ML Kit, puoi riconoscere il testo scritto a mano su una superficie digitale in centinaia di lingue e classificare gli schizzi.
Prova
- Prova l'app di esempio per vedere un utilizzo di esempio 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 di ML Kit al file Gradle a livello di app del tuo modulo, che di solito è
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. Su
Android, puoi utilizzare una
canvas a questo scopo. I gestori di eventi touch devono chiamare il metodo addNewTouchEvent()
mostrato nel seguente snippet di codice per memorizzare i punti nei tratti che l'utente disegna nell'oggetto Ink
.
Questo pattern generale è dimostrato nello snippet di codice riportato di seguito. Per un esempio più completo, consulta l'esempio della guida rapida di ML Kit.
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();
Recupero di un'istanza di DigitalInkRecognizer
Per eseguire il riconoscimento, invia l'istanza Ink
a un
oggetto DigitalInkRecognizer
. Il codice seguente mostra come creare un'istanza di questo 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 di esempio riportato sopra presuppone che il modello di riconoscimento sia già stato scaricato, come descritto nella sezione successiva.
Gestione dei download dei modelli
Sebbene l'API di riconoscimento dell'inchiostro digitale supporti centinaia di lingue, ogni lingua richiede il download di alcuni dati prima di qualsiasi riconoscimento. Sono necessari circa 20 MB di spazio di archiviazione per lingua. Questo viene gestito dall'oggetto RemoteModelManager
.
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
La rimozione di un modello dallo spazio di archiviazione del dispositivo libera 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 nelle diverse lingue. La precisione dipende anche dallo stile di scrittura. Sebbene Digital Ink Recognition sia addestrato per gestire molti tipi di stili di scrittura, i risultati possono variare da utente a utente.
Ecco alcuni modi per migliorare la precisione di un riconoscimento del testo. Tieni presente che queste tecniche non si applicano alle categorie di classificazione 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 è in parte determinato dalle sue dimensioni rispetto a quelle dell'area di scrittura che lo contiene. Ad esempio, la differenza tra la lettera "o" o "c" in minuscolo o maiuscolo e una virgola rispetto a una barra.
Indicare al riconoscimento la larghezza e l'altezza dell'area di scrittura può migliorare l'accuratezza. Tuttavia, il riconoscimento presuppone che l'area di scrittura contenga una sola riga di testo. Se l'area di scrittura fisica è abbastanza grande da consentire all'utente di scrivere due o più righe, potresti ottenere risultati migliori passando in un'area di scrittura con un'altezza che sia la stima migliore dell'altezza di una singola riga di testo. L'oggetto Scrittura Area che passi al riconoscimento non deve corrispondere esattamente all'area di scrittura fisica sullo schermo. Modificare l'altezza dell'area di scrittura in questo modo funziona meglio in alcune lingue che in altre.
Quando specifichi l'area di scrittura, specifica larghezza e altezza nelle stesse unità delle coordinate del tratto. Gli argomenti delle coordinate x,y non richiedono unità: l'API normalizza tutte le unità, quindi l'unica cosa che conta sono le dimensioni relative e la posizione dei tratti. Sei libero di inserire le coordinate in qualsiasi scala abbia senso per il tuo sistema.
Pre-contesto
Il pre-contesto è il testo che precede immediatamente i tratti nel Ink
che stai cercando di riconoscere. Puoi aiutare il riconoscimento indicando il pre-contesto.
Ad esempio, le lettere in corsivo "n" e "u" vengono spesso scambiate l'una per l'altra. Se l'utente ha già inserito la parola parziale "arg", potrebbe continuare con tratti che possono essere riconosciuti come "ument" o "nment". Specificare il pre-contesto "arg" risolve l'ambiguità, poiché la parola "argomento" è più probabile di "argnment".
Il pre-contesto può inoltre aiutare il sistema di riconoscimento a identificare le interruzioni di parole, ovvero gli spazi tra le parole. Puoi digitare uno spazio, ma non disegnarne uno. In che modo un riconoscimento può determinare quando termina una parola e quando 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 il pre-contesto "hello", il modello restituirà la stringa "world", con uno spazio iniziale, poiché "helloworld" ha più senso di "helloword".
Fornisci la stringa pre-contesto più lunga possibile, fino a 20 caratteri, spazi inclusi. Se la stringa è più lunga, il riconoscimento utilizza solo gli ultimi 20 caratteri.
L'esempio di codice riportato di seguito mostra come definire un'area di scrittura e utilizzare un oggetto RecognitionContext
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);
Ordine tratti
La precisione del riconoscimento dipende dall'ordine dei tratti. I sistemi di riconoscimento si aspettano che i colpi si corrano nell'ordine naturale che le persone scrivono, ad esempio da sinistra a destra per l'inglese. Qualsiasi caso che si discosta da questo modello, come la scrittura di una frase in inglese che inizia con l'ultima parola, fornisce risultati meno precisi.
Un altro esempio è quando una parola nel mezzo di Ink
viene rimossa e sostituita con un'altra parola. La revisione si trova probabilmente nel mezzo di una frase, ma i tratti per la revisione sono alla fine della sequenza.
In questo caso ti consigliamo di inviare separatamente la parola appena scritta all'API e di unire il risultato con i riconoscimenti precedenti utilizzando la tua logica.
Gestire le forme ambigue
In alcuni casi il significato della forma fornita al riconoscimento è ambiguo. Ad esempio, un rettangolo con bordi molto arrotondati può essere visto come un rettangolo o un'ellisse.
Questi casi poco chiari possono essere gestiti utilizzando i punteggi di riconoscimento, se disponibili. Solo
i classificatori di forma forniscono i punteggi. Se il modello è molto sicuro, il punteggio del primo risultato sarà molto migliore del secondo. In caso di incertezza, i punteggi dei primi due risultati saranno vicini. Inoltre, tieni presente che i classificatori di forma interpretano l'intero Ink
come una singola forma. Ad esempio, se Ink
contiene un rettangolo e un'ellisse uno accanto all'altro, il riconoscimento potrebbe restituire l'uno o l'altro (o qualcosa di completamente diverso) come risultato, poiché un singolo candidato per il riconoscimento non può rappresentare due forme.