Riconoscimento della scrittura a mano libera degli utenti

L'API Riconoscimento della scrittura a mano libera consente di riconoscere il testo inserito a mano libera nel momento in cui si verifica.

Christian Liebel
Christian Liebel

Che cos'è l'API Riconoscimento della scrittura a mano libera?

L'API di riconoscimento della scrittura a mano libera ti consente di convertire la scrittura a mano libera (inchiostro) dei tuoi utenti in testo. Alcuni sistemi operativi includono da tempo queste API e, con questa nuova funzionalità, le tue app web possono finalmente utilizzare questa funzionalità. La conversione avviene direttamente sul dispositivo dell'utente, funziona anche in modalità offline, il tutto senza l'aggiunta di librerie o servizi di terze parti.

Questa API implementa il riconoscimento "on-line" o quasi in tempo reale. Ciò significa che l'input scritto a mano viene riconosciuto mentre l'utente lo sta disegnando acquisendo e analizzando i singoli tratti. A differenza delle procedure "off-line" come il riconoscimento ottico dei caratteri (OCR), in cui è noto solo il prodotto finale, gli algoritmi online possono fornire un livello di precisione superiore grazie a segnali aggiuntivi come la sequenza temporale e la pressione dei singoli tratti di inchiostro.

Casi d'uso suggeriti per l'API Riconoscimento della scrittura a mano libera

Esempi di utilizzo includono:

  • Applicazioni per creare note in cui gli utenti vogliono acquisire note scritte a mano e tradurle in testo.
  • Applicazioni di moduli in cui gli utenti possono utilizzare l'input con penna o dito a causa dei limiti di tempo.
  • Giochi che richiedono la compilazione di lettere o numeri, come cruciverba, impiccato o sudoku.

Stato attuale

L'API Riconoscimento della scrittura a mano libera è disponibile su Chromium 99.

Come utilizzare l'API di riconoscimento della scrittura a mano libera

Rilevamento delle funzionalità

Rileva il supporto del browser controllando l'esistenza del metodo createHandwritingRecognizer() nell'oggetto del navigatore:

if ('createHandwritingRecognizer' in navigator) {
  // 🎉 The Handwriting Recognition API is supported!
}

Concetti principali

L'API Riconoscimento della scrittura a mano libera converte l'input scritto a mano in testo, indipendentemente dal metodo di inserimento (mouse, tocco, penna). L'API ha quattro entità principali:

  1. Un punto rappresenta la posizione del puntatore in un determinato momento.
  2. Un tratto è costituito da uno o più punti. La registrazione di un tratto inizia quando l'utente posiziona il puntatore verso il basso (ad esempio, fa clic sul pulsante principale del mouse o tocca lo schermo con la penna o il dito) e termina quando il puntatore viene sollevato di nuovo.
  3. Un disegno è costituito da uno o più tratti. Il riconoscimento effettivo avviene a questo livello.
  4. Il riconoscimento è configurato con la lingua di input prevista. Viene usato per creare un'istanza di un disegno alla quale è applicata la configurazione del riconoscimento.

Questi concetti vengono implementati sotto forma di interfacce e dizionari specifici, di cui parleremo a breve.

Entità principali dell'API di riconoscimento della scrittura a mano libera: uno o più punti compongono un tratto, uno o più tratti formano un disegno creato dal riconoscimento. Il riconoscimento effettivo avviene a livello di disegno.

Creazione di un riconoscimento

Per riconoscere il testo proveniente da input scritto a mano, devi ottenere un'istanza di HandwritingRecognizer chiamando navigator.createHandwritingRecognizer() e passando i vincoli. I vincoli determinano il modello di riconoscimento della scrittura da utilizzare. Al momento, puoi specificare un elenco di lingue in ordine di preferenza:

const recognizer = await navigator.createHandwritingRecognizer({
  languages: ['en'],
});

Il metodo restituisce una promessa che risolve con un'istanza di HandwritingRecognizer quando il browser è in grado di soddisfare la tua richiesta. In caso contrario, la promessa viene rifiutata con un errore e il riconoscimento della scrittura a mano libera non sarà disponibile. Per questo motivo, potresti chiedere prima l'assistenza del riconoscimento per determinate funzionalità di riconoscimento.

Esecuzione di query sull'assistenza per il riconoscimento

Chiamando navigator.queryHandwritingRecognizerSupport(), puoi verificare se la piattaforma di destinazione supporta le funzionalità di riconoscimento della scrittura che intendi utilizzare. Nell'esempio seguente, lo sviluppatore:

  • vuole rilevare i testi in inglese
  • ottenere previsioni alternative e meno probabili, se disponibili
  • accedi al risultato della segmentazione, ovvero ai caratteri riconosciuti, inclusi i punti e i tratti che li compongono
const { languages, alternatives, segmentationResults } =
  await navigator.queryHandwritingRecognizerSupport({
    languages: ['en'],
    alternatives: true,
    segmentationResult: true,
  });

console.log(languages); // true or false
console.log(alternatives); // true or false
console.log(segmentationResult); // true or false

Il metodo restituisce una promessa che risolve con un oggetto risultato. Se il browser supporta la funzionalità specificata dallo sviluppatore, il relativo valore verrà impostato su true. In caso contrario, verrà impostato su false. Puoi utilizzare queste informazioni per attivare o disattivare determinate funzionalità all'interno dell'applicazione o per modificare la query e inviarne una nuova.

Inizia un disegno

All'interno dell'applicazione, offri un'area di input in cui l'utente esegue le voci scritte a mano. Per migliorare le prestazioni, ti consigliamo di implementare questa funzionalità con l'aiuto di un oggetto canvas. L'esatta implementazione di questa parte non rientra nell'ambito di questo articolo, ma puoi fare riferimento alla demo per scoprire come fare.

Per iniziare un nuovo disegno, chiama il metodo startDrawing() sul riconoscimento. Questo metodo accetta un oggetto contenente suggerimenti diversi per perfezionare l'algoritmo di riconoscimento. Tutti i suggerimenti sono facoltativi:

  • Il tipo di testo inserito: testo, indirizzi email, numeri o un singolo carattere (recognitionType)
  • Il tipo di dispositivo di input: mouse, tocco o penna (inputType)
  • Il testo precedente (textContext)
  • Il numero di previsioni alternative meno probabili che devono essere restituite (alternatives)
  • Un elenco di caratteri identificabili dall'utente ("grafi") che l'utente probabilmente inserirà (graphemeSet)

L'API di riconoscimento della scrittura a mano libera funziona bene con gli eventi di puntamento, che forniscono un'interfaccia astratta per utilizzare l'input da qualsiasi dispositivo di puntamento. Gli argomenti dell'evento puntatore contengono il tipo di puntatore usato. Ciò significa che puoi utilizzare gli eventi puntatore per determinare automaticamente il tipo di input. Nell'esempio seguente, il disegno per il riconoscimento della scrittura a mano libera viene creato automaticamente alla prima occorrenza di un evento pointerdown nell'area di scrittura a mano libera. Poiché pointerType può essere vuoto o impostato su un valore proprietario, ho introdotto un controllo di coerenza per garantire che siano impostati solo i valori supportati per il tipo di input del disegno.

let drawing;
let activeStroke;

canvas.addEventListener('pointerdown', (event) => {
  if (!drawing) {
    drawing = recognizer.startDrawing({
      recognitionType: 'text', // email, number, per-character
      inputType: ['mouse', 'touch', 'pen'].find((type) => type === event.pointerType),
      textContext: 'Hello, ',
      alternatives: 2,
      graphemeSet: ['f', 'i', 'z', 'b', 'u'], // for a fizz buzz entry form
    });
  }
  startStroke(event);
});

Aggiungi un tratto

L'evento pointerdown è anche il punto giusto per iniziare un nuovo tratto. Per farlo, crea una nuova istanza di HandwritingStroke. Inoltre, devi memorizzare l'ora corrente come punto di riferimento per i punti successivi aggiunti:

function startStroke(event) {
  activeStroke = {
    stroke: new HandwritingStroke(),
    startTime: Date.now(),
  };
  addPoint(event);
}

Aggiungi un punto

Dopo aver creato il tratto, devi aggiungere direttamente il primo punto. Poiché aggiungerai altri punti in seguito, ha senso implementare la logica di creazione di punti in un metodo separato. Nell'esempio seguente, il metodo addPoint() calcola il tempo trascorso a partire dal timestamp di riferimento. Le informazioni temporali sono facoltative, ma possono migliorare la qualità del riconoscimento. Legge poi le coordinate X e Y dell'evento puntatore e aggiunge il punto al tratto corrente.

function addPoint(event) {
  const timeElapsed = Date.now() - activeStroke.startTime;
  activeStroke.stroke.addPoint({
    x: event.offsetX,
    y: event.offsetY,
    t: timeElapsed,
  });
}

Il gestore di eventi pointermove viene richiamato quando il puntatore viene spostato sullo schermo. Questi punti devono essere aggiunti anche al tratto. L'evento può essere sollevato anche se il puntatore non è in stato "giù", ad esempio quando si sposta il cursore sullo schermo senza premere il pulsante del mouse. Il gestore di eventi dell'esempio seguente controlla se esiste un tratto attivo e vi aggiunge il nuovo punto.

canvas.addEventListener('pointermove', (event) => {
  if (activeStroke) {
    addPoint(event);
  }
});

Riconoscimento del testo

Quando l'utente solleva di nuovo il puntatore, puoi aggiungere il tratto al disegno richiamando il relativo metodo addStroke(). L'esempio seguente reimposta anche activeStroke, in modo che il gestore di pointermove non aggiunga punti al tratto completato.

Successivamente, è il momento di riconoscere l'input dell'utente chiamando il metodo getPrediction() nel disegno. Il riconoscimento di solito richiede meno di qualche centinaio di millisecondi, quindi puoi eseguire ripetutamente le previsioni, se necessario. L'esempio seguente esegue una nuova previsione dopo ogni tratto completato.

canvas.addEventListener('pointerup', async (event) => {
  drawing.addStroke(activeStroke.stroke);
  activeStroke = null;

  const [mostLikelyPrediction, ...lessLikelyAlternatives] = await drawing.getPrediction();
  if (mostLikelyPrediction) {
    console.log(mostLikelyPrediction.text);
  }
  lessLikelyAlternatives?.forEach((alternative) => console.log(alternative.text));
});

Questo metodo restituisce una promessa che si risolve con un array di previsioni ordinate in base alla loro probabilità. Il numero di elementi dipende dal valore passato al suggerimento alternatives. Puoi utilizzare questo array per presentare all'utente una scelta di possibili corrispondenze e chiedere di selezionare un'opzione. In alternativa, puoi scegliere semplicemente la previsione più probabile, che è l'esempio riportato nell'esempio.

L'oggetto di previsione contiene il testo riconosciuto e un risultato di segmentazione facoltativo, che esamineremo nella sezione seguente.

Informazioni dettagliate con i risultati della segmentazione

Se supportato dalla piattaforma di destinazione, l'oggetto previsione può contenere anche un risultato di segmentazione. Questo è un array contenente tutti i segmenti di scrittura a mano libera riconosciuti, una combinazione del carattere riconosciuto che identifica l'utente (grapheme) e della sua posizione nel testo riconosciuto (beginIndex, endIndex), nonché dei tratti e dei punti che l'hanno creato.

if (mostLikelyPrediction.segmentationResult) {
  mostLikelyPrediction.segmentationResult.forEach(
    ({ grapheme, beginIndex, endIndex, drawingSegments }) => {
      console.log(grapheme, beginIndex, endIndex);
      drawingSegments.forEach(({ strokeIndex, beginPointIndex, endPointIndex }) => {
        console.log(strokeIndex, beginPointIndex, endPointIndex);
      });
    },
  );
}

Potresti utilizzare queste informazioni per ritrovare i grafemi riconosciuti sulla tela.

Vengono disegnate delle caselle intorno a ogni grafema riconosciuto

Riconoscimento completo

Una volta completato il riconoscimento, puoi liberare risorse chiamando il metodo clear() su HandwritingDrawing e il metodo finish() su HandwritingRecognizer:

drawing.clear();
recognizer.finish();

Demo

Il componente web <handwriting-textarea> implementa un controllo di modifica migliorato progressivamente in grado di riconoscere la scrittura a mano libera. Facendo clic sul pulsante nell'angolo in basso a destra del controllo di modifica, attivi la modalità di disegno. Una volta completato il disegno, il componente web inizierà automaticamente il riconoscimento e aggiungerà di nuovo il testo riconosciuto al controllo di modifica. Se l'API Riconoscimento della scrittura a mano libera non è supportata o se la piattaforma non supporta le funzionalità richieste, il pulsante di modifica sarà nascosto. Tuttavia, il controllo di modifica di base rimane utilizzabile come <textarea>.

Il componente web offre proprietà e attributi per definire il comportamento del riconoscimento dall'esterno, tra cui languages e recognitiontype. Puoi impostare i contenuti del controllo tramite l'attributo value:

<handwriting-textarea languages="en" recognitiontype="text" value="Hello"></handwriting-textarea>

Per ricevere informazioni su eventuali modifiche al valore, puoi ascoltare l'evento input.

Puoi provare il componente seguendo questa demo su Glitch. Assicurati inoltre di dare un'occhiata al codice sorgente. Per utilizzare il controllo nella tua applicazione, ottienilo da npm.

Sicurezza e autorizzazioni

Il team di Chromium ha progettato e implementato l'API di riconoscimento della scrittura a mano libera utilizzando i principi fondamentali definiti nella sezione Controllo dell'accesso alle funzionalità avanzate della piattaforma web, tra cui controllo dell'utente, trasparenza ed ergonomia.

Controllo utente

L'API Riconoscimento della scrittura a mano libera non può essere disattivata dall'utente. È disponibile solo per i siti web pubblicati tramite HTTPS e può essere chiamato solo dal contesto di navigazione di primo livello.

Trasparenza

Il riconoscimento della scrittura a mano libera non viene indicato. Per impedire il fingerprinting, il browser implementa contromisure, come la visualizzazione di una richiesta di autorizzazione per l'utente quando rileva un possibile abuso.

Persistenza dell'autorizzazione

Al momento, l'API Riconoscimento della scrittura a mano libera non mostra richieste di autorizzazione. Pertanto, l'autorizzazione non deve essere in alcun modo persistente.

Feedback

Il team di Chromium vuole conoscere le tue esperienze con l'API Riconoscimento della scrittura a mano libera.

Parlaci della progettazione dell'API

C'è qualcosa nell'API che non funziona come previsto? Oppure mancano metodi o proprietà di cui hai bisogno per implementare la tua idea? Hai domande o commenti sul modello di sicurezza? Segnala un problema di specifica nel repository GitHub corrispondente o aggiungi la tua opinione su un problema esistente.

Segnalare un problema con l'implementazione

Hai rilevato un bug nell'implementazione di Chromium? Oppure l'implementazione è diversa dalle specifiche? Segnala un bug all'indirizzo new.crbug.com. Assicurati di includere il maggior numero possibile di dettagli e di semplici istruzioni per la riproduzione, quindi inserisci Blink>Handwriting nella casella Componenti. Glitch è ottimo per condividere riproduzioni facili e veloci.

Mostra il supporto per l'API

Hai intenzione di utilizzare l'API Riconoscimento della scrittura a mano libera? Il tuo supporto pubblico aiuta il team di Chromium a dare la priorità alle funzionalità e mostra ad altri fornitori di browser quanto sia fondamentale supportarle.

Condividi come pensi di utilizzarlo nel thread del discorso su WiCG. Invia un tweet a @ChromiumDev usando l'hashtag #HandwritingRecognition e facci sapere dove e come lo utilizzi.

Ringraziamenti

Questo articolo è stato esaminato da Joe Medley, Honglin Yu e Jiewei Qian. Immagine hero di Samir Bouaked su Unsplash.