Da HP ao código aberto: a história real do Tesseract
O Tesseract não nasceu como projeto de comunidade, nasceu como produto comercial dentro de uma fabricante de hardware, décadas antes de virar a base de uma ferramenta de navegador. A linha do tempo abaixo segue a própria documentação oficial do projeto (README e tessdoc, no GitHub do tesseract-ocr).
- 1985 a 1998Nasce como produto comercial da HP
Desenvolvido nos laboratórios da Hewlett-Packard em Bristol, Reino Unido, e na HP em Greeley, Colorado (EUA), entre 1985 e 1994, com ajustes para rodar no Windows em 1996 e a conversão do código para C++ em 1998.
- 1995Bom desempenho no teste anual da UNLV
No UNLV Annual Test of OCR Accuracy, uma avaliação conduzida pela Universidade de Nevada, Las Vegas, o Tesseract registrou cerca de 98% de acerto por caractere num dos conjuntos de teste da época, um resultado de destaque frente aos motores comerciais concorrentes.
- 2005A HP abre o código
A Hewlett-Packard libera o Tesseract como projeto de código aberto, depois de anos sem desenvolvimento ativo como produto comercial.
- 2006 a 2017O Google assume o desenvolvimento
De 2006 até agosto de 2017, o desenvolvimento do Tesseract é conduzido pelo Google, sob a liderança de Ray Smith, o mesmo engenheiro por trás do motor original.
- 2018Tesseract 4: motor neural LSTM
O Tesseract 4.0.0 é lançado em 29 de outubro de 2018, com um novo motor de reconhecimento baseado em redes neurais LSTM, ao lado do motor clássico anterior.
- 2021 até hojeTesseract 5 e manutenção pela comunidade
O Tesseract 5.0.0 sai em 30 de novembro de 2021 e vira a versão estável principal. Desde o fim da liderança do Google, o projeto segue como código aberto mantido por uma comunidade de colaboradores, não mais por uma equipe interna de uma empresa.
O pipeline real: da imagem crua ao texto
Um motor de OCR nunca vai direto da imagem para as letras. Ele passa por três fases, pré-processamento (limpar e normalizar a imagem), segmentação (achar onde estão os blocos e linhas de texto antes de tentar lê-los) e só então reconhecimento (identificar os caracteres). Os passos abaixo são exatamente os que a ferramenta Imagem para Texto roda, na ordem em que o próprio código os executa.
- Decodificar respeitando a orientação EXIFA imagem é decodificada de um jeito que respeita os metadados de rotação da câmera, para que uma foto tirada de lado não comece de cabeça para baixo antes mesmo de chegar ao resto do pipeline.
- Aumentar a escala quando a imagem é pequenaSe o lado maior da imagem for menor que 1.600 px, ela é ampliada, no máximo 3 vezes, mirando essa borda de 1.600 px. Imagens já grandes nunca são reduzidas. Traços finos de letras pequenas somem em imagens pequenas antes mesmo da binarização; aumentar a escala dá aos traços pixels suficientes para sobreviver às próximas etapas.
- Converter para escala de cinzaA cor é descartada usando a fórmula de luma ITU-R BT.601 (0,299×vermelho + 0,587×verde + 0,114×azul). O que importa para achar o contorno de uma letra é o brilho, não a cor.
- Inverter se o fundo for escuroSe o brilho médio da imagem ficar abaixo de 128 (numa escala de 0 a 255), ela é invertida automaticamente. Um print em modo escuro, texto claro sobre fundo escuro, vira texto escuro sobre fundo claro, o padrão que as próximas etapas esperam.
- Esticar o contrasteA faixa de brilho entre o 1º e o 99º percentil da imagem é redistribuída para ocupar todo o intervalo de 0 a 255. Um recibo desbotado, onde o texto mais escuro e o papel mais claro estão a poucos tons de distância, ganha de volta um contraste que a binarização consegue separar.
- Segmentar e reconhecer, em até 3 passadasNo modo automático, a primeira passada assume um parágrafo comum. Se o resultado sair vazio ou com confiança abaixo de 55%, uma segunda passada binariza a imagem pelo método de Otsu e desliga o dicionário de palavras (útil para códigos e placas, que não são palavras de dicionário). Se ainda assim a confiança for baixa, uma terceira passada lê como linha única. A ferramenta guarda o resultado de maior confiança entre as passadas tentadas.
Um exemplo real com números reais: uma foto de recibo de 800×600 px tem o lado maior em 800 px, abaixo da meta de 1.600 px. O fator de ampliação é o menor entre 3 e 1.600/800, ou seja, 2. O canvas final sai em 1.600×1.200 px, o dobro do tamanho original, antes mesmo de virar cinza.
computeUpscaleFactor(800, 600)
lado maior = 800 px (abaixo da meta de 1600 px)
fator = min(3, 1600 / 800) = min(3, 2) = 2
canvas final = 1600 x 1200 pxUm segundo exemplo, agora da etapa de reconhecimento: uma foto de placa de carro é texto esparso, sem frases, o pior caso para um dicionário de idioma. No modo automático, a primeira passada (parágrafo) provavelmente sai vazia ou com confiança baixa, porque "ABC-1234" não é uma palavra. A ferramenta então tenta a segunda passada, binarizada e sem dicionário, que costuma resolver esse tipo de conteúdo. O reconhecimento, aqui, não é uma tentativa única, é uma busca por qual estratégia funciona para aquela imagem específica. Vale lembrar também que o formato do arquivo de origem já entra torto na primeira etapa: um JPEG salvo várias vezes borra exatamente os traços finos que a binarização precisa separar bem, o mesmo motivo, explicado no guia de formatos de imagem para a web, que faz um QR Code sair ilegível nesse formato. Prefira PNG, ou o arquivo original da câmera, quando o objetivo final for texto.
Clássico vs. neural: a guinada do Tesseract 4
Até o Tesseract 3, e na maioria dos motores de OCR até o início dos anos 2010, o reconhecimento funcionava caractere por caractere: o software isolava cada forma como um "blob" separado e comparava essa forma contra padrões aprendidos. O Tesseract 4.0.0, lançado em 2018, mudou isso ao adicionar um segundo motor, baseado em uma rede neural LSTM. Segundo a documentação oficial do projeto, esse novo subsistema "está integrado ao Tesseract como um reconhecedor de linha", ou seja, ele lê a linha inteira como uma sequência, não caractere isolado por caractere isolado.
Motor clássico (até o Tesseract 3)
- Isola cada caractere como uma forma separada, depois de encontrar linhas e palavras por análise de layout.
- Classifica cada forma isoladamente contra padrões aprendidos, e só depois aplica um dicionário para corrigir a leitura palavra a palavra.
- Mais leve, mas decide cada letra sem realmente olhar a linha inteira como sequência.
Motor neural LSTM (a partir do Tesseract 4, 2018)
- Lê a linha inteira como uma sequência de uma vez, em vez de decidir letra por letra isolada.
- Tem origem na implementação em Python do projeto OCRopus, adaptada para o Tesseract.
- Usa cerca de 10 vezes mais recursos de CPU que o motor clássico, segundo a documentação oficial, o preço de olhar mais contexto por vez.
Isso explica um detalhe prático desta ferramenta: o modo de conteúdo "parágrafo" e "linha" usam a passada padrão do motor (que hoje é a LSTM), enquanto o modo "esparso" some binarização e desliga o dicionário, uma combinação pensada para o texto que menos se parece com prosa normal, como códigos, placas e símbolos soltos.
Os modos de falha reais, e a etapa que cada um quebra
Um motor de OCR não erra de forma aleatória. Cada tipo comum de falha corresponde a uma etapa específica do pipeline descrito acima, sendo quebrada de um jeito específico. Entender qual etapa quebra é o que torna um resultado ruim consertável, em vez de só frustrante.
Foto torta ou rotacionada quebra a segmentação. A análise de layout que agrupa formas em linhas espera uma linha de base mais ou menos horizontal. Com poucos graus de inclinação, o reconhecedor de linha costuma se virar, porque ele lê ao longo de uma linha de base ajustada. Conforme a inclinação cresce, porém, o segmentador passa a desenhar caixas que cortam ascendentes de uma linha e descendentes da linha seguinte, então palavras saem partidas no meio da letra, antes mesmo de qualquer classificador entrar em ação. Esta ferramenta não corrige inclinação automaticamente: ela oferece uma rotação manual em passos de 90° e um editor de recorte, então o conserto prático para qualquer ângulo fora desse padrão é endireitar a foto antes de rodar o OCR, não confiar que o motor vai compensar sozinho, use o redimensionador e cortador de imagens para isso, se precisar de mais controle do que o editor embutido oferece.
Contraste baixo ou luz desigual quebra a binarização. O método de Otsu escolhe um único ponto de corte de brilho para a imagem inteira. Se a luz cair de forma desigual, um canto claro, um canto escuro, uma sombra atravessando metade da página, nenhum valor único separa tinta de papel em todo lugar ao mesmo tempo: partes do texto somem no fundo, outras ganham um halo de ruído. O esticamento de contraste desta ferramenta ajuda quando a imagem inteira está uniformemente fraca, mas não resolve quando o problema é a própria desigualdade da luz.
Fontes decorativas ou incomuns quebram o classificador, seja o clássico ou o LSTM, porque os dois foram treinados nas formas de fontes impressas típicas. Uma fonte gótica, cursiva estilizada ou muito ornamentada tem contornos de letra fora do que o modelo aprendeu a reconhecer, então a confiança cai e as trocas aumentam, um "S" decorativo virando um "5", por exemplo.
Fundos poluídos ou com textura quebram segmentação e binarização juntas. Uma textura atrás ou ao redor do texto cria bordas e contraste que a etapa de segmentação pode confundir com caracteres, ou que se misturam com as letras reais, então a fronteira entre "é tinta" e "não é tinta" fica embaçada, produzindo ruído que o reconhecedor tenta, e falha, ler como caracteres.
Letra de mão é um problema diferente, não apenas mais difícil. OCR impresso, incluindo o motor LSTM do Tesseract, é treinado no vocabulário de formas relativamente estreito e consistente das fontes impressas: uma letra "a" impressa parece sempre quase igual. A escrita à mão tem variação enorme entre pessoas, e até dentro da letra da mesma pessoa, sem um "alfabeto" fixo de formas, e em cursiva os traços se conectam sem se separar em blobs de um caractere só. É por isso que reconhecimento de escrita à mão é tratado como um campo próprio, chamado de HTR (Handwritten Text Recognition), com seus próprios modelos e dados de treino, em vez de algo que o mesmo motor de texto impresso resolve de forma confiável.
Perguntas frequentes
Que motor de OCR essa ferramenta usa, e minhas imagens são enviadas a algum servidor?
Por que uma foto torta atrapalha tanto o resultado?
Qual a diferença entre o motor clássico e o motor LSTM do Tesseract?
OCR funciona bem com letra de mão (manuscrita)?
Quais idiomas essa ferramenta reconhece, e por que ela baixa arquivos na primeira vez?
O que o modo de conteúdo (parágrafo, linha, esparso) muda no resultado?
OCR não é um passe de mágica, é um pipeline: pré-processar a imagem (upscale, escala de cinza, inversão, contraste), segmentar onde estão as linhas e só então reconhecer os caracteres, hoje por uma rede neural LSTM que o Tesseract adotou em 2018, herdeira de um motor que nasceu comercial na HP nos anos 1980 e foi aberto em 2005. A ferramenta deste site roda esse pipeline inteiro com o motor real, dentro do seu navegador, sem enviar nada a um servidor. Saber qual etapa quebra, segmentação numa foto torta, binarização com luz desigual, o classificador numa fonte decorativa, é o que transforma um resultado ruim em algo consertável.
Fontes e referências
- tesseract-ocr/tesseract, README (história do projeto)
- tessdoc, UNLV Testing of Tesseract
- tessdoc, Neural Nets in Tesseract 4.00
- tesseract-ocr/tesseract, release 4.0.0 (29 de outubro de 2018)
- tesseract-ocr/tesseract, release 5.0.0 (30 de novembro de 2021)
- naptha/tesseract.js, README (porta em WebAssembly)