L'API Handwriting Recognition ti consente di riconoscere il testo dall'input scritto a mano libera in tempo reale.
Che cos'è l'API Handwriting Recognition?
L'API Handwriting Recognition consente di convertire la scrittura a mano libera (inchiostro) degli utenti in testo. Alcuni sistemi operativi includono da tempo queste API e, con questa nuova funzionalità, le tue app web possono finalmente utilizzarle. La conversione avviene direttamente sul dispositivo dell'utente e funziona anche in modalità offline, il tutto senza aggiungere librerie o servizi di terze parti.
Questa API implementa il cosiddetto riconoscimento "on-line" o quasi in tempo reale. Ciò significa che l'input scritto a mano viene riconosciuto mentre l'utente lo disegna acquisendo e analizzando le singole tratti. A differenza delle procedure "off-line" come il riconoscimento ottico dei caratteri (OCR), in cui è noto solo il prodotto finale, gli algoritmi on-line possono fornire un livello di accuratezza superiore grazie a indicatori aggiuntivi come la sequenza temporale e la pressione dei singoli tratti di inchiostro.
Casi d'uso suggeriti per l'API Handwriting Recognition
Ecco alcuni esempi di utilizzo:
- Applicazioni per prendere appunti 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 la penna o il dito a causa di vincoli di tempo.
- Giochi che richiedono di inserire lettere o numeri, come cruciverba, gioco dell'impiccato o sudoku.
Stato attuale
L'API Handwriting Recognition è disponibile a partire da Chromium 99.
Come utilizzare l'API di riconoscimento della scrittura a mano libera
Rilevamento di funzionalità
Rileva il supporto del browser controllando l'esistenza del metodo createHandwritingRecognizer()
nell'oggetto navigator:
if ('createHandwritingRecognizer' in navigator) {
// 🎉 The Handwriting Recognition API is supported!
}
Concetti principali
L'API Handwriting Recognition converte l'input scritto a mano in testo, indipendentemente dal metodo di inserimento (mouse, tocco, penna). L'API ha quattro entità principali:
- Un punto rappresenta la posizione del cursore in un determinato momento.
- Un tratto è costituito da uno o più punti. La registrazione di un tratto inizia quando l'utente abbassa il cursore (ad es. fa clic sul pulsante principale del mouse o tocca lo schermo con la penna o il dito) e termina quando lo solleva di nuovo.
- Un disegno è costituito da uno o più tratti. Il riconoscimento effettivo avviene a questo livello.
- La funzione di riconoscimento è configurata con la lingua di inserimento prevista. Viene utilizzato per creare un'istanza di un disegno con la configurazione del riconoscitore applicata.
Questi concetti sono implementati come interfacce e dizionari specifici, che tratterò a breve.
Creazione di un riconoscimento
Per riconoscere il testo dall'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 a mano libera 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 si risolve con un'istanza di HandwritingRecognizer
quando il browser può soddisfare la tua richiesta. In caso contrario, rifiuterà la promessa con un errore e il riconoscimento della scrittura a mano non sarà disponibile. Per questo motivo, ti consigliamo di rivolgerti innanzitutto all'assistenza del sistema di riconoscimento per determinate funzionalità di riconoscimento.
Supporto per le query del riconoscitore
Chiamando navigator.queryHandwritingRecognizerSupport()
, puoi verificare se la piattaforma di destinazione supporta le funzionalità di riconoscimento della scrittura a mano libera che intendi utilizzare. Nell'esempio seguente, lo sviluppatore:
- Vuole rilevare testi in inglese
- ricevere previsioni alternative meno probabili, se disponibili
- accedere al risultato della segmentazione, ovvero ai caratteri riconosciuti, inclusi i punti e le linee 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 si 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 della tua applicazione oppure per modificare la query e inviarne una nuova.
Iniziare un disegno
All'interno della tua applicazione, devi offrire un'area di immissione in cui l'utente inserisce le voci scritte a mano. Per motivi di prestazioni, è consigliabile implementare questa funzionalità con l'aiuto di un oggetto canvas. L'implementazione esatta di questa parte non rientra nell'ambito di questo articolo, ma puoi consultare la demo per scoprire come si può fare.
Per iniziare un nuovo disegno, chiama il metodo startDrawing()
sul riconoscitore. Questo metodo riceve un oggetto contenente diversi suggerimenti 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 input con penna (
inputType
) - Il testo precedente (
textContext
) - Il numero di previsioni alternative meno probabili da restituire (
alternatives
) - Un elenco di caratteri identificabili dall'utente ("grafemi") che l'utente inserirà molto probabilmente
(
graphemeSet
)
L'API di riconoscimento della scrittura a mano libera è compatibile con gli eventi del cursore, che forniscono un'interfaccia astratta per utilizzare l'input di qualsiasi dispositivo di puntamento. Gli argomenti dell'evento del cursore contengono il tipo di cursore utilizzato. Ciò significa che puoi utilizzare gli eventi del cursore 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 assicurarmi che per il tipo di input del disegno vengano impostati solo i valori supportati.
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);
});
Aggiungere 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);
}
Aggiunge un punto
Dopo aver creato il tratto, devi aggiungere direttamente il primo punto. Poiché aggiungerai altri punti in un secondo momento, ha senso implementare la logica di creazione dei punti in un metodo separato. Nel
seguente esempio, il metodo addPoint()
calcola il tempo trascorso dal timestamp di riferimento.
Le informazioni temporali sono facoltative, ma possono migliorare la qualità del riconoscimento. Quindi, legge le coordinate X e Y dall'evento del cursore 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 eventi pointermove
viene chiamato quando il cursore viene spostato sullo schermo. Questi punti devono essere aggiunti anche al tratto. L'evento può essere attivato anche se il cursore non è in stato "giù", ad esempio quando si sposta il cursore sullo schermo senza premere il pulsante del mouse. Il gestore di eventi nell'esempio seguente controlla se esiste un tratto attivo e aggiunge il nuovo punto.
canvas.addEventListener('pointermove', (event) => {
if (activeStroke) {
addPoint(event);
}
});
Riconoscimento del testo
Quando l'utente solleva di nuovo il cursore, puoi aggiungere il tratto al disegno chiamando il metodo
addStroke()
. L'esempio seguente reimposta anche activeStroke
, pertanto l'handler pointermove
non aggiungerà punti al tratto completato.
A questo punto, è il momento di riconoscere l'input dell'utente chiamando il metodo getPrediction()
sul disegno. Il riconoscimento di solito richiede meno di qualche centinaio di millisecondi, quindi puoi eseguire ripetutamente le predizioni, 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 all'indicazione alternatives
. Puoi utilizzare questo array per presentare all'utente una scelta di possibili corrispondenze e chiedergli di selezionare un'opzione. In alternativa, puoi semplicemente utilizzare la previsione più probabile, che è ciò che faccio nell'esempio.
L'oggetto di previsione contiene il testo riconosciuto e un risultato di segmentazione facoltativo, che discuteremo nella sezione seguente.
Statistiche dettagliate con i risultati della segmentazione
Se supportato dalla piattaforma di destinazione, l'oggetto di previsione può contenere anche un risultato di segmentazione.
Si tratta di un array contenente tutti i segmenti di scrittura a mano libera riconosciuti, una combinazione del carattere identificabile dall'utente riconosciuto (grapheme
) e della sua posizione nel testo riconosciuto (beginIndex
, endIndex
), nonché dei tratti e dei punti che lo 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 rintracciare di nuovo i grafemi riconosciuti sulla tela.
Riconoscimento completo
Al termine del riconoscimento, puoi liberare le 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. Facendo clic sul pulsante nell'angolo in basso a destra del controllo di modifica, attivi la modalità di disegno. Al termine del disegno, il componente web avvia automaticamente il riconoscimento e aggiunge il testo riconosciuto al controllo di modifica. Se l'API di riconoscimento della scrittura a mano libera non è supportata o se la piattaforma non supporta le funzionalità richieste, il pulsante di modifica verrà nascosto. Tuttavia, il controllo di modifica di base rimane utilizzabile come <textarea>
.
Il componente web offre proprietà e attributi per definire il comportamento di 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 essere informato di eventuali modifiche al valore, puoi ascoltare l'evento input
.
Puoi provare il componente utilizzando questa demo su Glitch. Inoltre, dai 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 Handwriting Recognition utilizzando i principi fondamentali definiti in Controlling Access to Powerful Web Platform Features (Controllo dell'accesso a funzionalità potenti della piattaforma web), tra cui il controllo dell'utente, la trasparenza e l'ergonomia.
Controllo utente
L'API di 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
Non è presente alcuna indicazione se il riconoscimento della scrittura a mano libera è attivo. Per impedire il fingerprinting, il browser implementa contromisure, ad esempio la visualizzazione di una richiesta di autorizzazione all'utente quando rileva un possibile abuso.
Persistenza delle autorizzazioni
Al momento l'API di riconoscimento della scrittura a mano non mostra richieste di autorizzazione. Pertanto, l'autorizzazione non deve essere mantenuta in alcun modo.
Feedback
Il team di Chromium vuole conoscere la tua esperienza con l'API Handwriting Recognition.
Fornisci informazioni sul design 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? Invia una segnalazione relativa alle specifiche nel repository GitHub corrispondente o aggiungi il tuo parere a un problema esistente.
Segnalare un problema con l'implementazione
Hai trovato un bug nell'implementazione di Chromium? Oppure l'implementazione è diversa dalla specifica?
Segnala un bug all'indirizzo new.crbug.com. Assicurati di includere il maggior numero di dettagli possibile, istruzioni semplici per la riproduzione e inserisci Blink>Handwriting
nella casella Componenti.
Glitch è ideale per condividere riproduzioni rapide e semplici.
Mostra il supporto per l'API
Hai intenzione di utilizzare l'API di 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.
Spiega come prevedi di utilizzarlo nel thread di Discourse del WICG. Invia un tweet a
@ChromiumDev utilizzando l'hashtag
#HandwritingRecognition
e facci sapere dove e come lo utilizzi.
Link utili
- Spiegazione
- Bozza delle specifiche
- Repository GitHub
- ChromeStatus
- Bug di Chromium
- Revisione TAG
- Intent to Prototype
- Thread WebKit-Dev
- Posizione di Mozilla sugli standard
Ringraziamenti
Questo documento è stato esaminato da Joe Medley, Honglin Yu e Jiewei Qian.