marzo 18, 2022 10:00 am

Jesús

Sabemos cómo localizar y extraer texto de imágenes en condiciones ideales usando Tesseract.

También sabemos cómo usar EAST para localizar texto en circunstancias más complejas, con la ayuda de OpenCV.

Uno de los problemas de EAST, como descubrimos en el post pasado, es que es excelente localizando texto, pero no extrayéndolo. 

En otras palabras, podemos determinar dónde está, pero no qué dice.

Hoy cambiaremos esta situación, ya que combinaremos los poderes de Tesseract y OpenCV en un único pipeline de procesamiento que nos facilitará localizar y leer texto en una gran variedad de condiciones.

Al final de este artículo sabrás:

  • Cómo usar EAST en OpenCV para localizar texto en una imagen.
  • Cómo extraer el texto detectado por EAST.
  • Preprocesar el texto.
  • Usar Tesseract para hacer OCR del texto.

¡ATENTO!

Buena parte del código que veremos en este artículo, así como la explicación del mismo, se encuentra en estos dos artículos:

Por tal razón, te recomiendo fuertemente que leas ambos tutoriales antes de continuar, pues asumiremos que ya estás familiarizado con el código y su funcionamiento

¡Pongámonos manos a la obra!

Creación del Entorno de Desarrollo con Anaconda

Observemos la estructura del proyecto:

Estructura del proyecto

Nuestra implementación vivirá en el archivo datasmarts/ocr_pipeline.py. En la siguiente sección iremos armando paso a paso nuestra solución.

En la carpeta images hay varias fotos de prueba que usaremos para evaluar nuestra solución, mientras que en resources se halla el archivo frozen_east_text_detection.pb, correspondiente a la red neuronal EAST ya entrenada.

Para descargar el proyecto, simplemente llena el formulario de abajo:

A continuación crearemos el entorno de desarrollo con Anaconda, para lo que primero deberemos ubicarnos en la raíz del proyecto. Desde ahí ejecuta este comando:

conda env create -f opencv-rotated-text-detection

La configuración del ambiente (opencv-tesseract-ocr-pipeline) es la que sigue:

Para activar el ambiente, corre este comando:

conda activate opencv-tesseract-ocr-pipeline

Pasemos a la próxima sección, ¿vale?

Localización y OCR de Texto con OpenCV y Tesseract

Abre el archivo datasmarts/ocr_pipeline.py, e inserta estas líneas para importar las dependencias del programa:

Después, definimos las capas de la red EAST en las cuales estamos interesados:

Si estás trabajando en Windows, es posible que tengas que añadir esta línea para que el script funcione:

Evidentemente, cambia la ruta para que apunte a la ubicación del ejecutable tesseract.exe en tu máquina. 

Si usas Ubuntu/Debian o macOS, puedes ignorar este paso.

Definamos la función auxiliar cleanup_text(), la cual filtra caracteres que no pertenezcan al estándar ASCII, ya que OpenCV no puede mostrar caracteres Unicode:

Seguidamente, definiremos la función decode_precitions(), la cual se usa para convertir la salida de EAST en detecciones que podamos usar (una explicación más detallada se encuentra aquí):

Ahora, definimos los argumentos del programa:

Estos son:

  • -i/--image: Ruta a la imagen de entrada.
  • -e/--east: Ruta al archivo del detector EAST.
  • -w/--width: Ancho de la imagen redimensionada. Ha de ser múltiplo de 32 (por defecto es 320).
  • -t/--height: Altura de la imagen redimensionada. Ha de ser múltiplo de 32 (por defecto es 320).
  • -c/--min-confidence: Probabilidad mínima necesaria para inspeccionar una región.
  • -n/--nms-threshold: Umbral para aplicar NMS.
  • -p/--padding: Cantidad de margen (padding) que agregaremos a cada borde de una ROI.
  • -s/--sort: Si debemos ordenar las detecciones de izquierda a derecha (left-to-right) o de arriba hacia abajo (top-to-bottom).

Cargamos la imagen y la mostramos en pantalla:

Extraemos sus dimensiones:

Computamos las nuevas dimensiones de la imagen con base a los argumentos de entrada, y calculamos el ratio entre las dimensiones viejas y nuevas:

Cargamos el detector EAST en OpenCV, mediante cv2.dnn.readNet():

Transformamos la imagen en un blob, la normalizamos y la pasamos por la red:

Nota que la red nos retorna los scores y las geometrías. Usaremos ambos resultados para calcular las cajas de las detecciones más adelante. De momento, imprimimos cuánto tardó el detector en hacer su trabajo:

Usando la función auxiliar decode_predictions(), obtenemos los rectángulos y sus probabilidades asociadas. También aplicamos NMS, quedándonos con los índices de las detecciones que sobrevivieron:

Iteramos sobre las detecciones restantes, y almacenaremos los resultados en las lista results. Para cada detección, computamos las esquinas del rectángulo asociado a la misma:

Como Tesseract solo funciona sobre rectángulos normales, tenemos que ajustar las detecciones de EAST consecuentemente. Primero, hallamos el rectángulo “derecho” correcto asociado a esta detección:

Luego, aplicamos padding para potencialmente mejorar los resultados de Tesseract:

Después, extremos el ROI y lo pasamos por Tesseract para obtener el texto:

Agregamos el texto a la lista de resultados:

Organizamos las detecciones con base al parámetro --sort:

Iteramos sobre los resultados, imprimiendo el texto en la consola, y dibujando la detección + texto en la imagen original:

Finalmente, destruimos las ventanas creadas durante la ejecución del programa:

¡ATENTO!

Antes de ejecutar el código, asegúrate de hallarte en la raíz del proyecto para que los comandos funcionen correctamente.

Ejecuta el programa así:

python datasmarts/ocr_pipeline.py -i images/sign.jpg -e resources/frozen_east_text_detection.pb

Veremos primero la imagen original:

Señal de STOP! 

Y luego, la imagen con la detección de la red EAST, la cual incluye correctamente el texto “ALTO”:

Texto detectado: ALTO

Y en la consola un mensaje así:

Cargando el detector EAST...
La detección se demoró 0.113732 segundos.
ALTO

Como vemos, la red no se tardó casi nada, y el resultado fue perfecto. Vale la pena destacar que, efectivamente, el texto en la imagen se encuentra rotado, ya que el rectángulo que rodea a la detección tiene una inclinación notable.

Cool, ¿no?

Resumen

En este post aprendimos a combinar las capacidades de localización de texto, tanto de Tesseract como de OpenCV.

Como sabemos, Tesseract es bueno localizando y extrayendo texto de imágenes relativamente simples, mientras que, por su parte, OpenCV (mediante EAST) es mucho más robusto en cuanto a localización se refiere, pero carece de la capacidad de aplicar OCR per se.

La respuesta, claramente, yace en la unión de ambas librerías para crear un pipeline de procesamiento end-to-end para hacer OCR de texto en condiciones adversas o, al menos, no ideales.

Como notamos en las secciones anteriores, este tándem brinda resultados fantásticos.

¿Por qué no lo compruebas por ti mismo descargando el código aquí abajo?

¡Hasta pronto!

Sobre el Autor

Jesús Martínez es el creador de DataSmarts, un lugar para los apasionados por computer vision y machine learning. Cuando no se encuentra bloggeando, jugando con algún algoritmo o trabajando en un proyecto (muy) cool, disfruta escuchar a The Beatles, leer o viajar por carretera.