
Atualmente é comum no cadastro de APPs de fintechs como Nubank, Banco Inter e Neon uma etapa de envio de fotos de documentos como RG e CPF, os textos desses documentos são extraidos e processados para verificar a autenticidade deles (automaticamente).
Essa tecnologia que extrai textos de imagens (documentos escaneados, fotos, pdf’s de imagem) é chamada de OCR (Optical Character Recognition) e você vai descobrir como utiliza-la.
Nesse artigo você vai aprender como criar um APP Mobile (usando React Native + Express + Tesseract.js) que vai utilizar OCR para extração de textos de fotos tiradas com o APP, então vem com a gente 😁
O que vamos desenvolver:
Para melhorar a apresentação do conteúdo este tutorial será dividido em duas partes, na parte 1 aprenderemos a criar uma API com Express que extrai textos de imagens usando Tesseract.js e retorna via Json e na parte 2 desenvolveremos um aplicativo com React Native que se conecta a API para converter as frases das fotografias tiradas.
Caso você deseje ver os códigos do projeto completo: Link do projeto no GitHub
Nossas ferramentas:
- Nodejs
- Yarn
- Tesseract.js
- Postman
- Express
Obs: Neste artigo vamos utilizar o Yarn (você pode usar o npm se desejar), então pra quem não tem o Yarn, só ir neste link das docs e instalar: https://yarnpkg.com/en/docs/install
Configurando o projeto
1 – Inicialmente criaremos a pasta do nosso projeto e inicializaremos o yarn com:
1 |
mkdir api_ocr && cd api_ocr |
1 |
yarn init -y |
2 – Uma vez inicializado o yarn, vamos adicionar as dependências básicas do express:
1 |
yarn add express body-parser |
3 – Agora instalaremos o babel para usar os recursos do ES6+:
1 |
yarn add babel-cli babel-plugin-transform-object-rest-spread babel-preset-env |
4 – Crie um arquivo na raiz do projeto chamado .babelrc e adicione o seguinte conteúdo:
1 2 3 4 |
{ "presets": ["env"], "plugins": ["transform-object-rest-spread"] } |
5 – Para facilitar a execução do babel ao iniciar nosso servidor, adicione ao package.json o seguinte conteúdo:
1 2 3 |
"scripts": { "start": "babel-node ./server.js" }, |
Seu package.json deve ficar da seguinte forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "name": "api_ocr", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "body-parser": "^1.19.0", "express": "^4.17.1", }, "scripts": { "start": "babel-node ./server.js" }, "devDependencies": { "babel-cli": "^6.26.0", "babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-preset-env": "^1.7.0" } } |
Com isso já podemos dar início a configuração do tesseract.
Adicionando o Tesseract.js ao projeto
O Tesseract.js é uma implementação em puro javascript da biblioteca Tesseract OCR que foi inicialmente desenvolvida pela HP entre 1985 e 1994 e que é atualmente mantida pelo google.
Para instalar o Tesseract.js é necessário instalar o Tesseract OCR, neste artigo será utilizada uma instalação para Ubuntu 18.04. Entretanto é possível encontrar guias de instalação em plataformas no link do projeto.
1 – Instale as bibliotecas:
1 2 |
sudo apt install tesseract-ocr sudo apt install libtesseract-dev |
2 – Instale o pacote da língua portuguesa (de Portugal) do Tesseract:
1 |
sudo apt install tesseract-ocr-por |
3 – Adicione o Tesseract.js ao projeto:
1 |
yarn add node-tesseract-ocr |
O Tesseract por si só suporta diversos idiomas (100 idiomas para ser mais preciso), por padrão a biblioteca já possui o dicionário dessas linguagens separadas em módulos. Caso queira adicionar suporte a mais idiomas basta olhar na documentação a sigla da linguagem e instalar o pacote no link: Tesseract Linguagens.
Criando o servidor
1- Crie na raiz do projeto um arquivo chamado server.js com o seguinte conteúdo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Importa as dependências do express import express from 'express' import bodyParser from 'body-parser'; const app = express(); // Adiciona o body-parser ao projeto app.use(bodyParser.urlencoded({ extended: true })) // Cria endpoint localhost:3000/upload app.post('/upload', async (req, res, next) => { res.send('Escola de Javascript'); }) // Inicia o servidor na porta 3000 app.listen(3000, function () { console.log('Server listening on port 3000!'); }); |
2 – Inicie a aplicação:
1 |
yarn start |
3 – No postman tente acessar a url http://localhost:3000/upload com um método POST, você deverá receber uma resposta contendo: “Escola de Javascript”.
Upload de arquivos
Iremos adicionar ao nosso endpoint a habilidade de aceitar upload de imagens, para isto usaremos a biblioteca multer.
1 – Adicione a biblioteca multer ao projeto:
1 |
yarn add multer |
2 – Crie uma pasta chamada config e a pasta images.
1 |
mkdir config images |
- config – será utilizada para guardar configurações de bibliotecas extras da nossa api.
- images – local onde serão salvas as imagens temporariamente para processamento.
3 – Dentro da pasta config adicione um arquivo chamado storage.js com o seguinte conteúdo:
// diretório do projeto/config/storage.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import path from 'path' const multer = require('multer'); // Cria instância do multer const storage = multer.diskStorage({ // Configura o destino dos arquivo recebidos => /images destination: function (req, file, cb) { cb(null, 'images') }, // Após o upload renomeia os arquivos filename: function (req, file, cb) { cb(null, file.fieldname + '_' + Date.now()) } }); // Exporta a instância configurada export default multer({ storage: storage, fileFilter: function (_req, file, callback) { const ext = path.extname(file.originalname); // Permite apenas upload de arquivos de imagem if (ext !== '.png' && ext !== '.jpg' && ext !== '.gif' && ext !== '.jpeg') { return callback(new Error('Apenas imagens são permitidas')) } callback(null, true) }, // Limita o tamanho das imagens limits: { fileSize: 1024 * 1024 } }); |
Com nosso storage configurado, podemos editar nosso server.js para receber os arquivos.
4 – Edite o arquivo server.js para adicionar o multer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import express from 'express' import bodyParser from 'body-parser'; // Importa a instância do multer configurada import upload from './config/storage'; const app = express(); app.use(bodyParser.urlencoded({ extended: true })) // Adiciona o multer ao endpoint app.post('/upload', upload.single('image'), async (req, res, next) => { const file = req.file // Retorna erro caso nenhum arquivo tenha sido enviado if (!file) { const error = new Error('Envie o arquivo a ser tratado'); error.httpStatusCode = 400; return res.json(error) } // Retorna as informações do arquivo em caso de sucesso res.send(file); }) app.listen(3000, function () { console.log('Server listening on port 3000!'); }); |
Agora nossa api aceita upload de arquivos 😎!
Configurando o Tesseract.js
Até o momento nossa api recebe uma imagem e salva na pasta images, para adicionar o Tesseract.js ao projeto iremos criar uma pequena biblioteca que interage com o tesseract.
1 – Crie uma pasta chamada lib:
1 |
mkdir lib |
2 – Na pasta lib crie o arquivo imageHandler.js:
1 |
touch lib/imageHandler.js |
3 – No arquivo criado adicione o seguinte conteúdo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
// Importa as bibliotecas import * as tesseract from 'node-tesseract-ocr'; import fs from 'fs'; // Configura o Tesseract.js const config = { lang: 'por', // Pacote de idioma (por == Português) oem: 1, // Rede neural Long short-term memory (LSTM) psm: 3 // Segmentação de letras } /** Legenda psm * 0 = Orientação e detecção de scripts apenas (OSDI). * 1 = Segmentação de página automática com OSD. * 2 = Segmentação de página automática, sem OSD ou OCR. * 3 = Segmentação de página automática, sem OSD. (Padrão) * 4 = Assume uma coluna única de texto de tamanho variável. * 5 = Assume um bloco único e justificado de texto verticalmente alinhado. * 6 = Assume um bloco justificado de texto. * 7 = Trata a imagem como uma única linha de texto. * 8 = Trata a imagem como uma única palavra. * 9 = Trata a imagem como uma única palavra num círculo. * 10 = Trata a imagem como um caracter único. */ export async function extractText(filePath) { // Retorna uma promise com o resultado ou erro return new Promise((resolve, reject) => { // Inicia promise do Tesseract tesseract.recognize(filePath, config) .then(text => { // Limpa imagem temporária clearImage(filePath); // Retorna string do resultado resolve(text); }) .catch(error => { // Limpa imagem temporária clearImage(filePath); // Retorna erro reject(error); }) }); } // Limpa imagem temporária na pasta /images function clearImage(filePath) { fs.unlinkSync(filePath); } |
Com a biblioteca criada, basta alterar o server.js novamente para utilizar a biblioteca no endpoint.
4 – Altere o arquivo server.js para a seguinte forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import express from 'express' import bodyParser from 'body-parser'; import upload from './config/storage'; import { extractText } from './lib/imageHandler'; const app = express(); app.use(bodyParser.urlencoded({ extended: true })) app.post('/upload', upload.single('image'), async (req, res, next) => { const file = req.file if (!file) { const error = new Error('Envie o arquivo a ser tratado'); error.httpStatusCode = 400; return res.json(error); } // Inicia a extração de texto await extractText(file.path).then(text => { const result = { data: text, ...file }; res.json(result); }).catch(error => { res.json(error); }); }) app.listen(3000, function () { console.log('Server listening on port 3000!'); }); |
Testando resultados
Agora que finalizamos a nossa API é hora de testar para verificarmos se ela realmente está extraindo corretamente os textos das imagens enviadas (lembrando que a clareza da imagem faz diferença no resultado):
1 – Usaremos a seguinte imagem como teste (caso deseje usar a mesma clique aqui para baixar):
1 – Inicie o servidor
1 |
yarn start |
2 – Abra o postman com a seguinte url:
1 |
http://localhost:3000/upload |
3 – Configure o Body da requisição para “form-data” e crie um campo do tipo “File” chamado image (você pode escolher o tipo file colocando o mouse sobre o campo key e escolhen a opção que vai aparecer).
4 – Clique no botão “Escolher arquivos”.
5 – Selecione um arquivo de imagem contendo o texto que deseja extrair.
6 – Clique em “Send” para efetuar a requisição.
7 – Caso tenha usado a imagem exemplo, o resultado deve ser algo parecido com isto:
8 – Parabéns por concluir a parte 1 do tutorial o/
Conclusão
Neste artigo aprendemos um pouco sobre o Tesseract.js e OCR com javascript e sobre criação de APIs usando Express, na continuação dele criaremos nosso app mobile com React Native para se conectar a API criada.
Se você gostou deste conteúdo e quer aprender mais sobre visão computacional (ou outro tema no mundo javascript) deixa um comentário ai em baixo, também compartilha esse artigo com seus amigos programadores para incentivar a continuação deste trabalho.
Muito legal!
Aguardando a parte II.
Obrigado pelo comentário, estamos trabalhando nela 😀
Fiz o exemplo, porém apesar do status code 200, ele retornou :
{
“killed”: false,
“code”: 1,
“signal”: null,
“cmd”: “tesseract images\\image_1560859252050 stdout -l por –oem 1 –psm 3”
}
E aí Anderson, beleza? Você está usando qual sistema operacional?
Olá Anderson. Você usa o que? Linux ou Windows?
Caso use windows, configurou o tesseract no path do windows? Um erro provável está no caminho “images\\image_1560859252050”. Normalmente, as pastas Documentos, Imagens, Videos, etc no windows geram problemas de path. É necessário passar todo o path da imagen caso contrário o cmd quando rodar o tesseract não a encontrará.
Exemplo:
Ao invés de passar “images\\image_1560859252050” seria “C:\\Users\\\\…resto do path da imagem”
Olá, muito bom o tutorial, mas fui testar e não retornou o texto
Retorno:
{
“killed”: false,
“code”: 1,
“signal”: null,
“cmd”: “tesseract images\\image_1560862339769 stdout -l por –oem 1 –psm 3”
}
Alguma dica do que pode ser?
Estou usando Windows – testei o tesseract no cmd e deu tudo certo.
Conseguiu resolver como?
Muito bom! Fiz no macbook e funcionou certinho, claro tive que configurar algumas coisa pra poder rodar. Aguardando a segunda parte
Obrigado por comentar aqui o/
Bacana o tutorial. Difícil não deixar um “Parabéns bem top” como sempre
Gostei do post. Será que não tem integração direto com o React Native para que o processo de OCR seja offline, já que a biblioteca suporta conversão sem rede? 😀