Modelo para identificação dos caracteres da placa

Este post faz parte da série Reconhecimento automático de placas. Leia também os outros posts da série:

Este artigo descreve a etapa da identificação dos caracteres da placa de automóveis após a detecção da placa na etapa anterior.  A entrada dessa etapa é o recorte da placa a partir do bouding box obtido na etapa de detecção. Iremos abordar os métodos mais utilizados nesta tarefa, OCR e LPRNet, justificando a escolha da LPRNet. Então, apresentaremos os passos para criação de um dataset sintético com placas de veículos brasileiras e no novo modelo Mercosul para utilizar no treinamento da LPRNet. Por fim, detalharemos sobre o treinamento do modelo LPRNet, mostrando os resultados obtidos. 

OCR vs LPRNet 

Optical Character Recognition (OCR) é uma abordagem bastante popular para reconhecimento de caracteres em várias aplicações. Após obter o recorte da placa detectada, podemos segmentar os caracteres e usar um método de OCR para identificar cada caractere. Muitas implementações já incluem o pré-processamento com segmentação de caracteres no pipeline do OCR, como o EasyOCR.  

Por ser uma rede de propósito geral, e por isso treinada para reconhecer todos os caracteres de um determinado idioma (há vários modelos pré-treinados em Inglês), o OCR é um método pesado computacionalmente. Como alternativa ao OCR, foi proposta a arquitetura de rede neural LPRNet [Zherzdev, 2018], sendo um modelo leve e específico para reconhecimento de caracteres de placas de veículos. A LPRNet recebe a placa inteira como entrada e dá como resultado todos os caracteres da placa. É uma rede simples, sem pré-processamento para segmentação prévia dos caracteres como o pipeline do OCR.  

Dataset Sintético de Placas

A resolução 231/2007 e 509/2016 do CONTRAN especificam as características físicas de placas do modelo antigo e Mercosul, respectivamente. Por simplicidade, iremos nos ater às principais características da placa, como a fonte, tamanho e posicionamento dos textos. Detalhes como as furações e elementos de segurança da placa Mercosul não serão reproduzidos. As Figuras 1 e 2 mostram os resultados obtidos. 

Figura 1: Exemplo de placa sintética do modelo antigo 

Figura 2: Exemplo de placa sintética do modelo Mercosul 

No modelo antigo, a fonte Mandatory é utilizada para os caracteres, nome da cidade e estado. Já o modelo Mercosul utiliza a fonte FE Engschrift para a combinação alfanumérica e a fonte Gill Sans para os demais inscritos. Para ambos os modelos, a placa possui dimensões de 400 mm de largura por 130 mm de altura. 

Podemos descrever ambas as placas de forma genérica: São retângulos preenchidos com uma cor, com cantos arredondados e uma borda de cor diferente. No interior existe uma tarja com um inscrito (nome da cidade ou país), e os caracteres da placa centralizados logo abaixo. Assim, criamos uma classe base com um método genérico de geração de placa que recebe os caracteres da placa e o texto superior (nome da cidade ou do país, no caso do modelo Mercosul).  

A fim de gerar um código mais conciso, utilizaremos a orientação a objetos do Python para criar uma classe base, Plate, que possuirá um método genérico, gen(text, top_text), A partir dessa classe base, criamos duas classes que herdam dela, Antigo e Mercosul, que especializam o método para os modelos antigo do Brasil e Mercosul, respectivamente. 

Além disso, também definimos o método augstr, que gera uma string com base em um padrão de dígitos e letras passado como argumento. Este método também pode receber um vetor de pesos que define a probabilidade de cada caractere do vocabulário definido (letras do alfabeto a-z e dígitos de 0-9) serem sorteados na geração da string. Esses pesos foram definidos com o objetivo de balancear o dataset, buscando gerar um número de exemplos similar para cada um dos caracteres. 

Também desenvolvemos uma série de transformações para trazer variabilidade no dataset com o objetivo de trazer maior robustez ao modelo em treinamento. Por exemplo, a transformação noise adiciona ruído branco a imagem: 

E a transformação warp sorteia quatro pontos, constrói uma matriz de transformação com cv2.getPerspectiveTransform e então invoca o método cv2.warpPerspective para gerar uma distorção de perspectiva aleatória: 

Também foram definidas transformações para alterar brilho, saturação e desfoque de forma aleatória. 

Finalmente, o método gen_dataset foi desenvolvido para gerar as placas sintéticas com os caracteres sorteados pela função augstr, aplicar um número aleatório de transformações sobre a placa gerada, e criar o arquivo com a etiqueta da imagem para ser utilizado no treinamento. 

Os argumentos batch_num e batch_size indicam, respectivamente, o número e tamanho dos batches de imagens a serem gerados. Para promover o balanceamento entre as classes, a lista de pesos utilizada pelo método augstr é atualizada entre cada batch com o inverso da frequência dos caracteres. A divisão em batches evita esse cálculo a cada imagem, e também facilitará a paralelização em versão futuras do código. O dicionário vocab é utilizado para contar o número de ocorrências de cada caractere. Para evitar uma divisão por zero, todas as chaves do dicionário são inicializadas com o valor um. 

Para cada imagem do batch, uma placa com largura entre 100 e 1920 pixels é construída com os caracteres sorteados por augstr. Em seguida, um número aleatório de transformações é aplicado na imagem obtida. A imagem final é ajustada para as dimensões de entrada da rede LPRNet (96×48) e salva no diretório output/, utilizando os caracteres sorteados como nome do arquivo. Para facilitar a utilização com alguns scripts de treinamento, um arquivo de texto com o mesmo nome da imagem também é gerado, contendo apenas os caracteres da placa. 

A Figura 3 apresenta alguns exemplos de placas geradas para o dataset sintético de placas do modelo antigo e Mercosul.

Exemplos de placas  
Figura 3: Exemplos de placas   

Para realizar o treinamento e validação do modelo de reconhecimento de caracteres LPRNet, geramos 600 batches de 100 imagens do modelo antigo e 600 de 100 imagens do modelo Mercosul, dividindo essas imagens igualmente em três conjuntos: treinamento, validação e teste. Esse dataset gerado está disponível na plataforma Kaggle

Treinamento da LPRNet 

Nós utilizamos o modelo LPRNet disponilizado pela NVIDIA, pois o treinamento pode ser realizado usando o Toolkit NVIDIA TAO, e este toolkit também pode ser usado para exportar o modelo treinado em TensorRT, além de uma ampla documentação oficial. A NVIDIA disponibiliza alguns containers Docker com o TAO já instalado e alguns modelos configurados. Para o caso da LPRNet, é disponibilizado um container com o TAO para visão computacional, o TAO Toolkit for CV. Utilizamos a versão v3.21.08-py3 do container, a qual contém a versão CUDA 11.4 e TensorRT 8.0.1. Dessa forma, para utilizar o container Docker (para instalação e configuração do Docker consultar a seguinte documentação) use o comando para realizar o pull da imagem:

Então, o container pode ser criado e executado a partir dessa imagem:

Dentro do container, é necessário organizar os arquivos necessários para treinamento do modelo. Primeiro, criamos uma pasta chamada lprnet dentro do diretório /workspace, e então organizamos o dataset com estrutura no formato apresentado na Figura 4, em /workspace/lprnet

Figura 4: Estrutura do diretório do dataset, com as imagens e labels separadas em diferentes pastas. 

Tanto o conjunto de treinamento como de teste deve seguir essa estrutura. Criamos ambos no diretório /workspace/lprnet/dataset_lprnet_antigo_mercosul/

Após organizar os conjuntos de treinamento e validação, criamos o diretório /workspace/lprnet/lprnet_trainable para armazenas os pesos pré-treinados e o arquivo com a lista de caracteres do modelo, ambos disponibilizados neste link. Ao realizar o download dos arquivos, extrai-os no diretório criado. Usamos o modelo pré-treinado com placas de veículos dos Estados Unidos, us_lprnet_baseline18_trainable.tlt. Alteramos o arquivo com a lista de caracteres corresponde, us_lp_characters.txt, para incluir o caractere O e usamos esse arquivo para treinar o modelo com placas antigas e do Mercosul. 

Depois dessas etapas, é necessário criar um arquivo com as especificações do treinamento, como detalhado na seção Creating an Experiment Spec File. Criamos o arquivo /workspace/lprnet/specs/lprnet_spec.txt, copiando o exemplo apresentado neste link e alterando os seguintes parâmetros: 

max_label_length: no caso das placas de veículos antigas do Brasil e as do Mercosul, esse valor deve ser 7

nlayers: como usamos o modelo pré-treinado us_lprnet_baseline18_trainable.tlt, esse parâmetro deve ser 18

batch_size_per_gpu: aumentamos esse valor para 64

num_epochs: reduzimos esse valor para 50, pois estamos fazendo fine-tuning; 

image_directory_path de data_sources: caminho para a pasta contendo as imagens de treinamento; 

label_directory_path de data_sources: caminho para a pasta contendo os labels de treinamento; 

image_directory_path de validation_data_sources: caminho para a pasta contendo as imagens de validação; 

label_directory_path de validation_data_sources:  caminho para a pasta contendo os labels de validação; 

characters_list_file:  caminho para o arquivo com a lista de caracteres. 

A Figura 5 apresenta a estrutura final do arquivo lprnet_spec.txt, com os novos valores dos parâmetros descritos acima. 

Figura 5: Estrutura do arquivo lprnet_spec.txt após alterar o valor dos parâmetros descritos. 

Ao concluir esses passos, deve-se criar uma pasta para salvar os pesos gerado durante o treinamento, criamos a pasta /workspace/lprnet/experiment_dir_unpruned. Então, o treinamento do modelo LPRNet para placas antigas brasileiras e do Mercosul pode ser realizado com o seguinte comando:

Utilizamos os seguintes parâmetros: 

-e: passa o arquivo com as especificações de treinamento  

-r: indica o diretório para salvar os modelos gerados durante o treinamento 

-m: passa o modelo pré-treinado a ser utilizado no treinamento 

–gpus: indica o número de GPUs <NGPUS> a ser utilizado no treinamento. Se desejar utilizar apenas uma, identificar através do parâmetro –gpu_index=<IDX_GPU>, substituindo <IDX_GPU> pelo índice da GPU, o qual pode ser obtido com o comando nvidia-smi. Mais detalhes sobre os parâmetros do comando train podem ser encontrados na seguinte documentação.  

Os modelos gerados ao longo do treinamento, com extensão .tlt, são salvos no diretório passado com o parâmetro -r, neste caso /workspace/lprnet/experiment_dir_unpruned/. O processo de treinamento também gera um arquivo de log training_log.csv com os valores de loss do conjunto de treinamento calculada a cada época e as acurácias do conjunto de validação obtidas a cada cinco épocas. As Figuras 6 e 7 mostram os gráficos gerados a partir do histórico da loss de treinamento e do histórico da acurácia de validação, respectivamente. 

Figura 6: Histórico da loss do conjunto de treinamento nas 50 épocas. 

Figura 7: Histórico da acurácia do conjunto de validação calculada a cada 5 épocas. 

Observando os gráficos apresentados, notamos que a loss de treinamento estabiliza a partir de 15 épocas. Já a acurácia de validação fica estável a partir de 30 épocas. Dessa forma, escolhemos o modelo salvo na 30ª época. Avaliamos esse modelo escolhido com o conjunto de teste. Para isso, primeiro é necessário alterar os parâmetros image_directory_path e label_directory_path de validation_data_sources do arquivo lprnet_spec.txt, indicando o caminho dos labels e imagens do conjunto de teste, respectivamente: 

Após configurar os caminhos para o conjunto de teste, basta executar o seguinte comando: 

Os parâmetros utilizados foram: 

-e: passa o arquivo com as especificações do experimento  

-m: indica o modelo que desejamos avaliar 

–gpu_index: identifica o índice da CPU <IDX_GPU> que será utilizada para avaliar o modelo, o qual pode ser obtido com o comando: $ nvidia-smi

Este comando executa a inferência para as 12 mil imagens de teste, calculando a acurácia de acordo com os labels de teste. Obtivemos uma acurácia de aproximadamente 99,7%, o que é um resultado bem próximo ao obtido com o conjunto de validação. Isso indica que o modelo conseguiu aprender os padrões das placas e generalizar para um novo conjunto. 

Para ser otimizado para a Jetson Nano, vamos exportar esse modelo em TensorRT. Para isso, precisamos primeiro exportar o modelo na extensão .tlt para a extensão .etlt para deployment. Esse processo é realizado usando o seguinte comando: 

Utilizamos os seguintes parâmetros: 

-m: passa o modelo na extensão .tlt que queremos exportar 

-e: passa o arquivo com as especificações do experimento  

-o: indica o diretório e o nome do modelo que será exportado para extensão .etlt 

–gpu_index: identifica o índice da CPU <IDX_GPU> que será utilizada para exportar o modelo, o qual pode ser obtido com o comando nvidia-smi

Mais detalhes sobre os parâmetros do comando export podem ser encontrados na seguinte documentação. Ao final da execução do comando acima, o modelo lprnet_model.etlt é gerado no diretório /workspace/lprnet/experiment_dir_unpruned/export/. Disponibilizamos o modelo treinado e exportado no arquivo modelos.zip, dentro da pasta lprnet

Próximos passos

No artigo anterior da série apresentamos como treinar um modelo de detecção de placas de automóveis usando a YOLOv4-tiny. Neste artigo mostramos os passos para gerar um dataset de placas sintéticas e treinar um modelo de reconhecimento de placas de veículos usando a LPRNet. Este é o segundo passo para o reconhecimento automático dessas placas, em que a partir da placa detectada no passo anterior, são reconhecidos os caracteres desta. No próximo artigo abordaremos a implementação destes passos usando a Jetson Nano. 

[Wikipedia Typeface, 2021] Wikipedia. Typeface: Font metrics. URL: https://en.wikipedia.org/wiki/Typeface#Font_metrics. Acessado em: 28/01/2022. 

[Zherzdev, 2018] Sergey Zherzdev e Alexey Gruzdev. Lprnet: License plate recognition via deep neural networks. arXiv preprint arXiv:1806.10447 (2018). 

Autores

  • Geise Santos
  • Matheus Kowalczuk Ferst
  • Elton de Alencar
  • Lucas Coutinho
  • Murilo Pechoto

Outros artigos da série

Implementação na Jetson Nano >>Reconhecimento automático de placas de identificação de veículos em uma Jetson Nano usando YOLOv4-tiny e LPRNet >>

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Home » Software » Modelo para identificação dos caracteres da placa
Comentários:
Notificações
Notificar
guest
0 Comentários
Inline Feedbacks
View all comments
Talvez você goste:
Nenhum resultado encontrado.
Menu