Usando EASYOCR en video | Python – OpenCV

Por Administrador

¡Hola, hola Omesitos!. Bienvenidos a un nuevo tutorial. En el anterior post habíamos visto como usar easyocr para reconocer texto sobre una imagen, así que ahora veremos como hacerlo sobre un video y además calcularemos el número de fotogramas por segundo. ¡Comencemos!.

CONTENIDO:

  • Reconocimiento Óptico de Caracteres en video con easyocr
  • Instalación de packages
  • ¡Vamos con la programación!
  • Referencias

Reconocimiento Óptico de Caracteres en video con easyocr

Figura 1: Ejemplo de la aplicación de easyocr sobre un video.

En el anterior videotutorial donde vimos como utilizar easyocr sobre una imagen, me consultaron sobre si se podía emplear en videos, y eso es lo que veremos ahora. Vamos a plantearnos como problema a resolver el tener un video de entrada donde hay la presencia de papeles rectangulares con operaciones matemáticas simples, el objetivo será obtener el resultado.

Instalación de packages

Los módulos que vamos a utilizar son los mismos que vimos en el anterior videotutorial, 🔠 Reconocimiento Óptico de Caracteres (OCR) con EASYOCR | Python – OpenCV.

¡Vamos con la programación!

Para una explicación más detallada del programa que veremos a continuación, por favor dirígete al video que he preparado en mi canal, en donde explico paso a pasito cada procedimiento efectuado. ¡Anímate a verlo 😉!.

Vamos a realizar dos programas para apreciar la diferencia entre aplicar reconocimiento óptico de caracteres sobre cada fotograma y aplicando técnicas de visión por computador para extraer la región de interés en cada fotograma.

Para empezar, haremos el primer programa en el cual entregaremos cada fotograma a easyocr y calcularemos el número de fotogramas por segundo.

import cv2
import easyocr
import time

reader = easyocr.Reader(["en"], gpu=False)
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)

while True:
     ret, frame = cap.read()
     if ret == False:
          break
     start = time.time()
     result = reader.readtext(frame)
     for res in result:
          print(res)
          pt0 = int(res[0][0][0]), int(res[0][0][1])
          pt2 = int(res[0][2][0]), int(res[0][2][1])
          cv2.rectangle(frame, pt0, pt2, (0, 255, 0), 2)

          if "=" in res[1] and ("+" in res[1] or "*" in res[1] or "/" in res[1]):
               operation_result = eval(res[1][:-1])
               cv2.putText(frame, res[1] + str(operation_result), (10, 40), 1, 2.4, (166, 56, 242), 4)

     end = time.time()
     fps = 1 / (end - start)
     cv2.putText(frame, "FPS: {:.2f}".format(fps), (20, 400), 1, 2, (0, 255, 0), 2)
     cv2.imshow("Frame", frame)
     k = cv2.waitKey(1) & 0xFF
     if k == 27:
          break

cap.release()
cv2.destroyAllWindows()

Al ejecutar el programa obtendremos lo siguiente:

Figura 2: Visualización de la aplicación de easyocr sobre un video.

En la figura 2 podemos ver los resultados de aplicar easyocr sobre la imagen. Entonces el propio módulo detecta el texto y de este hemos resuelto la operación, que se muestra en la parte superior izquierda de la imagen. Sin embargo, si analizamos el número de fotogramas por segundo es bastante bajo. En este ejemplo obtenemos 0.48, ¿qué quiere decir?, esto nos quiere decir que por segundo no se está procesando ni una imagen, le lleva mucho más de 1 segundo procesar una sola imagen. 

NOTA: La visión humana puede percibir movimiento cuando existen más de 12 fotogramas por segundo. A un menor número de fps, se percibe como imágenes separadas. (Fuente)

Ahora vamos por el segundo programa, en este analizaremos un poco más la imagen de entrada. Tenemos hojas de color blanco que contrastan con el fondo de la imagen, además estas presentan forma rectangular y son de tamaño muy similar, así que podemos extraer de la imagen únicamente el área de la hoja. Vamos con el programa:

import cv2
import numpy as np
import easyocr
import time

def ordenar_puntos(puntos):
    n_puntos = np.concatenate([puntos[0], puntos[1], puntos[2], puntos[3]]).tolist()

    y_order = sorted(n_puntos, key=lambda n_puntos: n_puntos[1])

    x1_order = y_order[:2]
    x1_order = sorted(x1_order, key=lambda x1_order: x1_order[0])

    x2_order = y_order[2:4]
    x2_order = sorted(x2_order, key=lambda x2_order: x2_order[0])
    
    return [x1_order[0], x1_order[1], x2_order[0], x2_order[1]]
    
reader = easyocr.Reader(["en"], gpu=False)
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)

while True:
     ret, frame = cap.read()
     if ret == False:
          break
     start = time.time()
     gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
     canny = cv2.Canny(gray, 50, 150)
     canny = cv2.dilate(canny, None, iterations=1)
     #cv2.imshow("Canny", canny)
     cnts = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
     cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:1]

     for c in cnts:
          epsilon = 0.01*cv2.arcLength(c,True)
          approx = cv2.approxPolyDP(c,epsilon,True)
          
          if len(approx)==4:
               cv2.drawContours(frame, [approx], 0, (0,255,255),2)
               
               puntos = ordenar_puntos(approx)

               cv2.circle(frame, tuple(puntos[0]), 7, (255,0,0), 2)
               cv2.circle(frame, tuple(puntos[1]), 7, (0,255,0), 2)
               cv2.circle(frame, tuple(puntos[2]), 7, (0,0,255), 2)
               cv2.circle(frame, tuple(puntos[3]), 7, (255,255,0), 2)
               
               pts1 = np.float32(puntos)
               pts2 = np.float32([[0,0],[270,0],[0,70],[270,70]])
               M = cv2.getPerspectiveTransform(pts1,pts2)
               dst = cv2.warpPerspective(gray,M,(270,70))
               dst = cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)
               #cv2.imshow('dst', dst)

               result = reader.readtext(dst)
               for res in result:
                    print(res)
                    if "=" in res[1] and ("+" in res[1] or "*" in res[1] or "/" in res[1]):
                         operation_result = eval(res[1][:-1])
                         cv2.putText(frame, res[1] + str(operation_result), (10, 40), 1, 2.4, (166, 56, 242), 4)
     end = time.time()
     fps = 1 / (end - start)
     cv2.putText(frame, "FPS: {:.2f}".format(fps), (20, 400), 1, 2, (0, 255, 0), 2)
     cv2.imshow('Frame', frame)
     k = cv2.waitKey(1) & 0xFF
     if k == 27:
          break
cap.release()
cv2.destroyAllWindows()

El proceso que hemos realizado es similar al que habíamos hecho en ? Escáner de documentos + ? reconocimiento de texto (OCR) ?| OpenCV con Python y Transformación de perspectiva | OpenCV con Python. Si ejecutamos el programa, obtendríamos lo siguiente:

Figura 3: Visualización de la aplicación de easyocr sobre el área de interés.

En la figura 3 tenemos los resultados del segundo programa. Podemos apreciar que en primer lugar se ubica el papel que contiene la operación, entonces se recorta y alinea esta imagen. Sobre esta última es que se aplica easyocr y obtenemos el resultado que podemos ver en la sección superior izquierda.

Pero además podemos analizar el número de fotogramas por segundo. Gracias a esta serie de procesos hemos podido elevar a 3.3 fps, lo que nos quiere decir que ahora se están analizando 3 imágenes por segundo, mucho mayor a lo que teníamos en el anterior programa.

Esta ha sido una alternativa que quería presentarles para mejorar la respuesta en cuanto al uso de easyocr en video, sin usar GPU. También podrías aplicar otras técnicas de visión por computador para mejorar la respuesta.

Y bien, esto ha sido todo por el tutorial de hoy. ¡Espero que te haya gustado! 😊 Nos vemos en el siguiente… ¡Qué te vaya súper bien!.

Referencias

📎 Video anterior: https://youtu.be/0OBAAPvG4XU
📎 Escáner de documentos + reconocimiento de texto (OCR): https://youtu.be/iAnCUJvNCGY
📎 Post: https://omes-va.com/escaner-de-documentos-reconocimiento-de-texto/