Group 10
Da Imagem à Palavra: Explorando Textos com EasyOCR e OpenCV

Ana Carolina

Postado em 09 ago, 2023

  • OpenCV
  • Visão Computacional
  • OCR

Contextualizando

OCR significa "Optical Character Recognition" ou "Reconhecimento Ótico de Caracteres". É uma tecnologia que permite a digitalização de textos em documentos físicos, como imagens ou páginas impressas, em texto digital.

OpenCV significa "Open Source Computer Vision Library" ou "Biblioteca de Visão Computacional de Código Aberto". É uma biblioteca que oferece funções e algoritmos para processamento de imagens e visão computacional

Ps: Essa é uma versão simplificada de outro projeto que trabalha com a qualidade e orientação das imagens.

Nesse artigo vamos extrair textos dessa foto do curso:

Iniciando somente com o EasyOCR:

import easyocr

reader = easyocr.Reader(['pt'])
reader = easyocr.Reader(['pt','pt'], gpu=True)
 result = reader.readtext('fotocurso.png', detail='False')

for res in result:
     print(res)

Assim obtemos o seguinte output:

([[907, 907], [1017, 907], [1017, 933], [907, 933]], 'Cênciada', 0.5145408411218583) ([[908, 927], [1000, 927], [1000, 948], [908, 948]], '(omrut?', 0.36136108648684784) ([[720, 1106], [989, 1106], [989, 1318], [720, 1318]], 'KL', 0.4091815058853481) ([[442, 1313], [1125, 1313], [1125, 1417], [442, 1417]], 'CODE TOWER', 0.6197818725078946) ([[1225, 1254], [1701, 1254], [1701, 1555], [1225, 1555]], 'C', 0.9684747166574859) ([[1754, 1271], [2329, 1271], [2329, 1432], [1754, 1432]], 'CIÊNCIA DA', 0.9962903181443976) ([[2743, 1391], [2955, 1391], [2955, 1440], [2743, 1440]], 'INSTIIUTO', 0.5065471089454394) ([[2762, 1423], [2942, 1423], [2942, 1471], [2762, 1471]], 'FEDERAL', 0.8186429013654711) ([[2814, 1464], [2896, 1464], [2896, 1495], [2814, 1495]], 'Goiás', 0.9206229007627292) ([[1753, 1424], [2630, 1424], [2630, 1583], [1753, 1583]], 'COMPUTAÇÃO', 0.5540302378284719) ([[2795, 1504], [2924, 1504], [2924, 1577], [2795, 1577]], 'Câapols', 0.4230541471485723) ([[2145.013606076168, 727.0816364570071], [2231.7234365066056, 747.1993682900567], [2217.986393923832, 798.9183635429929], [2131.2765634933944, 778.8006317099433]], 'FV"', 0.06376217939419207) ([[2545.470001059997, 1010.152001695995], [2569.962964019714, 1014.73037007448], [2566.529998940003, 1027.8479983040052], [2543.037035980286, 1022.26962992552]], 'a0', 0.2917875464364398)

Assim fica difícil entender o que aconteceu, né? Então ai que entra o OpenCV com ele vamos demarcar a área da leitura e adicionar o resultado na imagem:

...
import cv2
...
result = reader.readtext(image, detail='False')

for res in result:
    top_left = tuple(res[0][0]) 
    bottom_right = tuple(res[0][2])
    cv2.rectangle(image, top_left, bottom_right, (255, 0, 0), 2) 
    cv2.putText(image, res[1], (top_left[0], top_left[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
    print(res)
    
cv2.imshow('Resultado', image)
cv2.imwrite('resultado.png', image)
cv2.waitKey(0)  

Para evitar o erro:

cv2.error: OpenCV(4.8.0) 👎 error: (-5:Bad argument) in function 'rectangle'

Isso acontece quando o retângulo não possui as dimensões corretas, ou uma das laterais está maior que a imagem ou as coordenadas são inválidas.

Vamos entender melhor o comportamento do posicionamento no OpenCV

Aqui nosso 'frame' fica localizado no 4° quadrante, e é nele que vamos posicionar nossos objetos:

Para desenhar esse retângulo fornecemos (x1,y1) e (x2,y2) em cv2.rectangle

Então vamos ignorar retângulos que não forem válidos adicionando:

try:
    print(res)
    cv2.rectangle(image, top_left, bottom_right, (255, 0, 0), 2) 
    cv2.putText(image, res[1], (top_left[0], top_left[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
except Exception as e:
    print(e)

Fazendo com que nosso novo output se pareça com isso:

([[906, 905], [1017, 905], [1017, 934], [906, 934]], 'cênciada', 0.9194093133914393) ([[908, 927], [1000, 927], [1000, 948], [908, 948]], '(omrut?', 0.32191579504804385) ([[2547, 1014], [2568, 1014], [2568, 1027], [2547, 1027]], '40', 0.29109037076239486) ([[723, 1112], [971, 1112], [971, 1309], [723, 1309]], 'IL', 0.41506575775035626) ([[441, 1312], [1130, 1312], [1130, 1421], [441, 1421]], 'CODE TOWER', 0.9989489047445782) ([[1220, 1261], [1689, 1261], [1689, 1552], [1220, 1552]], 'C', 0.9791617707792852) ([[1754, 1271], [2326, 1271], [2326, 1432], [1754, 1432]], 'CIÊNCIA DA', 0.9957832139217082) ([[2743, 1391], [2955, 1391], [2955, 1440], [2743, 1440]], 'INSTIIUTO', 0.552711672923763) ([[2762, 1423], [2942, 1423], [2942, 1471], [2762, 1471]], 'FEDERAL', 0.8030398935242598) ([[2814, 1464], [2896, 1464], [2896, 1495], [2814, 1495]], 'Goiás', 0.6839087502213124) ([[1753, 1425], [2633, 1425], [2633, 1582], [1753, 1582]], 'COMPUTAÇÃO', 0.8723647770468417) ([[2798, 1507], [2917, 1507], [2917, 1546], [2798, 1546]], 'Câmpus', 0.9998796449092232) ([[2799, 1538], [2921, 1538], [2921, 1574], [2799, 1574]], 'Anápolis', 0.999987524500607)

Ps: A fonte FONT_HERSHEY_SIMPLEX não suporta caracteres especiais, uma opção é usar o módulo Draw.text() do Pillow

Aplicando tratamento de imagem

Nesse caso não tivemos a necessidade de aplicar nenhum tratamento de imagem, mas já vou apresentar um caso sua imagem precise:

import cv2

img = cv2.imread('fotocurso.png', cv2.IMREAD_GRAYSCALE)
image = cv2.adaptiveThreshold(img, 255 ,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
 cv2.THRESH_BINARY,7,7)

cv2.imwrite("resultado.png", image)

Lembre-se que existem vários tratamentos que podem ser aplicados, mas é necessário que você identifique o que mais atende seu problema em específico.