Deep Learning e OCR — Reconhecimento de Documentos

Diogo Floriano
Senior Sistemas
Published in
10 min readFeb 12, 2020

Com a transformação digital em vigor, muitas empresas estão preocupadas com a automatização de processos tradicionais. Um desses processos é o reconhecimento de documentos. Quem aí nunca precisou tirar várias fotos de um documento para se cadastrar em um banco digital, que atire a primeira pedra 😅.

A evolução da inteligência artificial (IA), tornou a classificação de objetos por imagem uma tarefa que está relativamente simples. Hoje é possível identificar se uma imagem contém um documento válido e extrair o seu conteúdo para validação de autenticidade.

Existem diversos serviços em nuvem que possibilitam o reconhecimento óptico de caracteres (OCR — Optical Character Recognition) através de imagens. No entanto, quando estamos falando de documentos, precisamos destacar uma área de interesse que contenha somente o conteúdo a ser extraído.

Depois da comparação de algumas alternativas, a Deep Learning YOLOYou Only Look Once — foi escolhida como solução para reconhecimento de objetos. Para seu treinamento, foram adquiridas diversas imagens de documentos de RG e CNH vigentes no período em que o trabalho foi desenvolvido (primeiro semestre de 2019).

A detecção de objetos em imagens não compreende somente a identificação do tipo de objeto, mas contempla também a localização do mesmo dentro da imagem. Essa localização é obtida através das coordenadas de uma caixa delimitadora — também conhecida, do termo inglês, como bounding box — que contém o objeto.

O algoritmo YOLO é um dos métodos de detecção de objetos mais eficientes e rápidos que temos disponível. Ele trouxe diversas inovações para comunidade de pesquisa em visão computacional. Através de uma Deep Learning baseada em Redes Neurais Convolucionais (CNN — Convolutional Neural Network), o algoritmo é capaz de extrair todos os objetos de uma imagem em uma única análise, diferente de métodos anteriores.

Mas como ele funciona de fato? Bem, é uma estratégia simples, mas um pouco extensa. Então vamos lá! Inicialmente a imagem é dividida em uma grade SxS, onde cada célula faz a previsão de m bounding boxes de possíveis objetos. Para cada bounding box, o algoritmo calcula um grau de confiança da possibilidade de conter um objeto qualquer.

Na Figura 1, a imagem a esquerda foi dividida em uma grade 13x13, contendo 169 células, e cada célula realizou a previsão de 5 bounding boxes. Isto resultou em uma imagem com 845 bounding boxes de possíveis objetos, que pode ser vista à direita na Figura 1.

Figura 1 — Exemplo do funcionamento do YOLO

Para cada bounding box, é executado o processo de classificação dos objetos através de uma distribuição de cada possível classe C. Na Figura 2, o algoritmo classificou 20 classes possíveis. A combinação do grau de confiança com a probabilidade da classe geram a pontuação final. Essa pontuação indica qual a probabilidade de uma determinada bounding box conter um objeto.

Figura 2 — Resultado da classificação de bounding boxes

Imagino que nesse momento você está olhando para a Figura 2 e pensando “Que bagunça é essa? 😱. Mas fique calmo, boa parte das bounding boxes detectadas possuem um grau de confiança muito baixo, então podemos definir um limiar mínimo, como 70%, e eliminar o que está abaixo deste valor. Agora restam somente as bounding boxes que realmente importam, veja a Figura 3 (destaque para esse doguinho fofinho, look at him 😆).

Figura 3 — Eliminação de bounding boxes com grau de confiança abaixo do limiar

Se a gente descer para um nível mais técnico, temos a Figura 4. Ela representa a estrutura da Rede Neural utilizada pelo YOLO, que possui 24 camadas convolucionais seguidas de 2 camadas totalmente conectadas (FC — Fully Connected). As camadas convolucionais são responsáveis por extrair as características dos objetos e criar mapas de características. As camadas FC são responsáveis por associar os resultados das convoluções com as classes de objetos adotadas.

Figura 4 — Arquitetura da rede neural YOLO

A última camada convolucional da rede possui um núcleo 1x1 e existe para reduzir os dados para uma matriz no formato SxSxO, onde O = 5*(C+5). A constante 5 é composta pelas informações que definem o bounding box:

  • X, Y, Width, Height que definem o retângulo do bounding box;
  • Grau de confiança.

Ufa! Chega de teoria, vamos por a mão na massa com a construção do modelo. Para o desenvolvimento desse projeto, foi utilizado uma implementação do YOLO com o framework Tensorflow chamada de Darkflow. Esta nos traz algumas vantagens, como a possibilidade de otimizar a execução da rede neural em diferentes hardwares e permitir que a aplicação seja embarcada em soluções móveis com mais facilidade.

A implementação do Darkflow permite importar modelos treinados a partir da versão em Darknet, que é o framework original do YOLO. Mas para construção de um modelo próprio, é necessário mudar a estrutura da rede e construir seu dataset contendo exemplos dos objetos a serem detectados. Que neste caso será: CNH, RG frente e RG verso.

O dataset foi construído utilizando imagens capturadas na Internet e de documentos físicos de uma contabilidade. Haviam imagens coloridas e P&B, dentre elas:

  • CNH: 493 imagens;
  • RG frente: 453 imagens; e
  • RG verso: 570 imagens.

Para o treinamento da rede, cada imagem do dataset deve estar acompanhada de um arquivo XML que descreve as coordenadas do bounding box. Este também deve identificar qual classe esse objeto pertence. Abaixo um exemplo deste arquivo no padrão Pascal VOC.

<annotation>
<folder>images</folder>
<filename>cnh-verso-1.jpg</filename>
<segmented>0</segmented>
<size>
<width>768</width>
<height>1024</height>
<depth>3</depth>
</size>
<object>
<name>cnh</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>132</xmin>
<ymin>168</ymin>
<xmax>686</xmax>
<ymax>532</ymax>
</bndbox>
</object>
</annotation>

Para gerar o arquivo acima, foi adaptada a ferramenta BBox Label Tool para gerar os arquivos no padrão Pascal VOC. Esta inicialmente havia sido desenvolvida para gerar arquivos de coordenada no padrão COCO, suportada apenas pela versão Darknet. Além disso, foram feitas melhorias na navegação entre imagens e na seleção de classes. O resultado final pode ser visto na Figura 5.

Figura 5 — Aplicativo em Python para gerar os arquivos de coordenada XML no padrão Pascal VOC

Para esta solução foram criados dois modelos: uma versão usando o YOLO para o rastreamento de objetos em imagens e outra versão utilizando o YOLO Tiny. A segunda é uma simplificação do YOLO com 9 camadas, utilizada para inferência rápida em vídeo.

A construção de um modelo próprio (novo) usando o Darkflow é simples, não há necessidade de mexer em código. A configuração das camadas da rede é realizada através de um arquivo de configuração (*.cfg). Este arquivo contém a quantidade de classes (C = 3) e o número de elementos na última camada de convolução (O = 5 x (3 + 5) = 40) que foram alterados.

Na etapa de treinamento, foi utilizado a técnica de Transfer Learning (TL). Que consiste na transferência de conhecimento de uma rede existente com classes semelhantes ao nosso problema. Desta forma, apenas os pesos das camadas FC foram ajustadas. Isso tudo é feito para que o tempo de treinamento e a quantidade de dados de treinamento sejam reduzidos. Neste caso, foi utilizado TL sob os modelos criados a partir do dataset Pascal VOC.

O treinamento foi realizado em uma instância EC2 na AWS do tipo P3, que conta com uma placa nVIDIA Tesla V100 com 16 GB de memória GPU. A máquina ainda conta com 8 vCPUs e 61 GB de memória RAM. O tempo de treinamento durou aproximadamente 2 horas para ambos os modelos. No total, foi gasto aproximadamente US$50,00 com o treinamento, ou R$267,67 com impostos e o Dólar a R$4,02 na época.

Bom, agora precisamos avaliar se os modelos atingiram o resultado esperado. Como possuímos dois modelos com objetivos diferentes, um é focado na inferência em imagens estáticas e o outro é completamente focado na inferência em vídeo. Sendo assim, temos que avaliá-los conforme seu propósito.

Então, para avaliar a precisão do modelo de inferência em imagens, foi criado um novo dataset com imagens de documentos de 20 pessoas nunca antes vistos pelo modelo. Durante os testes decidimos também separar CNH aberta e fechada para avaliar como o modelo reagiria. O resultado está na Tabela 1.

Tabela 1 — Resultado do treinamento do modelo treinado no YOLO

A CNH teve índices de acerto significativos, onde a CNH aberta facilitou o acerto da rede. Já o RG teve uma diferença mais significativa, o RG frente ficou 8 pontos percentuais abaixo do RG verso que obteve um resultado de 98,50% de acurácia. Um ponto importante que identificamos é que o treinamento ainda poderia melhorar. Poderíamos utilizar mais imagens capturadas de celulares, pois no nosso dataset a maioria dos documentos obtidos eram escaneados.

Já para o modelo baseado em inferência em vídeo, foi possível realizar o processamento com 30 FPS, utilizando uma máquina com processador Intel Core i5 de 2.2 GHz e 8 GB de RAM. Na detecção, o poder de processamento da máquina não é muito crítico, visto que o objetivo é detectar apenas um dos frames. No entanto, o resultado ficou bem abaixo do esperado, como é possível ver na Figura 6.

Figura 6 — Resultado do modelo para inferência em vídeo

Entretanto, o objetivo da solução se tornou trabalhar apenas com imagens. Assim, mesmo se o modelo feito com o YOLO Tiny apresentasse melhores resultados, não seria útil para o objetivo final do projeto. Mas a notícia boa é que o modelo treinado em YOLO, conseguiu resultados excelentes nos nossos testes. Então, podemos dar continuidade ao projeto.

Uma vez o documento identificado, é hora de extrair o texto para validações com o uso de OCR. Os nossos maiores inimigos são o alinhamento e a perspectiva do objeto dentro da imagem. Não temos como prever ou garantir que o usuário encaminhe uma imagem em perfeitas condições para que o OCR atue sem confundir os caracteres. A falta de alinhamento e/ou perspectiva distorcida podem reduzir drasticamente a acurácia da solução.

Para isso, trabalhamos com dois tratamentos na imagem, um conhecido como skew e o outro four point transform. Ambos são conceitos consagrados dentro da área de processamento de imagem. O primeiro consiste no alinhamento do texto em 90º baseado no alinhamento de linhas paralelas encontradas na imagem. O segundo, resumidamente, trata o ajuste de perspectiva calculando o tamanho dos objetos retangulares dentro da imagem e tratando os ângulos entre as arestas.

Toda imagem que entrar no aplicativo precisa passar por esses tratamentos antes de ser enviada para o OCR. É desta forma que tentamos garantir com que o que chegar ao OCR será uma imagem nítida, como pode ser visto na Figura 7. Caso algum dos tratamentos falhar, há grandes chances da imagem recebida ser incorreta.

Figura 7 — Exemplo de como os tratamentos skew e four point transform trabalham

No início do projeto, houveram testes com ferramentas Open Source (OpenCV EAST e o Tesseract V4). O OpenCV EAST disponibiliza uma Deep Learning previamente treinada chamada de EAST (An Efficient and Accurate Scene Text Detector) para detectar textos em imagens. O Tesseract, que foi originalmente criada pela HP e hoje está nas mãos da Google, ficou responsável pelo OCR. Combinando as duas ferramentas, temos um fluxograma da Figura 8.

Figura 8 — Fluxo do OCR utilizando OpenCV EAST e Tesseract

Após a entrada de uma imagem, o detector de texto faz a busca para delimitar a área exata com texto, criando uma bounding box. Para cada área encontrada, é aplicada a rotina de OCR do Tesseract, que utiliza uma Rede Neural Recorrente (RNN) pré-treinada para reconstruir palavras a partir de uma cadeia de caracteres. O resultado desta etapa pode ser visto na Figura 9.

Figura 9 — Resultado da aplicação do OpenCV EAST com o Tesseract

Infelizmente, como é possível ver na Figura 9, ambas as rotinas tiveram um resultado abaixo do ideal. O OpenCV EAST não conseguiu capturar todas as áreas com texto e o Tesseract não conseguiu reconhecer boa parte das palavras por completo, além de trazer vários caracteres especiais. Então, para economizar tempo utilizamos o AWS Rekognition, que possui resultados fantásticos com OCR.

A AWS disponibiliza um conjunto de soluções voltadas à visão computacional no serviço Rekognition, como identificação de objetos, pessoas, texto, cenas e atividades. Uma das principais vantagens deste serviço é que o usuário não precisa de nenhum conhecimento prévio em inteligência artificial ou processamento de imagem para utilizá-lo.

Então, utilizamos o AWS Rekognition Text Detections, que retorna as coordenadas delimitadora dos textos detectados e a cadeia de caracteres de cada uma delas. Não há necessidade de definir idioma e o serviço consegue alcançar uma precisão muito alta. O resultado pode ser visto na Figura 10.

Figura 10 — Resultado do OCR utilizando o serviço AWS Rekognition

Com o problema do OCR resolvido, precisamos definir uma estrutura de chave e valor para conseguir extrair da imagem cada informação separadamente. A estratégia adotada foi utilizar um algoritmo que calcule similaridade entre cadeias de caracteres, neste caso, a biblioteca difflib para Python. Nem sempre o OCR vai conseguir extrair a palavra corretamente, pode acontecer de “Nome” virar “Name”, por exemplo.

Com este algoritmo em mãos, o retorno do OCR é varrido em busca das palavras chaves contidas em cada documento, como: Nome, CPF, Registro Geral, Data de Nascimento e entre outros. Ao localizar cada uma das palavras chave, buscamos a posição correta do texto condizente ao valor desta chave, por exemplo, no caso da Figura 10, Naturalidade (chave) é Blumenau (valor). Desta forma, conseguimos uma estrutura similar ao quadro abaixo.

{
"nome": "Fulano de Tal",
"rg": "1234567",
"cpf" "123.456.789-00",
"data_nascimento": "01/01/1999",
"filiacao: "Ciclano de Tal, Beltrana de Tal"
...
}

Nesse ponto do desenvolvimento, conseguimos diferenciar o que é uma CNH, um RG frente e um RG verso, e extrair seu conteúdo para uma estrutura de dados de chave e valor. Podemos concluir que o objetivo inicial foi cumprido e alcançamos bons resultados para continuar movimentando o projeto.

Embora os resultados tenham sido bem positivos, existem ainda muitos desafios para tornar a solução robusta. Observamos que muitas imagens tiradas de celular são um grande desafio devido ao ângulo e a qualidade das imagens. Além disso, existe bastante trabalho pela frente, como treinar o modelo para classificar outros documentos, melhorar a precisão modelo e aprimorar a extração de texto.

Muito obrigado! Chegamos ao fim dessa breve experiência. Esse foi um resumo dos desafios e da rotina de experiência que envolveu o desenvolvimento de uma solução para reconhecimento e extração de texto dos documentos CNH e RG. Um agradecimento especial ao Daniel Theisges dos Santos que foi um dos pesquisadores que iniciou esse trabalho e deu uma mão para repassar essa granada para mim 😅.

--

--