Reconhecimento de placas de carro com OpenCv e Google Vision API
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:
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.
É 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.
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.
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.
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
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:
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.
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.
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.