Reconhecimento de placas de carro com OpenCv e Google Vision API

Rickson Gomes Monteiro
5 min readFeb 8, 2021

--

Placa após segmentação

Pequeno projeto de segmentação e reconhecimento de placas de carro utilizando o OpenCV e a google Vision API.
Antes de iniciar é necessário adicionar suas credencias do Google Vision para a utlização da API que será utilizada para o Reconhecimento Ótico de Caracteres.

Instruções para obter credenciais aqui.

os.environ["GOOGLE_APPLICATION_CREDENTIALS"]="[PATH].json"

Substitua “[PATH]” pelo caminho onde suas credencias estiverem salvas na sua máquina.

Segmentação

O processo de segmentação foi totalmente realizado com o auxílio da biblioteca de visão computacional OpenCV e foi dividido em 5 etapas.
-Inicialmente é feito a leitura da imagem e sua conversão para GrayScale, temos o exemplo a abaixo:

Imagens após a leitura e conversão para escala de cinza

Logo depois, aplicamos o cv2.bilateralFilter(), este filtro é bastante útil para remoção de ruídos com um ótima preservação de bordas. você pode encontrar mais informações sobre este método aqui.

Imagem após aplicação do cv2.bilateralFilter()

É possível perceber como a imagem tem uma aparência mais “cartunista” após a aplicação do filtro.

Agora com a imagem já suavizada é aplicada uma transformação morfológica conhecida como Black-Hat, ela é basicamente a diferença entre a imagem de fechamento (Imagem após as operações de dilatação e erosão) e a imagem de entrada, no nosso caso, a imagem suavizada. Essa operação é muito útil para encontrar “coisas” escuras em fundos claros, como é o caso dos digitos da placa. Neste link é possível obter mais informações sobre a operação. Após sua aplicação chegamos no resultado abaixo.

Imagem após operação black-hat

Em seguida aplicamos uma operação de fechamento afim de ressaltar os digitos da placa, pois após a operação black-hat eles obtiveram algumas falhas em seu interior. Ela também será útil para reduzir alguns ruídos externos. Neste link é possível entender um pouco mais sobre o funcionamento das operações morfológicas. Também iremos realizar uma binarização na imagem. Após os procedimentos temos os seguintes resultados.

Imagem após operação de fechamento e após limiarização

Como a queremos detectar uma placa, precisamos de alguma forma destacar a placa entre os outros objetos da imagem, para isso iremos utilizar o método cv2.Sobel() ele promove uma operação de alisamento gaussiano conjunto mais diferenciação, no nosso caso iremos usar a derivada na direção X afim de ressaltar os traços verticais (Isso mesmo, verticais! haha), pois são maioria na placa e em seus dígitos. No link é possível entender melhor seu funcionamento. Abaixo temos a imagem após o procedimento.

cv2.Sobel()

No entanto a imagem acima perdeu sua formatação dos valores, seus valores não estão mais entre [0–255] e seu “dtype” não é mais uint8, como de padrão nas imagens por esse fator a imagem acima aparece com tanto ruído. Dessa forma, é necessario realizar uma normalização para resgatar este intervalo de valores e seu tipo padrão. Após isso temos uma resultado melhor na imagem, como pode ser visto

Imagem após normalização do gradiente na direção x

Com a imagem já normalizada aplicamos um filtro gaussiano com kernel (9x9), afim de reduzir os ruídos restantes, seguida de outra operação de fechamento com o mesmo intuito da aplicada anteriormente. Assim chegamos no resultado abaixo:

Após aplicação do filtro cv2.GaussianBlur() e outra operação de fechamento

Por fim, é realizada outra operação de binarização na imagem. Com a imagem já binarizada aplicamos uma operação de erosão com 3 iterações seguida de uma operação de dilatação de com 9 iterações (Valores obtidos empíricamente). Com a erosão tentaremos reduzir os restantes dos ruídos, porém iremos perder parte da informação da placa, com a dilatação tentaremos recuperar parte dessa informação perdida.

Imagens após a segunda binarização e as operações de erosão e dilatação.

Após os procedimentos iremos enviar a imagem para a função crop que desenvolvi(Disponível no meu GitHub). Ela recebe a imagem após os últimos procedimento(imagem A) e a imagem em escala de cinza(Imagem B). A imagem “A” é submetida ao método cv2.findContourns(), com ela iremos conseguir todos os contornos da imagem e com o auxílio da cv2.boudingRect() conseguimos obter os vértices dos retângulos encontrados. A proporção das placas mercosul são de 40x13, assim temos uma proporção de 3.07. Dessa forma, considerei que apenas os retângulos encontrados que respeitassem uma proporção de valores entre [2–5]. Assim, com os vértices obtidos pude realizar um recorte na imagem em escala de cinza e obter a placa. Atualmente esse algoritmo de segmentação obteve uma acurácia de apenas 70%, porém acredito ser possível aumentar esse valor com a utilização de mais técnicas de processamento de imagem.

Placa após segmentação

Reconhecimento:

O Reconhecimento da placa é realizado através da API Google Vision utilizando técnicas de Reconhecimento Óptico de Caracteres (OCR), que basicamente nos permite reconhecer caracteres a partir de uma arquivo, neste caso será a imagem da placa. Neste link é possível obter uma melhor explicação de como utilizar.

Espero que tenho gostado, qualquer duvida ou sugestão podem estar entrando em contato para trocarmos um pouco de conhecimento haha! Obrigado pela leitura!

GitHub:

Neste link é possível obter o código do projeto em meu GitHub.

--

--

Rickson Gomes Monteiro

Control and Automation Engineering student at CEFET-MG. Enthusiast in the areas of artificial intelligence