EasyOCR é a biblioteca de OCR pronta para uso da JaidedAI para Python: pip install easyocr, duas linhas de código, e o texto “embutido” numa imagem volta como strings. Ela usa licença Apache-2.0, informa suporte a mais de 80 idiomas e funciona como um pipeline de dois modelos PyTorch — um detector CRAFT que desenha caixas em tudo o que acha ser texto e, depois, um reconhecedor que lê os caracteres dentro de cada caixa. Os pesos pré-treinados são baixados automaticamente na primeira vez que você chama a ferramenta. Na prática, é uma alternativa local ao Tesseract e ao PaddleOCR, e não uma API de OCR em nuvem cobrada por página.
A API básica é curta: Reader(['en']), depois readtext(). Mas a implantação é bem mais pesada — cerca de 2 GB de PyTorch neste ambiente e algo em torno de um gigabyte de memória residente no pico em um processo novo medido. Renderizei 36 arquivos PNG em inglês, rodei o easyocr 1.7.2 em CPU e pontuei as leituras caractere por caractere contra o texto de referência gerado. Tamanho e orientação causaram as maiores quedas no CER; o painel também mostrou problemas em tokens curtos e na leitura do símbolo de dólar.
A falha mais nítida envolve justamente o parâmetro que todo mundo recomenda. rotation_info tem fama, nos relatos de issues, de ser a solução para imagens giradas, então ele recebeu três cópias ortogonalmente rotacionadas da mesma frase. Em 270° ele fez exatamente o que promete, reduzindo o character error rate de 0.83 para 0.10. Em 180° funcionou pela metade: de 0.85 para 0.67, com uma parte da frase sumindo. Em 90° foi na direção oposta, de 0.81 para 0.92, e o recognizer começou a devolver texto espelhado. Mesmo parâmetro, mesma lista de ângulos, três resultados diferentes — então ativá-lo não quer dizer que “a rotação ficou resolvida”. Os mesmos 36 fixtures também mostraram um limite duro de tamanho de fonte, uma leitura errada sistemática do cifrão e uma previsão minha que acabou simplesmente errada.
Dois modelos disfarçados de um só
EasyOCR não é um único modelo. É um pipeline de dois estágios, e saber qual deles falhou muda completamente o debug.
O primeiro estágio é o CRAFT, o detector. A única função dele é localizar — decidir onde na imagem existe texto e devolver caixas. Ele nunca lê caracteres. O segundo estágio é um CRNN recognizer — extração de recursos com ResNet, depois uma BiLSTM e, por fim, decodificação greedy com CTC — que lê os caracteres dentro de cada caixa. Ambos rodam em PyTorch. Em CPU, o recognizer usa quantização dinâmica para int8 por padrão, o que explica por que ele é mais rápido e leve do que o número bruto de parâmetros faria imaginar.

Na prática, isso quer dizer que o EasyOCR tem dois modos de falha totalmente diferentes, e cada um pede um tipo de correção. Se o detector nunca desenha uma caixa, não adianta mexer no recognizer — os caracteres nem chegaram ao pipeline. Se a caixa existe, mas a string sai errada, então o problema é de reconhecimento e o pré-processamento pode salvar. Quase todo tópico de “o EasyOCR não pegou meu texto” que li mistura essas duas coisas.
Estado atual do projeto, verificado em 27 de julho de 2026: 29.825 estrelas, 528 issues abertas, Apache-2.0, e v1.7.2 de setembro de 2024, com o último push para o master em dezembro de 2025. Essas datas não provam estabilidade arquitetural nem saúde de manutenção. Antes de adotar, confira compatibilidade com seu stack de Python/PyTorch, a resposta recente dos mantenedores e issues relevantes para seus dados de entrada.
OCR costuma ser associado a bypass de CAPTCHA, e esse não é o caso aqui. Nada foi testado contra desafios de bot detection, e nada neste texto endossa contornar esse tipo de proteção. O escopo aqui é ler texto em imagens e capturas de tela que você tem direito de ler.
O que eu medi — e o que esses números não cobrem
O conjunto de testes é formado por 36 PNGs que eu mesmo renderizei: 35 imagens de uma linha, cobrindo sete fontes, oito tamanhos, sete níveis de contraste, sete ângulos de inclinação, três rotações ortogonais e três fundos — além de uma captura sintética de dashboard com 19 elementos rotulados individualmente. Cada imagem foi gerada a partir de uma string fixa (Sphinx of black quartz, judge my vow. 1234567890 — 48 caracteres, caixa alta e baixa, dígitos e pontuação) no mesmo passo em que o rótulo ground truth foi escrito, então imagem e rótulo simplesmente não podem divergir.
A métrica de precisão usada é o character error rate (CER): distância de Levenshtein em caracteres dividida pelo comprimento do texto de referência. CER 0 significa leitura perfeita. CER 0.10 significa aproximadamente um caractere errado a cada dez. Eu apresento o CER sensível a caixa alta/baixa como destaque e, ao lado, o CER sem considerar caixa, porque é justamente aí que a maior parte do “erro” aparece.
Os limites importam mais do que os números:
- Só inglês. O recognizer
english_g2. O EasyOCR anuncia mais de 80 idiomas; eu testei um. Nada aqui diz respeito a scripts não latinos, que são justamente o foco das comparações acadêmicas publicadas. - Só sintético. Texto renderizado, não fotografado. Sem ruído de câmera, sem artefatos JPEG, sem iluminação variável, sem perspectiva.
- Sem escrita manual. O próprio projeto informa que handwriting ainda não é suportado.
- Apenas CPU. macOS arm64,
gpu=False. Havia MPS disponível na máquina, mas o EasyOCR usa CPU em qualquer coisa que não seja CUDA. Desempenho em GPU não foi medido, então não há números de GPU aqui. - Uma máquina, uma versão. easyocr 1.7.2, torch 2.13.0, Python 3.12.
Ou seja: são curvas controladas de variável única mostrando exatamente onde a fidelidade quebra, em texto latino limpo e renderizado. Isso não é uma nota de corpus do mundo real — e não substitui uma.
As evidências podem ser inspecionadas, em vez de ficarem presas em um notebook. O gerador de fixtures e as strings exatas estão em tests/build_fixtures.py e tests/fixtures/ground_truth.json; a coleta de reconhecimento, tempo e recursos fica em tests/run_easyocr.py; e tests/metrics.py calcula as taxas de erro reportadas a partir da saída bruta. Os registros de reconhecimento e as métricas agregadas finais estão preservados em artifacts/raw/. Reexecutar essa cadeia ajuda a verificar esta máquina e esta versão. Ainda assim, isso não responde como o EasyOCR vai se comportar em fotos de celular, outros idiomas, layouts diferentes ou sua própria pipeline de pré-processamento, então a validação em produção deve usar entradas representativas em vez de tratar esses fixtures como certificação.
Um detalhe do harness vale ser destacado, porque quase gerou um número final errado. Minha primeira passada de métricas reportou CER 0.375 em Arial preta e limpa, o que seria péssimo para a entrada mais fácil possível. O problema não era o EasyOCR. O detector havia dividido uma linha visual em uma caixa de palavras e uma caixa de dígitos, e meu join ingênuo ordenando por y depois x colocava os dígitos antes. Corrigido com agrupamento por linha (agrupar caixas por sobreposição vertical e depois ler da esquerda para a direita), as fontes limpas caíram para algo entre 0.04 e 0.10. Se você for montar sua própria avaliação de OCR, essa armadilha também vai te esperar.
Setup: a instalação é pequena, a dependência não

pip install easyocr
É só isso — e a honestidade para por aí. O pacote em si é pequeno; o que ele puxa junto é PyTorch, algo em torno de 2 GB. Depois, na primeira vez que você chama readtext(), o EasyOCR baixa silenciosamente os pesos para ~/.EasyOCR/model/ — 93.7 MiB no total, divididos em 79.30 MiB para o detector CRAFT (craft_mlt_25k.pth) e 14.44 MiB para o recognizer em inglês (english_g2.pth).
Isso quase nunca é destacado em tutoriais, então vale o aviso: a primeira execução precisa de rede e vai pausar por causa do download; e qualquer implantação em contêiner precisa ou embutir esses pesos na imagem ou pagar o custo do download no cold start. Depois de em cache, tudo funciona offline.
A inicialização fria de Reader() — carregar modelos do disco para a RAM, mais a passagem de quantização para int8 — levou 1.3–1.7 segundos ao longo das execuções. Depois disso:
import easyocr
reader = easyocr.Reader(['en'], gpu=False)
result = reader.readtext('screenshot.png')
E pronto. Duas linhas, sem configuração, sem escolher checkpoint. O “easy” no nome é real nessa etapa — a fricção está toda no peso das dependências, não na API.
O piso do texto limpo: caracteres quase perfeitos, capitalização imperfeita
Sete fontes do sistema, preto sobre branco, 32 px, a mesma string toda vez:
| Fonte | CER (sensível a caixa) | CER (sem caixa) |
|---|---|---|
| Georgia | 0.0625 | 0.0000 |
| Times | 0.0417 | 0.0417 |
| Comic Sans | 0.0417 | 0.0208 |
| Arial | 0.0833 | 0.0208 |
| Verdana | 0.0833 | 0.0208 |
| Impact | 0.0833 | 0.0208 |
| Courier | 0.1042 | 0.0417 |
| Média | 0.0714 | 0.0238 |
CER médio de 0.071, caindo para 0.024 quando a caixa alta/baixa é normalizada. Essa diferença é o ponto principal. O EasyOCR não está perdendo caracteres em texto latino limpo — ele acerta a forma e erra a capitalização.
Mais especificamente, ele lê a palavra em minúsculas vow como VOW em seis das sete fontes (Comic Sans prefere Vow). Impact ainda transforma of em Of. O outro erro recorrente é pontuação: o ponto final da frase volta como : ou _ em várias fontes. Georgia é uma leitura perfeita assim que você para de se importar com capitalização.
Isso é muito útil de saber. Se a etapa seguinte for fuzzy matching, busca por palavra-chave ou enviar o texto para um modelo de linguagem, trocar caixa custa quase nada. Se a próxima etapa for comparação exata com uma chave de banco de dados, custa tudo. Normalize a caixa antes de comparar, e metade do erro aparente do EasyOCR desaparece.
O Courier ser o pior caso (0.1042) também faz sentido: fontes monoespaçadas deixam os espaços entre caracteres artificialmente largos, o que é mais difícil para um decodificador CTC que aprendeu espaçamentos típicos entre letras.
O limite de tamanho fica exatamente onde a documentação diz que fica

readtext() tem um parâmetro documentado, min_size=10, que descarta caixas detectadas menores que 10 pixels. Muita gente passa direto por ele. Ele é, de longe, o número mais importante da API para quem extrai texto de screenshots ou PDFs — e eis o que acontece quando você varia a altura do glyph renderizado:
| px renderizados | CER | O que aconteceu |
|---|---|---|
| 8 | 0.7708 | Colapso — caixas caem abaixo do filtro min_size e são descartadas; só sobram fragmentos |
| 10 | 0.1458 | Degradado — exatamente no limite, o detector fragmenta a linha em 3 caixas |
| 12 | 0.0417 | Recuperado |
| 16 | 0.0000 | Leitura perfeita |
| 20 | 0.0208 | Limpo |
| 28 | 0.0208 | Limpo |
| 40 | 0.0625 | Limpo (o flip de caixa reaparece) |
| 64 | 0.0625 | Limpo (flip de caixa) |
O salto de 0.04 para 0.77 entre 12 px e 8 px não é uma degradação gradual. É um filtro fazendo exatamente o que foi documentado para fazer — e o resultado é que texto abaixo de cerca de 10 px fica, na prática, invisível para o EasyOCR padrão.
A faixa ideal está entre 12 e 28 px, com CER total de 0 aos 16 px. Acima de 40 px, o CER volta a subir — não porque os caracteres desaparecem, mas porque o flip vow → VOW reaparece. Texto maior não é mais difícil de ler; ele só deixa de se beneficiar do espaçamento que fez 16 px acertar perfeitamente.
Para quem extrai texto de screenshots: verifique a altura do glyph antes de culpar o modelo. Um dashboard capturado em 1× num display HiDPI, ou uma página de PDF rasterizada a 72 DPI, frequentemente deixa o texto principal abaixo de 10 px. Capture em 2× ou faça upscale antes do OCR, e você pula toda a classe de bugs “o EasyOCR ignorou metade da página”. Se nenhuma dessas opções for possível, reduza min_size — mas espere ruído, porque o filtro existe justamente para suprimir detecções lixo.
Rotação: tolerância de 10° e uma correção que não é simétrica
Primeiro, inclinação. Ângulos pequenos, Arial 32 px, padrão versus rotation_info=[90,180,270]:
| Ângulo de inclinação | CER (padrão) | CER (com rotation_info) |
|---|---|---|
| 0° | 0.0833 | 0.0833 |
| 5° | 0.0417 | 0.0417 |
| 10° | 0.0208 | 0.0833 |
| 15° | 0.2917 | 0.3750 |
| 20° | 0.7500 | 0.7708 |
| 30° | 0.8958 | 0.8750 |
| 45° | 0.8958 | 0.8750 |
O EasyOCR padrão lida com inclinação de até cerca de 10° sem esforço (CER ≤ 0.083), começa a oscilar em 15° e praticamente quebra em 20°. rotation_info não ajuda no skew, o que faz sentido quando você entende o que ele faz — ele só tenta de novo nos ângulos que você listar, e uma inclinação de 15° não é 90, 180 nem 270. Em 10° ele até piorou um pouco (0.021 → 0.083), porque uma tentativa no ângulo errado pode vencer na votação de confiança.
As rotações ortogonais são onde a coisa fica estranha:
| Rotação | CER (padrão) | CER (com rotation_info) | Recuperou? |
|---|---|---|---|
| 90° | 0.8125 | 0.9167 | Não — piorou |
| 180° | 0.8542 | 0.6667 | Parcialmente |
| 270° | 0.8333 | 0.1042 | Sim |
Mesmo parâmetro. Mesma lista de ângulos. Três resultados diferentes.
Em 270°, rotation_info faz exatamente o que o tópico da issue promete: o CER cai de 0.83 para 0.10, uma leitura realmente aproveitável. Em 180°, ele funciona só pela metade — o CER melhora para 0.67, mas a frase my vow. some por completo. Em 90°, ele anda para trás, de 0.81 para 0.92, e a saída bruta explica o motivo: o recognizer devolve strings espelhadas. VOW volta como MOA. quartz volta como zuuenb. Lidos no espelho, estão corretos — uma curiosidade divertida, mas um pipeline de dados inútil.
Eu conferi isso nas previsões brutas, não só nas métricas agregadas, porque minha primeira suspeita foi de que a ordem do join tinha bagunçado tudo. Não era artefato de join — foi o que o EasyOCR realmente devolveu.
O mecanismo é uma hipótese, não uma medição; nenhum experimento de convenção de rotação foi executado. O Pillow renderiza ângulos positivos no sentido anti-horário, então só a imagem renderizada em 270° acaba alinhando com uma orientação de retry que o recognizer trata bem, e o caso de 90° tem o retry mais bem pontuado caindo numa orientação invertida. Seja qual for o mecanismo, a lição operacional não depende disso:
Este fixture mostra que não dá para assumir que rotation_info se comporta de forma simétrica entre orientações. Valide as rotações esperadas nas suas entradas; normalização de orientação antes do OCR é uma mitigação possível, não um requisito demonstrado por três exemplos renderizados.
A previsão em que eu errei
Entrei esperando que o baixo contraste fosse o ponto fraco do EasyOCR. Texto cinza-claro sobre fundo branco é o clássico fracasso de OCR, e existe até um caminho documentado para tentar salvar isso: contrast_ths=0.1 com adjust_contrast=0.5, que reprocessa caixas de baixo contraste com uma cópia mais forte e fica com o resultado de maior confiança.
Mas isso nunca foi acionado, porque nunca precisou.
| Cinza do primeiro plano | Contraste de Weber | CER (padrão) | CER (adjust_contrast=1.0) |
|---|---|---|---|
| 0 (preto) | 1.000 | 0.0833 | 0.0833 |
| 64 | 0.749 | 0.0833 | 0.0833 |
| 110 | 0.569 | 0.0833 | 0.0833 |
| 150 | 0.412 | 0.1042 | 0.1042 |
| 180 | 0.294 | 0.0625 | 0.0625 |
| 200 | 0.216 | 0.0417 | 0.0417 |
| 220 | 0.137 | 0.0417 | 0.0417 |
O CER nunca sai da faixa de texto limpo, mesmo chegando a Weber 0.14 — cinza-220 sobre branco, tão fraco que precisei apertar os olhos para confirmar que o texto estava mesmo lá. E a coluna de reforço de contraste é idêntica à padrão em todos os pontos, porque o padrão já estava funcionando.
Os fundos contaram a mesma história. Texto preto em todos os casos:
| Fundo | CER |
|---|---|
| Painel azul-claro sólido | 0.083 |
| Gradiente vertical | 0.021 |
| Ruído gaussiano (μ200, σ22) | 0.000 |
Leitura perfeita no fixture mais ruidoso do conjunto.
O escopo é estreito: aqui estamos falando de baixo contraste em cor sólida, sem ruído, e não de um recibo fotografado com ruído de sensor e compressão JPEG. Neste conjunto de fixtures, geometria e tokens curtos causaram as maiores falhas; as variações de cor e ruído sintético testadas não causaram.
Um cenário real: tirar números de uma captura de dashboard
Esse é o caso mais comum de OCR em Python na prática. Alguém envia um print de um dashboard interno, ou você está rodando um pipeline de scraping em Python numa página de analytics cheia de gráficos, onde os números só existem como pixels renderizados, e você quer os valores em forma de dados.
Renderizei uma janela de “Sales Dashboard” — cabeçalho escuro com título e um avatar circular, três painéis de KPI, três botões e uma tabela 2×3 — e rotulei todos os 19 elementos de texto com suas strings exatas e caixas em pixels, depois comparei a saída do EasyOCR com eles por sobreposição de caixas.
Recall de detecção: 16 de 19. As três falhas:
- o badge de uma letra, “A”
- a célula da tabela “Q1”
- a célula da tabela “Q2”
E “Q3” foi detectado. Mesma fonte, mesmo tamanho, mesma coluna — o detector manteve um token de dois caracteres e descartou dois outros. A detecção foi inconsistente entre células visualmente parecidas. Como as saídas foram determinísticas nessas execuções, isso não é evidência de comportamento aleatório de “cara ou coroa”. Um problema relacionado à qualidade de screenshots está registrado em #460.
Nos 16 elementos que ele encontrou, o texto veio quase perfeito: CER médio de 0.027, com 13 de 16 exatos. Títulos, rótulos, botões ("Save", "Cancel", "Export CSV"), cabeçalhos de coluna e números com separador de milhar voltaram com CER 0. 1,284 foi lido corretamente, vírgula incluída.
As três leituras imperfeitas são todas o mesmo erro. Valores em dólar:
| Ground truth | Leitura do EasyOCR |
|---|---|
$57,912 | S57,912 |
$18,330 | S18,330 |
$25,178 | S25,178 |
$12,004 | $12,004 (correto) |
Três de quatro cifrões viraram um S maiúsculo. Visualmente, até faz sentido — mas isso significa que qualquer campo de moeda na sua extração está a um caractere de virar lixo, e um float() ingênuo vai falhar em todos eles.
Se o seu pipeline de screenshots contém rótulos curtos ou moeda, valide mitigadores como upscale, crops com padding, expectativas restritas de campo ou pós-processamento sensível a símbolos. Nada disso foi benchmarkado aqui, e uma regex que troca S no início pode corromper valores legítimos. Aplique correções apenas quando o esquema e as regras de validação as tornarem seguras.
Quanto custa rodar
Números na mesma máquina (macOS arm64, CPU, um host, medido sob possível carga concorrente — trate isso como formato, não como benchmark universal):
| Métrica | Valor |
|---|---|
| Pesos do modelo em disco | 93.7 MiB (79.30 detector + 14.44 recognizer) |
| Pico de memória residente, processo CPU novo | 984.5 MiB |
Inicialização fria de Reader() | 1.3–1.7 s |
| Latência em quente, uma linha limpa de 48 caracteres (p50) | ~0.062 s (p25–p75: 0.059–0.067 s, n=20) |
detail=0 vs detail=1 | ~igual (mediana 0.062 vs 0.063 s) |
O custo principal não são os 94 MB de pesos — é aproximadamente um gigabyte de memória residente por processo worker, além de uma instalação de torch de ~2 GB. É esse número que decide se a ferramenta cabe no seu contêiner, e é esse número que quase ninguém cita.
A velocidade é boa para o caso fácil. Menos de 0.1 s em quente para uma linha limpa em CPU é perfeitamente utilizável. Mas esse é o caso fácil: uma linha curta e de alto contraste. As reclamações recorrentes de “o EasyOCR leva dezenas de segundos em CPU” dizem respeito a documentos grandes com múltiplas regiões em tamanho de tela cheia, e eu não reproduzi isso — é uma carga diferente, e estou citando a referência, não afirmando que reproduzi.
Um mito pequeno para derrubar: detail=0 não deixa o EasyOCR mais rápido. Ele só remove caixas delimitadoras e scores de confiança do retorno. O trabalho de computação já aconteceu. As medianas diferem por um milissegundo, o que é ruído.
Prós e contras
Prós
- O recall de caracteres em texto latino renderizado e limpo é praticamente perfeito — CER médio de 0.071 com caixa sensível e 0.024 sem caixa, com CER 0 completo possível aos 16 px.
- API genuinamente de duas linhas.
Reader(['en'])depoisreadtext(), sem configuração e sem seleção de modelo. - Muito mais robusto a contraste do que a fama sugere: não houve colapso até Weber 0.14 em texto limpo, e fundos coloridos, com gradiente ou ruído não pioraram o resultado (o fixture com ruído gaussiano teve leitura perfeita).
- Quase perfeito nos elementos de screenshot que detecta: CER médio 0.027, 13 de 16 exatos, incluindo números com vírgula de milhar.
- Determinístico. Todos os números de precisão aqui foram byte a byte idênticos em duas execuções de processo totalmente independentes; só o tempo variou.
- Apache-2.0 e self-hosted, sem taxa de uso de fornecedor; o custo fica em computação, memória, armazenamento e fila.
Contras
- Colapso brusco abaixo do piso documentado
min_size=10— CER 0.77 a 8 px. Texto pequeno de UI fica invisível por padrão. - Tolerância a skew para por volta de 10° e cai em 20°.
rotation_infonão é uma correção simétrica: 270° recupera, 180° recupera parcialmente, 90° piora e devolve texto espelhado.- O detector descarta tokens curtos isolados — um badge de uma letra e duas células de 2 caracteres, enquanto preserva uma terceira célula com formato idêntico.
- Leitura sistemática de
$comoSem valores monetários (3 de 4). - Cerca de 1 GB de memória residente por processo, além de uma dependência torch de ~2 GB.
- O último release é de setembro de 2024; o projeto está estável, mais do que em evolução ativa.
Quem deveria usar e quem deveria desistir
Vale avaliar o EasyOCR quando suas entradas forem limpas, na orientação correta, texto renderizado em tamanho razoável — screenshots, capturas de interface, PDFs rasterizados ou relatórios gerados — e você quiser um pipeline Python local, sem taxa de uso de fornecedor. Os resultados sintéticos em inglês rodando em CPU valem para esse cenário; fotos, escrita manual e outros scripts exigem testes separados.
Desista se qualquer um destes casos descreve suas entradas. Fotografias — meus números são de texto sintético renderizado e não dizem nada sobre ruído de câmera, perspectiva ou iluminação. Escrita manual — o próprio projeto não a reivindica. Scripts não latinos — o EasyOCR suporta mais de 80 idiomas, mas eu testei um, e as comparações acadêmicas publicadas são a referência nesse caso, não uma varredura sintética em inglês. Entradas arbitrariamente rotacionadas — a menos que você faça sua própria correção de orientação antes. Implantações com pouca memória — um gigabyte por worker se acumula rápido.
Antes de escolher OCR, inspecione o DOM e as respostas de rede. Se os valores desejados já existirem como texto estruturado, extrair essa fonte evita os erros de detecção e reconhecimento do OCR. OCR faz sentido quando pixels são a única representação disponível.
Alternativas e onde nosso stack se encaixa
EasyOCR é Apache-2.0 e self-hosted, sem taxa de uso de fornecedor, mas com custo real de computação e operação. PaddleOCR, Tesseract e modelos visão-linguagem não passaram por este benchmark, então não há conclusão direta de um contra o outro.
A comparação mais interessante não é OCR versus OCR. É se você deveria estar usando OCR mesmo.
A maior parte do trabalho de extração de screenshots que eu vejo é um contorno para uma página difícil de raspar — uma tabela renderizada em JavaScript, um dashboard atrás de login, um site que resistiu. Tirar print e rodar OCR parece o caminho de menor resistência, mas você joga fora texto estruturado perfeitamente bom e depois paga o “imposto do cifrão” para recuperar uma versão pior dele.
Nota do autor: Thunderbit é nossa opção gerenciada para extração de páginas web. Ele não foi executado nesses fixtures de imagem. A fronteira relevante é a representação da fonte: use extração via DOM/rede quando houver dados estruturados na web e avalie OCR quando pixels forem a única fonte.
Leituras relacionadas do mesmo banco de testes: a comparação completa de scrapers open source, a análise do Crawl4AI e uma visão mais ampla sobre extração orientada por IA para páginas que resistem a seletores.
Experimente o Thunderbit para extração de dados da web
Veredito
Vale usar EasyOCR? Sim — se suas imagens estiverem na orientação correta, seus glyphs tiverem pelo menos 12 pixels de altura e você estiver lendo script latino. Dentro dessas condições ele é muito bom — CER médio de 0.071 em texto limpo, 0.024 depois de normalizar caixa, leitura perfeita em 16 px e uma robustez a contraste melhor do que a reputação sugere. A API realmente cabe em duas linhas e a saída é determinística, o que importa mais do que muita gente admite quando você está depurando um pipeline.
Fora disso, ele falha de formas específicas e previsíveis. Texto abaixo de 10 px some no filtro min_size. Skew acima de 20° destrói a leitura. rotation_info resolve uma orientação ortogonal, resolve outra pela metade e piora a terceira com texto espelhado. Letras isoladas e tokens de dois caracteres caem fora do detector enquanto os vizinhos sobrevivem. Cifrões viram a letra S.
As falhas dos fixtures vieram dos dois estágios: caixas perdidas ou mal orientadas do lado geométrico e confusão entre cifrão e S do lado do reconhecimento. Trate upscale, normalização de orientação, crops com padding e correção de símbolos consciente do esquema como candidatos a validar, não como soluções universalmente seguras.
Só não teste do jeito que eu quase testei, com um harness quebrado e um número que você não entende. Renderize seus próprios fixtures, saiba exatamente qual é o ground truth e encontre seu próprio limite.
Experimente o Thunderbit para extração de dados da web Get Started Free
FAQs
O EasyOCR é preciso o bastante para extrair texto de screenshots em produção?
No dashboard sintético, os elementos correspondentes tiveram CER médio de 0.027, com 13 de 16 exatos. Três dos 19 elementos não foram detectados, e três de quatro cifrões viraram S. Se isso é aceitável — e se upscale ou correção consciente do esquema ajuda — precisa ser testado nos layouts-alvo.
Qual é o tamanho mínimo de fonte que o EasyOCR consegue ler?
Na prática, cerca de 12 pixels de altura renderizada do glyph. O parâmetro min_size=10 de readtext() descarta caixas detectadas com menos de 10 px, e o efeito é um precipício, não uma ladeira: o CER foi 0.77 a 8 px, 0.15 a 10 px, 0.04 a 12 px e 0 a 16 px. A faixa limpa no meu sweep ficou em 12–28 px. Se sua fonte for uma captura HiDPI feita em 1× ou um PDF rasterizado a 72 DPI, faça upscale antes do OCR em vez de reduzir min_size, porque esse filtro existe para suprimir detecções lixo.
rotation_info corrige imagens giradas no EasyOCR?
Não de forma confiável, e não de forma simétrica. Com rotation_info=[90,180,270] em três cópias ortogonalmente rotacionadas da mesma frase, a imagem a 270° se recuperou bem (CER 0.83 → 0.10), a de 180° apenas parcialmente (0.85 → 0.67, com parte da frase removida), e a de 90° ficou pior (0.81 → 0.92), devolvendo texto espelhado como VOW → MOA. Ele também não faz nada para pequenos ângulos de skew, porque só tenta de novo nos ângulos que você listar. Corrija a orientação antes de chamar o EasyOCR, em vez de confiar nesse parâmetro.
Quanta memória e espaço em disco o EasyOCR precisa?
Os pesos ocupam 93.7 MiB, baixados para ~/.EasyOCR/model/ no primeiro uso — 79.30 MiB para o detector e 14.44 MiB para o recognizer em inglês. A memória residente de pico no processo CPU novo medido foi de 984.5 MiB, além de uma instalação de torch de cerca de 2 GB. A inicialização fria do reader levou de 1.3 a 1.7 segundos; uma linha única limpa rodou depois com p50 perto de 0.062 segundos nesta máquina. detail=0 mudou o formato da resposta, não o tempo medido.
O EasyOCR é gratuito para uso comercial e ainda é mantido? Ele usa licença Apache-2.0, que é permissiva e amigável para uso comercial. Em 27 de julho de 2026, o repositório tinha 29.825 estrelas e 528 issues abertas, o último release era v1.7.2 de setembro de 2024 e o último push para o master foi em dezembro de 2025. Isso soa mais como estável do que abandonado — a arquitetura não muda há um tempo e a atividade migrou para o tracker de issues. Confirme você mesmo a licença e o estado dos releases antes de construir em cima dele.


