Reconocimiento de matrículas con Raspberry Pi y OpenCV

Reconocimiento de matrículas con Raspberry Pi y OpenCV

La seguridad siempre ha sido una de las principales preocupaciones de la humanidad. Hoy en día tenemos cámaras de video vigilancia en escuelas, hospitales y cualquier otro lugar público para que nos sintamos seguros.

Según una encuesta de HIS, se estima que en 2014 había alrededor de 245 millones de cámaras de seguridad instaladas y en funcionamiento, lo que es como tener una cámara de seguridad por cada 30 personas en este planeta. Con el avance de la tecnología, especialmente en el procesamiento de imágenes y el aprendizaje automático, es posible hacer que estas cámaras sean más inteligentes al capacitarlas para procesar la información de la alimentación de vídeo.

El video de estas cámaras puede ser utilizado para realizar reconocimiento facial, análisis de patrones, análisis de emociones y mucho más, lo que realmente lo acercaría a algo como el «Ojo de Dios» que se muestra en la película del FF7. De hecho, empresas de vigilancia como Hikvision y muchas otras ya han comenzado a implementar estas características en sus productos.

Anteriormente utilizábamos el procesamiento de imágenes de MATLAB para leer la matrícula, hoy en este artículo aprenderemos a reconocer y leer el número de matrícula de los automóviles con Raspberry Pi y OpenCV ( (Open Source computer vision). Usaremos algunas imágenes aleatorias de vehículos de Google y escribiremos un programa para reconocer la matrícula usando OpenCV Contour Detection y luego leeremos el número de la matrícula usando Tesseract OCR. Suena interesante, así que empecemos.

Requisitos previos

Como ya se ha dicho, utilizaremos la librería OpenCV para detectar y reconocer caras. Así que asegúrese de instalar la librería OpenCV en Raspberry Pi antes de proceder con este tutorial. También encienda su Pi con un adaptador de 2A y conéctelo a un monitor de pantalla para facilitar la depuración.

Este tutorial no explica exactamente cómo funciona OpenCV, si está interesado en aprender sobre el procesamiento de imágenes, eche un vistazo a los tutoriales básicos y avanzados de procesamiento de imágenes de OpenCV. También puede aprender sobre contornos, detección de manchas, etc. en este tutorial de segmentación de imágenes utilizando OpenCV. Vamos a hacer algo similar a esto para detectar la matrícula del coche a partir de la imagen.

Pasos a seguir en el reconocimiento de matrículas con Raspberry Pi

El reconocimiento de matrículas o LPR, para abreviar, implica tres pasos principales. Los pasos son los siguientes

1. Detección de matrículas: El primer paso es detectar la matrícula desde el coche. Usaremos la opción de contorno en OpenCV para detectar objetos rectangulares y encontrar la matrícula. La precisión puede mejorarse si conocemos el tamaño exacto, el color y la ubicación aproximada de la matrícula. Normalmente, el algoritmo de detección se entrena en función de la posición de la cámara y el tipo de placa de matrícula utilizada en ese país en particular. Esto se complica si la imagen ni siquiera tiene coche, en este caso vamos a dar un paso más para detectar el coche y luego la matrícula.

2. Segmentación de caracteres: Una vez que hemos detectado la Placa de matrícula tenemos que recortarla y guardarla como una nueva imagen. Una vez más, esto se puede hacer fácilmente usando OpenCV.

3. Reconocimiento de caracteres: Ahora, la nueva imagen que obtuvimos en el paso anterior seguramente tendrá algunos caracteres (Números/Alfabetos) escritos en ella. Por lo tanto, podemos realizar OCR (Reconocimiento Óptico de Caracteres) en él para detectar el número. Ya hemos explicado el Reconocimiento Óptico de Caracteres (OCR) mediante el uso de Raspberry Pi.

1. Detección de matrículas

El primer paso en este Lector de Placas Raspberry Pi es detectar la Placa de Licencia. Tomemos una imagen de muestra de un coche y comencemos con la detección de la matrícula del mismo. Entonces usaremos la misma imagen para la segmentación y el reconocimiento de caracteres. Si desea saltar directamente al código sin explicación, puede desplazarse hacia abajo hasta la parte inferior de esta página, donde se proporciona el código completo. La imagen de prueba que estoy usando para este tutorial se muestra a continuación.

deteccion de matriculas en un autoPaso 1: Cambie el tamaño de la imagen al tamaño requerido y luego póngala en escala de grises. El código de la misma se indica a continuación:

img = cv2.resize(img, (620,480) )
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #convert to grey scale

Redimensionar nos ayuda a evitar cualquier problema con imágenes de mayor resolución, asegurándonos de que la matrícula permanece en el marco después del redimensionamiento. La escala de grises es común en todos los pasos de procesamiento de imágenes. Esto acelera otros procesos posteriores, ya no tenemos que ocuparnos de los detalles de color cuando procesamos una imagen. La imagen se transformaría de la siguiente manera cuando se realice este paso:

imagen en escala de grises del auto para detectar la matriculaPaso 2: Cada imagen tendrá información útil e inútil, en este caso para nosotros sólo la matrícula es la información útil y el resto de la información no sirve para nuestro programa. Esta información inútil se llama ruido. Normalmente, el uso de un filtro bilateral (Bluring) eliminará los detalles no deseados de una imagen. El código para el mismo es:

gray = cv2.bilateralFilter(gray, 11, 17, 17)

La sintaxis es destination_image = cv2.bilateralFilter(imagen_fuente, diámetro del píxel, sigmaColor, sigmaSpace). Puede aumentar el color sigma y el espacio sigma de 17 a valores más altos para difuminar más información de fondo, pero tenga cuidado de que la parte útil no se difumine. La imagen de salida se muestra a continuación, como puede ver los detalles del fondo (árbol y edificio) están borrosos en esta imagen. De esta manera podemos evitar que el programa se concentre en estas regiones más adelante:

resultado de cv2 bilateralFilterPaso 3: El siguiente paso es interesante cuando realizamos la detección de bordes. Hay muchas maneras de hacerlo, la más fácil y popular es usar el método canny edge de OpenCV. La línea de código para hacer esto se muestra a continuación:

edged = cv2.Canny(gray, 30, 200) #Perform Edge detection

La sintaxis será destination_image = cv2.Canny(source_image, thresholdValue 1, thresholdValue 2). El valor umbral 1 (thresholdValue 1)y el valor umbral 2 (thresholdValue 2) son los valores umbral mínimo y máximo. Sólo se mostrarán los bordes que tengan un gradiente de intensidad superior al valor umbral mínimo e inferior al valor umbral máximo. La imagen resultante se muestra a continuación:

edge detectionPaso 4: Ahora podemos empezar a buscar contornos en nuestra imagen.

nts = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:10]
screenCnt = None

Una vez que los Contornos han sido detectados los clasificamos de grandes a pequeños y consideramos sólo los primeros 10 resultados ignorando los otros. En nuestra imagen el contador puede ser cualquier cosa que tenga una superficie cerrada pero de todos los resultados obtenidos el número de placa también estará allí ya que es también una superficie cerrada.

Para filtrar la imagen de la matrícula entre los resultados obtenidos, recorreremos todos los resultados y comprobaremos cuál tiene un contorno en forma de rectángulo con cuatro lados y una figura cerrada. Ya que una placa de matrícula sería definitivamente un rectángulo de cuatro lados.

# loop over our contours
for c in cnts:
                # approximate the contour
                peri = cv2.arcLength(c, True)
                approx = cv2.approxPolyDP(c, 0.018 * peri, True)
                # if our approximated contour has four points, then
                # we can assume that we have found our screen
                if len(approx) == 4:
                      screenCnt = approx
                      break

El valor 0.018 es un valor experimental; puedes jugar a su alrededor para comprobar cuál funciona mejor para ti. O llévalo al siguiente nivel usando la Machine Learning para hacer un entrenamiento basado en imágenes de coches y luego usa el valor correcto allí. Una vez que hemos encontrado el contador correcto lo guardamos en una variable llamada screenCnt y luego dibujamos un rectángulo alrededor de él para asegurarnos de que hemos detectado la matrícula correctamente.

deteccion de contornosPaso 5: Ahora que sabemos dónde está la matrícula, el resto de la información es bastante inútil para nosotros. Así que podemos proceder a enmascarar toda la imagen excepto el lugar donde está la matrícula. El código para hacer lo mismo se muestra a continuación:

# Masking the part other than the number plate
mask = np.zeros(gray.shape,np.uint8)
new_image = cv2.drawContours(mask,[screenCnt],0,255,-1,)
new_image = cv2.bitwise_and(img,img,mask=mask)

La nueva imagen enmascarada aparecerá de la siguiente manera:

imagen enmascarada con la matricula del auto

2. Segmentación de caracteres y números

El siguiente paso en el Reconocimiento de matrículas es segmentar la matrícula fuera de la imagen recortándola y guardándola como una nueva imagen. Entonces podemos usar esta imagen para detectar los caracteres que hay en ella. El código para recortar la imagen roi (Region of interest) de la imagen principal se muestra a continuación:

# Now crop
(x, y) = np.where(mask == 255)
(topx, topy) = (np.min(x), np.min(y))
(bottomx, bottomy) = (np.max(x), np.max(y))
Cropped = gray[topx:bottomx+1, topy:bottomy+1]

La imagen resultante se muestra a continuación. Normalmente añadida al recorte de la imagen, también podemos hacerla gris y bordearla si es necesario. Esto se hace para mejorar el reconocimiento de caracteres en el siguiente paso. Sin embargo, me di cuenta de que funciona bien incluso con la imagen original.

matricula recortada

3. Reconocimiento de caracteres

El paso final en este Reconocimiento de matrículas es leer la información de la matrícula de la imagen segmentada. Usaremos el paquete pytesseract para leer los caracteres de la imagen. El código de la misma se indica a continuación:

#Read the number plate
text = pytesseract.image_to_string(Cropped, config='--psm 11')
print("Detected Number is:",text)

Ya hemos explicado cómo configurar un motor de Tesseract, así que aquí de nuevo si es necesario podemos configurar el OCR de Tesseract para obtener mejores resultados si es necesario. El carácter detectado se imprime en la consola. Una vez compilado, el resultado se muestra a continuación:

resultado del reconocimiento de la matricula del autoComo puede ver la imagen original el auto tiene el número «HR 25 BR9044» y nuestro programa ha detectado e impreso el mismo valor en pantalla.

Casos de fallo en el reconocimiento de matrículas

El archivo completo del proyecto de este Reconocimiento de Placas con Raspberry Pi puede ser descargado desde aquí, contiene el programa y las imágenes de prueba que usamos para comprobar nuestro ejemplo. Sin embargo, hay que recordar que los resultados de este método no serán exactos. La precisión depende de la claridad de la imagen, la orientación, la exposición a la luz, etc. Para obtener mejores resultados, puede intentar implementar algoritmos de aprendizaje automático junto con esto.

Para tener una idea, veamos otro ejemplo en el que el coche no está mirando directamente a la cámara:

deteccion de matriculasComo puede ver, nuestro programa fue capaz de detectar la matrícula correctamente y recortarla. Pero la biblioteca Tesseract no ha reconocido correctamente a los caracteres. En lugar del actual «TS 08 UE 3396», el OCR lo ha reconocido como «1508 ye 3396». Problemas como este pueden ser corregidos usando mejores imágenes de orientación o configurando el motor de Tesseract.

En el peor de los casos, el contorno no detecta correctamente la matrícula. La imagen de abajo tiene demasiada información de fondo y mala iluminación que el programa ni siquiera ha podido identificar la matrícula del número. En este caso tenemos que volver a confiar en el aprendizaje automático o mejorar la calidad de la imagen.

errores en el reconocimiento de matriculasOtros ejemplos de éxito

La mayoría de las veces la calidad de la imagen y la orientación es correcta, el programa fue capaz de identificar la matrícula y leer el número de la misma. Las siguientes instantáneas muestran algunos de los resultados obtenidos. Una vez más, todas las imágenes de prueba y el código utilizado aquí estarán disponibles en el archivo ZIP que se proporciona aquí.

Código completo para el Reconocimiento de matrículas con Raspberry Pi y OpenCV

import cv2
import imutils
import numpy as np
import pytesseract
from PIL import Image

img = cv2.imread('4.jpg',cv2.IMREAD_COLOR)

img = cv2.resize(img, (620,480) )

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #convert to grey scale
gray = cv2.bilateralFilter(gray, 11, 17, 17) #Blur to reduce noise
edged = cv2.Canny(gray, 30, 200) #Perform Edge detection

# find contours in the edged image, keep only the largest
# ones, and initialize our screen contour
cnts = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:10]
screenCnt = None

# loop over our contours
for c in cnts:
 # approximate the contour
 peri = cv2.arcLength(c, True)
 approx = cv2.approxPolyDP(c, 0.018 * peri, True)
 
 # if our approximated contour has four points, then
 # we can assume that we have found our screen
 if len(approx) == 4:
  screenCnt = approx
  break

 

if screenCnt is None:
 detected = 0
 print "No contour detected"
else:
 detected = 1

if detected == 1:
 cv2.drawContours(img, [screenCnt], -1, (0, 255, 0), 3)

# Masking the part other than the number plate
mask = np.zeros(gray.shape,np.uint8)
new_image = cv2.drawContours(mask,[screenCnt],0,255,-1,)
new_image = cv2.bitwise_and(img,img,mask=mask)

# Now crop
(x, y) = np.where(mask == 255)
(topx, topy) = (np.min(x), np.min(y))
(bottomx, bottomy) = (np.max(x), np.max(y))
Cropped = gray[topx:bottomx+1, topy:bottomy+1]

 

#Read the number plate
text = pytesseract.image_to_string(Cropped, config='--psm 11')
print("Detected Number is:",text)

cv2.imshow('image',img)
cv2.imshow('Cropped',Cropped)

cv2.waitKey(0)
cv2.destroyAllWindows()

Fuente: https://circuitdigest.com/microcontroller-projects/license-plate-recognition-using-raspberry-pi-and-opencv

Comentarios