Pular para o conteúdo principal

Um tutorial abrangente sobre reconhecimento óptico de caracteres (OCR) em Python com Pytesseract

Domine os fundamentos do reconhecimento óptico de caracteres em OCR com PyTesseract e OpenCV.
Actualizado 16 de jan. de 2025  · 11 min de leitura

Por que aprender o reconhecimento óptico de caracteres (OCR)?

A extração manual de texto de imagens e documentos pode ser muito tediosa e demorada. Felizmente, o OCR (Optical Character Recognition, reconhecimento óptico de caracteres) pode automatizar esse processo, permitindo que você converta essas imagens em arquivos de texto editáveis e pesquisáveis.

As técnicas que você está prestes a aprender podem ser aplicadas em muitos aplicativos:

  • Transformando documentos físicos em digitais: Converta documentos digitalizados, PDFs ou fotos de texto em arquivos editáveis e pesquisáveis.
  • Automatizar a entrada de dados: Extraia informações de formulários, faturas, recibos e outros documentos para preencher automaticamente bancos de dados ou planilhas.
  • Melhorar a acessibilidade: Crie versões de texto digital de livros, menus ou placas para pessoas com deficiências visuais. As ferramentas de conversão de texto em fala podem ser usadas para ler o texto em voz alta.
  • Carros autônomos: Reconhecer sinais de trânsito e placas de veículos para uma navegação segura.

O tutorial se concentrará no mecanismo de OCR do Tesseract e em sua API Python - PyTesseract. Antes de começarmos a escrever o código, vamos analisar brevemente algumas das bibliotecas populares dedicadas ao OCR.

As principais bibliotecas de OCR de código aberto em Python

Como o OCR é um problema popular e contínuo, muitas bibliotecas de código aberto tentam resolvê-lo. Nesta seção, abordaremos os que ganharam mais popularidade devido ao seu alto desempenho e precisão.

Tesseract

O Tesseract OCR é um mecanismo de reconhecimento óptico de caracteres de código aberto que é o mais popular entre os desenvolvedores. Como as outras ferramentas desta lista, o Tesseract pode pegar imagens de texto e convertê-las em texto editável.

Vantagens

  • Biblioteca amplamente utilizada e madura com uma grande comunidade
  • Suporta mais de 100 idiomas
  • Gratuito e de código aberto

Desvantagens

  • A precisão pode ser menor em comparação com algumas soluções baseadas em aprendizagem profunda
  • Opções de configuração limitadas

OCR fácil

O EasyOCR é uma biblioteca Python projetada para o reconhecimento óptico de caracteres (OCR) sem esforço. Ele faz jus ao seu nome, oferecendo uma abordagem fácil de usar para a extração de texto de imagens.

Vantagens

  • Fácil de usar e de configurar
  • Alta precisão com modelos de aprendizagem profunda
  • Suporta vários idiomas prontos para uso

Desvantagens

  • Depende de modelos pré-treinados, que podem ser grandes
  • Pode ser mais lento do que o Tesseract para tarefas mais simples

Keras OCR

O Keras-OCR é uma biblioteca Python criada com base no Keras, uma estrutura popular de aprendizagem profunda. Ele fornece modelos de OCR prontos para uso e um pipeline de treinamento de ponta a ponta para criar novos modelos de OCR.

Vantagens

  • Abordagem baseada em aprendizagem profunda, oferecendo alta precisão para vários tipos de texto
  • Seleção e treinamento de modelos personalizáveis
  • Pode ser mais preciso em layouts complexos ou texto manuscrito

Desvantagens

  • Requer GPU para um desempenho ideal
  • Curva de aprendizado mais acentuada devido à sua natureza de aprendizado profundo
  • O treinamento de modelos personalizados pode consumir muito tempo

Aqui está uma tabela que resume suas diferenças, vantagens e desvantagens:

Nome do pacote

Vantagem

Desvantagens

Tesseract (pytesseract)

Maduro, amplamente utilizado, com amplo suporte

Mais lento e com menor precisão em layouts complexos

EasyOCR

Simples de usar, vários modelos

Menor precisão, personalização limitada

Keras-OCR

Maior precisão, personalizável

Requer GPU, curva de aprendizado mais acentuada

Neste tutorial, vamos nos concentrar em PyTesseract, que é a API Python do Tesseract. Aprenderemos a extrair texto de imagens simples, a desenhar caixas delimitadoras ao redor do texto e a realizar um estudo de caso com um documento digitalizado.

Um guia passo a passo para OCR com PyTesseract e OpenCV

Instalação

O PyTesseract funciona com base no mecanismo oficial do Tesseract, que é um software CLI separado. Antes de instalar o pytesseract, você deve ter o mecanismo instalado. Abaixo estão as instruções de instalação para diferentes plataformas.

Para Ubuntu ou WSL2 (minha escolha):

$ sudo apt update && sudo apt upgrade
$ sudo apt install tesseract-ocr
$ sudo apt install libtesseract-dev

Para Mac usando o Homebrew:

$ brew install tesseract

Para Windows, siga as instruções desta página do GitHub.

Em seguida, crie um novo ambiente virtual. Usarei o Conda:

$ conda create -n ocr python==3.9 -y
$ conda activate ocr

Em seguida, você deve instalar o pytesseract para fazer OCR e o opencv para manipulação de imagens:

$ pip install pytesseract
$ pip install opencv-python

Se você estiver seguindo este tutorial no Jupyter, execute esses comandos na mesma sessão de terminal para que seu novo ambiente virtual seja adicionado como um kernel:

$ pip install ipykernel
$ ipython kernel install --user --name=ocr

Agora, podemos começar a escrever o código.

Uso básico

Começamos importando as bibliotecas necessárias:

import cv2
import pytesseract

Nossa tarefa é ler o texto da imagem a seguir:

Uma imagem de amostra para executar o OCR com o PyTesseract e o OpenCV

Primeiro, definimos o caminho da imagem e o alimentamos com a função cv2.imread:

# Read image
easy_text_path = "images/easy_text.png"
easy_img = cv2.imread(easy_text_path)

Em seguida, passamos a imagem carregada para a função image_to_string de pytesseract para extrair o texto:

# Convert to text
text = pytesseract.image_to_string(easy_img)
print(text)
This text is
easy to extract.

É tão fácil quanto isso! Vamos converter o que acabamos de fazer em uma função:

def image_to_text(input_path):
   """
   A function to read text from images.
   """
   img = cv2.imread(input_path)
   text = pytesseract.image_to_string(img)

   return text.strip()

Vamos usar a função em uma imagem mais difícil:

Outra imagem de amostra para executar o OCR com o PyTesseract e o OpenCV

A imagem oferece um desafio maior, pois há mais símbolos de pontuação e texto em fontes diferentes.

# Define image path
medium_text_path = "images/medium_text.png"

# Extract text
extracted_text = image_to_text(medium_text_path)
print(extracted_text)
Home > Tutorials » Data Engineering

Snowflake Tutorial For Beginners:
From Architecture to Running
Databases

Learn the fundamentals of cloud data warehouse management using
Snowflake. Snowflake is a cloud-based platform that offers significant
benefits for companies wanting to extract as much insight from their data as
quickly and efficiently as possible.

Jan 2024 - 12 min read

Nossa função funcionou quase perfeitamente. Você confundiu um dos pontos e os sinais ">", mas o resultado é aceitável.

Desenho de caixas delimitadoras ao redor do texto

Uma operação comum no OCR é desenhar caixas delimitadoras ao redor do texto. Essa operação é compatível com o PyTesseract.

Primeiro, passamos uma imagem carregada para a função image_to_data:

from pytesseract import Output

# Extract recognized data from easy text
data = pytesseract.image_to_data(easy_img, output_type=Output.DICT)

A parte Output.DICT garante que os detalhes da imagem sejam retornados como um dicionário. Vamos dar uma olhada no interior:

data
{'level': [1, 2, 3, 4, 5, 5, 5, 4, 5, 5, 5],
'page_num': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
'block_num': [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
'par_num': [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1],
'line_num': [0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2],
'word_num': [0, 0, 0, 0, 1, 2, 3, 0, 1, 2, 3],
'left': [0, 41, 41, 236, 236, 734, 1242, 41, 41, 534, 841],
'top': [0, 68, 68, 68, 68, 80, 68, 284, 309, 284, 284],
'width': [1658, 1550, 1550, 1179, 380, 383, 173, 1550, 381, 184, 750],
'height': [469, 371, 371, 128, 128, 116, 128, 155, 130, 117, 117],
'conf': [-1, -1, -1, -1, 96, 95, 95, -1, 96, 96, 96],
'text': ['', '', '', '', 'This', 'text', 'is', '', 'easy', 'to', 'extract.']}

O dicionário contém muitas informações sobre a imagem. Primeiro, observe as teclas conf e text. Ambos têm um comprimento de 11:

len(data["text"])
11

Isso significa que pytesseract desenhou 11 caixas. O conf significa confiança. Se for igual a -1, a caixa correspondente será desenhada em torno de blocos de texto em vez de palavras individuais.

Por exemplo, se você observar os quatro primeiros valores de width e height, eles são grandes em comparação com o restante porque essas caixas são desenhadas ao redor de todo o texto no meio, depois para cada linha de texto e para a própria imagem geral.

Also:

  • left é a distância do canto superior esquerdo da caixa delimitadora até a borda esquerda da imagem.
  • top é a distância do canto superior esquerdo da caixa delimitadora até a borda superior da imagem.
  • width e height são a largura e a altura da caixa delimitadora.

Usando essas informações, vamos desenhar as caixas na parte superior da imagem no OpenCV.

Primeiro, extraímos os dados novamente e seu comprimento:

from pytesseract import Output

# Extract recognized data
data = pytesseract.image_to_data(easy_img, output_type=Output.DICT)
n_boxes = len(data["text"])

Em seguida, criamos um loop para o número de caixas encontradas:

for i in range(n_boxes):
   if data["conf"][i] == -1:
       continue

Dentro do loop, criamos uma condição que ignora a iteração do loop atual se conf for igual a -1. Ignorar caixas delimitadoras maiores manterá nossa imagem limpa.

Em seguida, definimos as coordenadas da caixa atual, especificamente os locais dos cantos superior esquerdo e inferior direito:

for i in range(n_boxes):
   if data["conf"][i] == -1:
       continue
   # Coordinates
   x, y = data["left"][i], data["top"][i]
   w, h = data["width"][i], data["height"][i]

   # Corners
   top_left = (x, y)
   bottom_right = (x + w, y + h)

Depois de definir alguns parâmetros da caixa, como a cor e a espessura da caixa em pixels, passamos todas as informações para a função cv2.rectangle:

for i in range(n_boxes):
   if data["conf"][i] == -1:
       continue
   # Coordinates
   x, y = data["left"][i], data["top"][i]
   w, h = data["width"][i], data["height"][i]

   # Corners
   top_left = (x, y)
   bottom_right = (x + w, y + h)

   # Box params
   green = (0, 255, 0)
   thickness = 3  # pixels

   cv2.rectangle(
       img=easy_img, pt1=top_left, pt2=bottom_right, color=green, thickness=thickness
   )

A função desenhará as caixas em cima das imagens originais. Vamos salvar a imagem e dar uma olhada:

# Save the image
output_image_path = "images/text_with_boxes.jpg"
cv2.imwrite(output_image_path, easy_img)
True

Uma imagem de amostra com caixas delimitadoras desenhadas ao redor de cada palavra. Realizado com PyTesseract e OpenCV.

O resultado é exatamente o que você queria!

Agora, vamos colocar tudo o que fizemos em uma função novamente:

def draw_bounding_boxes(input_img_path, output_path):
   img = cv2.imread(input_img_path)

   # Extract data
   data = pytesseract.image_to_data(img, output_type=Output.DICT)
   n_boxes = len(data["text"])

   for i in range(n_boxes):
       if data["conf"][i] == -1:
           continue
       # Coordinates
       x, y = data["left"][i], data["top"][i]
       w, h = data["width"][i], data["height"][i]

       # Corners
       top_left = (x, y)
       bottom_right = (x + w, y + h)

       # Box params
       green = (0, 255, 0)
       thickness = 1  # The function-version uses thinner lines

       cv2.rectangle(img, top_left, bottom_right, green, thickness)

   # Save the image with boxes
   cv2.imwrite(output_path, img)

E use a função no texto de dureza média:

output_path = "images/medium_text_with_boxes.png"

draw_bounding_boxes(medium_text_path, output_path)

Outra imagem de amostra com caixas delimitadoras desenhadas ao redor de cada palavra. Realizado com PyTesseract e OpenCV.

Mesmo com a imagem mais difícil, o resultado é perfeito!

Estudo de caso: OCR em um arquivo PDF com Python

Vamos fazer um estudo de caso em um exemplo de arquivo PDF digitalizado. Na prática, é muito provável que você trabalhe com PDFs digitalizados em vez de imagens, como esta:

Um exemplo de documento digitalizado prestes a ser executado com OCR usando o PyTesseract.

Você pode baixar o PDF nesta página do meu GitHub.

A próxima etapa é instalar a biblioteca pdf2image, que requer um software de processamento de PDF chamado Poppler. Aqui estão as instruções específicas para cada plataforma:

Para Mac:

$ brew install poppler
$ pip install pdf2image

Para Linux e WSL2:

$ sudo apt-get install -y poppler-utils
$ pip install pdf2image

No Windows, você pode seguir as instruções dos documentos do PDF2Image.

Após a instalação, importamos os módulos relevantes:

import pathlib
from pathlib import Path

from pdf2image import convert_from_path

A função convert_from_path converte um determinado PDF em uma série de imagens. Aqui está uma função que salva cada página de um arquivo PDF como uma imagem em um determinado diretório:

def pdf_to_image(pdf_path, output_folder: str = "."):
   """
   A function to convert PDF files to images
   """
   # Create the output folder if it doesn't exist
   if not Path(output_folder).exists():
       Path(output_folder).mkdir()

   pages = convert_from_path(pdf_path, output_folder=output_folder, fmt="png")

   return pages

Vamos executá-lo em nosso documento:

pdf_path = "scanned_document.pdf"

pdf_to_image(pdf_path, output_folder="documents")
[<PIL.PngImagePlugin.PngImageFile image mode=RGB size=1662x2341>]

A saída é uma lista que contém uma única imagem do objeto PngImageFile. Vamos dar uma olhada no diretório documents:

$ ls documents
2d8f6922-99c4-4ef4-a475-ef81effe65a3-1.png

A imagem está lá, então vamos alimentá-la com a função image_to_text que criamos no início e imprimir as primeiras centenas de caracteres do texto extraído:

scanned_img_path = "documents/2d8f6922-99c4-4ef4-a475-ef81effe65a3-1.png"

print(image_to_text(scanned_img_path)[:377])
PEU Business report

New customer's development
and increasing the sale of product

My country economy at this season keeps escaping from Odoba of business though holds a crude oil
high so on unstable element that continues still, and recovering gradually and well.
In the IT industry, there is an influence such as competing intensification in narrowing investment field.

Se compararmos o texto com o arquivo, tudo está funcionando bem: a formatação e o espaçamento são preservados e o texto é preciso. Então, como compartilhamos o texto extraído?

Bem, o melhor formato para compartilhar o texto extraído do PDF é outro arquivo PDF! O PyTesseract tem uma função image_to_pdf_or_hocr que pega qualquer imagem com texto e a converte em um arquivo PDF bruto, pesquisável por texto. Vamos usá-lo em nossa imagem digitalizada:

raw_pdf = pytesseract.image_to_pdf_or_hocr(scanned_img_path)

with open("searchable_pdf.pdf", "w+b") as f:
   f.write(bytearray(raw_pdf))

E aqui está a aparência do site searchable_pdf:

Um GIF que mostra o resultado do OCR executado em um documento PDF digitalizado.

Como você pode ver, posso destacar e copiar o texto do arquivo. Além disso, todos os elementos do PDF original são preservados.

Técnicas de pré-processamento de imagens para OCR no OpenCV

Não existe uma abordagem única para o OCR. As técnicas que abordamos hoje podem não funcionar com outros tipos de imagens. Recomendo que você experimente diferentes técnicas de pré-processamento de imagens e configurações do Tesseract para encontrar as configurações ideais para imagens específicas.

O fator mais importante no OCR é a qualidade da imagem. Imagens adequadamente digitalizadas, totalmente verticais e de alto contraste (preto e branco) tendem a funcionar melhor com qualquer software de OCR. Lembre-se de que, só porque você consegue ler o texto, não significa que seu computador consiga.

Se suas imagens não satisfizerem os altos padrões de qualidade do Tesseract e a saída for sem sentido, há algumas etapas de pré-processamento que você pode executar.

1. Conversão em escala de cinza

Primeiro, comece com a conversão de imagens coloridas em escala de cinza. Isso pode melhorar a precisão ao remover variações de cores que podem confundir o processo de reconhecimento. No OpenCV, você terá a seguinte aparência:

def grayscale(image):
   """Converts an image to grayscale.

   Args:
       image: The input image in BGR format.

   Returns:
       The grayscale image.
   """
   return cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

2. Redução de ruído

Nem todas as imagens, especialmente os documentos digitalizados, vêm com fundos imaculados e uniformes. Além disso, algumas imagens podem ser de documentos antigos cujas páginas se deterioraram devido ao tempo. Aqui está um exemplo:

Uma amostra de imagem ruidosa na qual o OCR será executado.

Aplique técnicas como filtros de redução de ruído (por exemplo, desfoque mediano) para reduzir os artefatos de ruído na imagem que podem levar a interpretações errôneas durante o OCR. No OpenCV, você pode usar a função medianBlur:

def denoise(image):
   """Reduces noise in the image using a median blur filter.

   Args:
       image: The input grayscale image.

   Returns:
       The denoised image.
   """
   return cv2.medianBlur(image, 5)  # Adjust kernel size as needed

3. Afiação

Em alguns casos, a nitidez da imagem pode aprimorar as bordas e melhorar o reconhecimento de caracteres, especialmente em imagens borradas ou de baixa resolução. A nitidez pode ser realizada aplicando um filtro Laplaciano no OpenCV:

def sharpen(image):
   """Sharpens the image using a Laplacian filter.

   Args:
       image: The input grayscale image.

   Returns:
       The sharpened image (be cautious with sharpening).
   """
   kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
   return cv2.filter2D(image, -1, kernel)

4. Binarização

Para determinadas imagens, a binarização (conversão da imagem em preto e branco) pode ser benéfica. Faça experiências com diferentes técnicas de limiarização para encontrar a separação ideal entre o primeiro plano (texto) e o plano de fundo.

No entanto, a binarização pode ser sensível a variações na iluminação e nem sempre é necessária. Aqui está um exemplo da aparência de uma imagem binarizada:

Uma imagem de amostra: original à esquerda, versão binarizada à direita no OpenCV.

Para realizar a binarização no OpenCV, você pode usar a função adaptiveThreshold:

def binarize(image):
   """Binarizes the image using adaptive thresholding.

   Args:
       image: The input grayscale image.

   Returns:
       The binary image.
   """
   thresh = cv2.adaptiveThreshold(
       image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2
   )

   return thresh

5. Outras técnicas

Há muitas outras técnicas de pré-processamento, como:

  • Dilatação: tornar as fontes pequenas e finas mais fortes para melhorar o reconhecimento
  • Erosão: corroer o texto em negrito para melhorar a precisão. Comum em documentos históricos com fontes grossas.
  • Detecção de borda inteligente
  • Correção de inclinação: correção da inclinação (skewness) das linhas de texto. Comum em documentos digitalizados incorretamente

Você pode saber mais sobre melhorias na qualidade da imagem nesta página da documentação do Tesseract.

Conclusão

Neste artigo, você deu os primeiros passos para aprender sobre o problema dinâmico que é o OCR. Primeiro, abordamos como extrair texto de imagens simples e, em seguida, passamos para imagens mais difíceis com formatação complexa.

Também aprendemos um fluxo de trabalho de ponta a ponta para extrair texto de PDFs digitalizados e como salvar o texto extraído como PDF novamente para que ele se torne pesquisável. Encerramos o artigo com algumas dicas para você melhorar a qualidade da imagem com o OpenCV antes de alimentá-la no Tesseract.

Se você quiser saber mais sobre como resolver problemas relacionados a imagens, aqui estão alguns recursos de visão computacional que você pode consultar:


Bex Tuychiev's photo
Author
Bex Tuychiev
LinkedIn

Sou um criador de conteúdo de ciência de dados com mais de 2 anos de experiência e um dos maiores seguidores no Medium. Gosto de escrever artigos detalhados sobre IA e ML com um estilo um pouco sarcástico, porque você precisa fazer algo para torná-los um pouco menos monótonos. Produzi mais de 130 artigos e um curso DataCamp, e estou preparando outro. Meu conteúdo foi visto por mais de 5 milhões de pessoas, das quais 20 mil se tornaram seguidores no Medium e no LinkedIn. 

Perguntas frequentes sobre Python OCR

Por que sou tão alto?

Genética.

Temas

Continue sua jornada de aprendizado de Python!

Certificação disponível

curso

Processamento de imagens em Python

4 hr
46.9K
Aprenda a processar, transformar e manipular imagens como você quiser.
Ver DetalhesRight Arrow
Iniciar curso
Ver maisRight Arrow