Reconoce la escritura a mano de tus usuarios

La API de reconocimiento de escritura a mano te permite reconocer texto de entradas escritas a mano a medida que sucede.

¿Qué es la API de reconocimiento de escritura a mano?

La API de reconocimiento de escritura a mano te permite convertir la escritura a mano (con tinta) de tus usuarios en texto. Algunos sistemas operativos han incluido por mucho tiempo estas API y, con esta nueva capacidad, tus aplicaciones web pueden finalmente usar esta funcionalidad. La conversión se realiza directamente en el dispositivo del usuario y funciona incluso en modo sin conexión, todo sin agregar bibliotecas ni servicios de terceros.

Esta API implementa los servicios “en línea” o el reconocimiento casi en tiempo real. Esto significa que el se reconoce la entrada escrita a mano mientras el usuario la dibuja capturando y analizando la única brazadas. A diferencia de lo “sin conexión” como el reconocimiento óptico de caracteres (OCR), en los que solo se conoce el producto final, los algoritmos en línea pueden proporcionar un mayor nivel de precisión debido a indicadores adicionales, como la secuencia temporal y la presión de los trazos de tinta individuales.

Casos de uso sugeridos para la API de reconocimiento de escritura a mano

Estos son algunos ejemplos de usos:

  • Aplicaciones para tomar notas en las que los usuarios desean capturar notas escritas a mano y traducirlas y transformarlos en texto.
  • Aplicaciones de Formularios en las que los usuarios pueden utilizar lápiz o entrada con el dedo debido a limitaciones de tiempo
  • Juegos que requieren completar letras o números, como crucigramas, ahorcado o sudoku.

Estado actual

La API de reconocimiento de escritura a mano está disponible en Chromium 99.

Cómo usar la API de reconocimiento de escritura a mano

Detección de funciones

Para detectar la compatibilidad con el navegador, verifica la existencia del método createHandwritingRecognizer(). en el objeto Navigator:

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

Conceptos básicos

La API de reconocimiento de escritura a mano convierte la entrada de escritura a mano en texto, independientemente del método de entrada (mouse, toque, lápiz). La API tiene cuatro entidades principales:

  1. Un punto representa dónde se encontraba el puntero en un momento determinado.
  2. Un trazo consta de uno o más puntos. La grabación de un trazo comienza cuando el usuario coloca el puntero hacia abajo (es decir, hace clic en el botón principal del mouse o toca la pantalla con el lápiz o dedo) y finaliza cuando vuelven a levantar el puntero.
  3. Un dibujo consiste en uno o más trazos. El reconocimiento real se lleva a cabo en este nivel.
  4. El reconocidor está configurado con el idioma de entrada esperado. Se usa para crear una instancia de un dibujo con la configuración del reconocedor aplicada.

Estos conceptos se implementan como interfaces y diccionarios específicos, de los que hablaremos en breve.

Entidades principales de la API de reconocimiento de escritura a mano: uno o más puntos componen un trazo, uno o más trazos conforman un dibujo que crea el reconocedor. El reconocimiento real se realiza a nivel del dibujo.

Crea un reconocedor

Para reconocer texto de entradas escritas a mano, necesitas obtener una instancia de un HandwritingRecognizer llamando a navigator.createHandwritingRecognizer() y pasando restricciones que se les asigna. Las restricciones determinan el modelo de reconocimiento de escritura a mano que se debe usar. Actualmente, puede especificar una lista de idiomas en orden de preferencia:

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

El método muestra una promesa que se resuelve con una instancia de HandwritingRecognizer cuando la navegador puede completar tu solicitud. De lo contrario, rechazará la promesa con un error y El reconocimiento de escritura a mano no estará disponible. Por este motivo, quizás quieras consultar la compatibilidad del reconocedor para funciones de reconocimiento particulares primero.

Compatibilidad con el reconocedor de consultas

Llama a navigator.queryHandwritingRecognizerSupport() para verificar si la plataforma de destino admita las funciones de reconocimiento de escritura a mano que quieras usar. En el siguiente ejemplo, el desarrollador:

  • quiere detectar textos en inglés
  • Obtén predicciones alternativas y menos probables cuando estén disponibles.
  • obtener acceso al resultado de la segmentación, es decir, los caracteres reconocidos, incluidos los puntos y trazos que las componen
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

El método muestra una promesa que se resuelve con un objeto result. Si el navegador es compatible con la función especificado por el desarrollador, su valor se establecerá en true. De lo contrario, se establecerá como false. Puedes usar esta información para habilitar o inhabilitar ciertas funciones dentro de tu aplicación, o para ajusta tu consulta y envía una nueva.

Empieza a dibujar

Dentro de tu aplicación, debes ofrecer un área de entrada en la que el usuario escriba de entradas de registro. Por motivos de rendimiento, se recomienda implementarlo con la ayuda de un objeto lienzo. El nombre exacto de esta sección está fuera del alcance de este artículo, pero puedes consultar la demostración para ver cómo se puede hacer.

Para iniciar un nuevo dibujo, llama al método startDrawing() en el reconocedor. Este método toma un que contiene diferentes sugerencias para ajustar el algoritmo de reconocimiento. Todas las sugerencias son opcionales:

  • El tipo de texto que se ingresa: texto, direcciones de correo electrónico, números o un carácter individual (recognitionType)
  • El tipo de dispositivo de entrada: mouse, entrada táctil o lápiz (inputType)
  • El texto anterior (textContext)
  • La cantidad de predicciones alternativas menos probables que se deben mostrar (alternatives)
  • Una lista de caracteres de identificación del usuario ("grafemas") que es más probable que el usuario ingrese (graphemeSet)

La API de reconocimiento de escritura a mano funciona bien con Los eventos de puntero que proporcionan un interfaz abstracta para consumir entradas desde cualquier dispositivo apuntador. Los argumentos de eventos del puntero contienen el tipo de puntero que se usa. Esto significa que puedes usar eventos del puntero para determinar el tipo de entrada automáticamente. En el siguiente ejemplo, el dibujo para el reconocimiento de escritura a mano se agrega automáticamente Se crea la primera vez que se produce un evento pointerdown en el área de escritura a mano. Como pointerType puede estar vacío o establecido en un valor de propiedad, así que introduje una verificación de coherencia para hacer que asegúrate de que solo se establezcan valores admitidos para el tipo de entrada de dibujo.

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);
});

Cómo agregar un trazo

El evento pointerdown también es el lugar adecuado para comenzar un nuevo trazo. Para ello, crea una nueva instancia de HandwritingStroke. Además, debes almacenar la hora actual como punto de referencia para los puntos posteriores que se le agregaron:

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

Añada un punto

Después de crear el trazo, debes agregarle directamente el primer punto. A medida que vayas agregando puntos más adelante, tiene sentido implementar la lógica de creación de puntos en un método separado. En la En el siguiente ejemplo, el método addPoint() calcula el tiempo transcurrido a partir de la marca de tiempo de referencia. La información temporal es opcional, pero puede mejorar la calidad de reconocimiento. Luego, lee la X y Coordenadas Y del evento del puntero y agregan el punto al trazo actual.

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

Se llama al controlador de eventos pointermove cuando el puntero se mueve por la pantalla. Esos puntos deben agregarse al trazo. El evento también se puede generar si el puntero no está en una “abajo” estado, por ejemplo, cuando mueves el cursor por la pantalla sin presionar el mouse . El controlador de eventos del siguiente ejemplo verifica si existe un trazo activo y agrega el nuevo punto hacia él.

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

Reconoce texto

Cuando el usuario levante nuevamente el puntero, podrás agregar el trazo a tu dibujo llamando al addStroke(). En el siguiente ejemplo, también se restablece el activeStroke, por lo que pointermove el controlador no agregará puntos al trazo completado.

A continuación, es momento de reconocer la entrada del usuario llamando al método getPrediction() en el dibujo. El reconocimiento suele tardar menos de unos cientos de milisegundos, así que puedes ejecutarlo de forma repetida predicciones si es necesario. En el siguiente ejemplo, se ejecuta una predicción nueva después de cada trazo completado.

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));
});

Este método devuelve una promesa que se resuelve con un array de predicciones ordenadas por su más alta. La cantidad de elementos depende del valor que pasaste a la sugerencia alternatives. Tú podrías usar este array para presentar al usuario la opción de posibles coincidencias y pedirles que seleccionen una de 12 a 1 con la nueva opción de compresión. Como alternativa, puedes usar la predicción más probable, que es lo que hago en la ejemplo.

El objeto de predicción contiene el texto reconocido y un resultado de segmentación opcional, que analizaremos en la siguiente sección.

Estadísticas detalladas con resultados de segmentación

Si la plataforma de destino lo admite, el objeto de predicción también puede contener un resultado de segmentación. Este es un array que contiene todos los segmentos reconocidos de escritura a mano, una combinación de los caracteres carácter identificable para el usuario (grapheme), junto con su posición en el texto reconocido (beginIndex, endIndex) y los trazos y puntos que lo crearon.

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);
      });
    },
  );
}

Podrías usar esta información para volver a encontrar los grafemas reconocidos en el lienzo.

Se dibujan cajas alrededor de cada grafema reconocido

Reconocimiento completo

Después de que se complete el reconocimiento, puedes liberar recursos llamando al método clear() en el HandwritingDrawing y el método finish() en HandwritingRecognizer:

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

Demostración

El componente web <handwriting-textarea> implementa un mejorado progresivamente, control de edición capaz de escribir a mano el reconocimiento de imágenes. Si haces clic en el botón en la esquina inferior derecha del control de edición, activarás el modo de dibujo. Cuando completes el dibujo, el componente web iniciará automáticamente la reconocimiento y volver a agregarlo al control de edición. Si el botón de Reconocimiento de escritura a mano La API no es compatible o la plataforma no admite las funciones solicitadas, el botón Editar se ocultará. Sin embargo, el control de edición básico se puede seguir usando como <textarea>.

El componente web ofrece propiedades y atributos para definir el comportamiento de reconocimiento de la fuera, incluidos languages y recognitiontype. Puedes configurar el contenido del control mediante la Atributo value:

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

Para recibir información sobre cualquier cambio en el valor, puedes escuchar el evento input.

Puedes probar el componente con esta demostración de Glitch. Además, asegúrate de echar un vistazo a código fuente. Para usar el control en tu aplicación, obtenla de npm.

Seguridad y permisos

El equipo de Chromium diseñó e implementó la API de reconocimiento de escritura a mano utilizando los principios básicos se definen en Controla el acceso a las funciones potentes de la plataforma web, incluida la información la transparencia y la ergonomía.

Control de usuarios

El usuario no puede desactivar la API de reconocimiento de escritura a mano. Solo está disponible para los sitios web entregadas a través de HTTPS y solo se pueden llamar desde el contexto de navegación de nivel superior.

Transparencia

No hay indicación de si el reconocimiento de escritura a mano está activo. Para evitar la creación de huellas digitales, el navegador implementa contramedidas, como mostrar un mensaje de permiso al usuario cuando detecta posible abuso.

Persistencia de permisos

Actualmente, la API de reconocimiento de escritura a mano no muestra ningún mensaje de permisos. Por lo tanto, el permiso no necesita ser persistente de ninguna manera.

Comentarios

El equipo de Chromium quiere conocer tu experiencia con la API de reconocimiento de escritura a mano.

Cuéntanos sobre el diseño de la API

¿Algo en la API no funciona como esperabas? ¿O faltan métodos o propiedades que necesitas para implementar tu idea? Haz una pregunta o comentario sobre la seguridad modelo? Informa un problema de especificaciones en el repositorio de GitHub correspondiente o agrega lo que piensas a un problema existente.

Informar un problema con la implementación

¿Encontraste un error en la implementación de Chromium? ¿O la implementación es diferente de la especificación? Informa un error en new.crbug.com. Asegúrate de incluir tantos detalles como puedas instrucciones simples de reproducción y, luego, ingresa Blink>Handwriting en el cuadro Componentes. Glitch funciona muy bien para compartir repros rápidos y fáciles.

Demuestra compatibilidad con la API

¿Piensas usar la API de reconocimiento de escritura a mano? Tu asistencia pública ayuda al equipo de Chromium prioriza funciones y muestra a otros proveedores de navegadores la importancia de admitirlas.

Comparte cómo piensas usarlo en la conversación del discurso de WICG. Enviar un tweet a @ChromiumDev con el hashtag #HandwritingRecognition y cuéntanos dónde y cómo la utilizas.

Agradecimientos

Joe Medley, Honglin Yu y Jiewei Qian revisaron este artículo. Hero image de Samir Bouaked en Retiro: