marzo 16, 2022 10:00 am

Jesús

En un artículo anterior aprendimos a usar Tesseract para localizar texto en una imagen.

No obstante, hay dos cosas que posiblemente habrás notado:

  • Solo usamos Tesseract, lo cual es extraño ya que, como bien sabemos, su especialidad es la “lectura” de texto, no el procesamiento de imágenes o la detección de objetos.
  • Solo nos enfocamos en localizar texto en condiciones ideales (es decir, cuando éste se encuentra perfectamente alineado).

¿Qué pasa si el texto está rotado? Como hemos visto a lo largo de esta serie, las condiciones ideales rara vez coinciden con las condiciones reales, así que tenemos que saber qué hacer cuando un desafío se nos presenta.

Afortunadamente, en el presente post aprenderemos a lidiar con circunstancias más complejas cuando de localizar texto se trata, todo con la ayuda de un viejo amigo: OpenCV.

Al final de este artículo sabrás:

  • Por qué la detección de texto en la vida real es tan desafiante.
  • Cómo usar el detector EAST en OpenCV para localizar texto en situaciones cotidianas.
  • Cómo decodificar las detecciones de la red EAST para poderlas mostrar como resultados en una imagen.

¿Listo? Si es así, comencemos.

¿Por Qué es Difícil Detectar Texto en la Vida Real?

Detectar texto cuando controlamos las condiciones en las que se tomó la foto es jugar el juego en modo fácil.

Lo verdaderamente bueno empieza cuando tratamos de aplicar a OCR a imágenes tomadas en condiciones variantes, como aquellas que capturamos con nuestro smartphone.

¿Por qué? He aquí algunas de las razones:

  • Ruido del sensor o en la imagen: No todas las cámaras usan los sensores de la más alta calidad, ni los algoritmos de pre y pos procesamiento más avanzados, lo que conduce a cierta cantidad de “ruido” en el producto final.
  • Ángulos de vista: Rara vez tomamos una imagen perfectamente perpendicular al texto capturado, así que tenemos que tener en cuenta cierta deformación producto del ángulo de captura de las fotos.
  • Imágenes borrosas: Esto suele pasar cuando la cámara (típicamente de un smartphone) no controla adecuadamente la estabilización o iluminación.
  • Pobres condiciones de iluminación.
  • Resolución: Como ya hemos dicho, no todas las cámaras toman imágenes de la mejor calidad, por el simple hecho de que no todas usan los mejores componentes.
  • Objetos no planos: Si tratamos de leer el texto de una etiqueta de una botella, que es cilíndrica, claramente tendremos que lidiar con un grado de distorsión considerable (y así en muchas otras circunstancias similares).

Como verás, los desafíos de leer texto “in the wild” son numerosos, pero afortunadamente contamos con un aliado robusto: el detector EAST. Hablemos un poco más al respecto.

Detector de Texto Basado en Deep Learning, EAST

Al igual que sucede con muchos otros campos dentro y fuera de computer vision, la detección de texto se ha visto vastamente potenciada por deep learning.

Uno de los máximos exponentes en esta área se conoce como EAST: Efficient and Accurate Scene Text Detector o, en español, Detector Eficiente y Preciso de Texto de Escena.

He aquí varios de los rasgos principales de EAST:

  • Puede detectar palabras y líneas de texto en orientaciones arbitrarias.
  • Trabaja sobre imágenes de 720p.
  • Corre a 13 FPS.
  • Se trata de un modelo end-to-end, lo que lo hace más eficiente, ya que no hay que aplicar procesos más lentos y arcaicos como la pirámide de imágenes o ventanas deslizantes.

Estructura de nuestro detector de texto FCN (Fully Convolutional Network)

Arriba puedes ver la arquitectura general del detector. Si deseas aprender más al respecto, lo mejor que puedes hacer es leer la publicación oficial aquí.

Creación del Entorno de Desarrollo con Anaconda

Observemos la estructura del proyecto:

Estructura del proyecto

Nuestra implementación vivirá en el archivo datasmarts/localize.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-rotated-text-detection) es la que sigue:

Para activar el ambiente, corre este comando:

conda activate opencv-rotated-text-detection

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

Localización de Texto Rotado con OpenCV

Abre el archivo datasmarts/localize.py e inserta estas líneas, las cuales importan las dependencias del proyecto:

A continuación especificamos los nombres de la red EAST que nos interesan:

Buena parte del trabajo pesado tiene que ver con la decodificación de las predicciones. Por tal motivo, implementaremos la función auxiliar decode_predictions() paso a paso, la cual nos asistirá en esta tarea:

En el extracto de arriba vemos que la función acepta estos inputs:

  • scores: Un volumen que contiene la probabilidad de que una determinada región contenga un texto.
  • geometry: Mapa usado para derivar las coordenadas del rectángulo que rodea al texto en la imagen de entrada.
  • min_confidence: Probabilidad mínima de una detección para considerarse válida.

También definimos dos arreglos para almacenar las coordenadas de los rectángulos de las detecciones, y la probabilidad asociada a cada una de ellas, respectivamente.

Luego, iteraremos sobre cada fila en scores, extrayendo las probabilidades, así como la data geométrica usada para derivar los rectángulos que rodean a las detecciones potenciales:

Fíjate que de la geometría también extraemos el ángulo de rotación de la detección.

Lo próximo es iterar sobre las columnas en scores, extrayendo el puntaje específico de la detección en la interacción actual. Si no es suficientemente alto, la desechamos. Si sí, entonces tenemos que hacer un montón de cálculos:

Lo primero que tenemos que hacer es calcular el desfase, ya que los resultados de la red serán 4 veces más pequeños que la imagen de entrada:

Luego, extraemos el ángulo de rotación y lo usamos para calcular el seno y el coseno del mismo, valores que necesitaremos más adelante:

Derivamos las dimensiones del rectángulo:

Usando el desfase, y el seno y el coseno del ángulo de rotación, podemos calcular el desfase y ángulo de rotación generales del rectángulo de la detección:

Con el desfase, el seno y el coseno, derivamos las coordenadas de interés del rectángulo: esquina superior izquierda y centro:

Añadimos las coordenadas del rectángulo y su probabilidad a las listas respectivas:

Una vez completadas las iteraciones, retornamos los resultados:

Con eso culminamos la implementación de la función auxiliar. Lo que nos queda es completar la carpintería básica para poder detectar texto dada una imagen de entrada. Primero definimos los parámetros 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.

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 los resultados, y los dibujamos sobre la imagen original:

Finalmente, mostramos el resultado y destruimos las ventanas creadas en el proceso:

¡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/localize.py -i images/sign.jpg -e resources/frozen_east_text_detection.pb

Veremos primero la imagen original:

Y luego, la imagen con la detección de la red EAST:

Y en la consola un mensaje así:

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

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.

Resumen

En este artículo aprendimos cómo utilizar el detector EAST en OpenCV para localizar texto en condiciones no ideales.

A diferencia de la localización de texto con Tesseract, el detector EAST es mucho más robusto, siendo capaz de lidiar con texto en múltiples condiciones. 

El lado malo es que usar EAST es una tarea no trivial, como pudimos evidenciar, especialmente cuando se trata de decodificar los resultados.

Otra cosa que vale la pena mencionar es que si bien Tesseract funciona en condiciones ideales, aparte de darte los rectángulos de las detecciones, también te entrega el texto como tal, mientras que EAST se limita a localizar, más no a aplicar OCR per se.

¿Por qué no te descargas el código y experimentas con las imágenes restantes? O, mejor aún, con las tuyas propias:

¡Hasta luego!

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.