Detección de zonas legibles por máquina en imágenes de pasaporte
La entrada de blog de hoy no sería posible sin Hans Boone, miembro de PyImageSearch Gurus. Hans está trabajando en un proyecto de visión por computadora para detectar automáticamente Zonas legibles por máquina (MRZ) en imágenes de pasaporte, al igual que la región detectada en la imagen de arriba.
La región MRZ en pasaportes o tarjetas de viaje se divide en dos clases: Tipo 1 y Tipo 3. Las MRZ de tipo 1 son tres líneas, cada una de las cuales contiene 30 caracteres. El MRZ de tipo 3 solo tiene dos líneas, pero cada línea contiene 44 caracteres. En cualquier caso, el MRZ codifica la información de identificación de un ciudadano, incluyendo el tipo de pasaporte, pasaporte, IDENTIFICACIÓN, país de emisión, nombre, nacionalidad, fecha de vencimiento, etc.
Dentro del curso de Gurús de PyImageSearch, Hans me mostró su progreso en el proyecto e inmediatamente me interesé. Siempre he querido aplicar algoritmos de visión artificial a las imágenes de pasaporte (principalmente por diversión), pero carecía del conjunto de datos para hacerlo. Dada la información de identificación personal que contiene un pasaporte, obviamente no pude escribir una publicación de blog sobre el tema y compartir las imágenes que utilicé para desarrollar el algoritmo.
Afortunadamente, Hans accedió a compartir algunas de las imágenes de muestra/pasaporte de muestras a las que tiene acceso, y aproveché la oportunidad de jugar con estas imágenes.
Ahora, antes de llegar lejos, es importante tener en cuenta que estos pasaportes no son «reales» en el sentido de que pueden vincularse a un ser humano real. Pero son pasaportes genuinos que se generaron utilizando nombres, direcciones, etc. falsos. para desarrolladores con los que trabajar.
Podría pensar que para detectar la región MRZ de un pasaporte necesita un poco de aprendizaje automático, tal vez utilizando el marco lineal SVM + HOG para construir un «detector MRZ», pero eso sería exagerado.
En su lugar, podemos realizar la detección de MRZ utilizando solo técnicas básicas de procesamiento de imágenes, como umbrales, operaciones morfológicas y propiedades de contorno. En el resto de esta entrada de blog, detallaré mi propia opinión sobre cómo aplicar estos métodos para detectar la región MRZ de un pasaporte.
Busca el código fuente de este post?
Vaya Directamente A La Sección De Descargas
Detección de zonas legibles por máquina en imágenes de pasaporte
Sigamos adelante y comencemos con este proyecto. Abra un nuevo archivo, asígnele un nombre detect_mrz.py
e inserte el siguiente código:
# import the necessary packagesfrom imutils import pathsimport numpy as npimport argparseimport imutilsimport cv2# construct the argument parse and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-i", "--images", required=True, help="path to images directory")args = vars(ap.parse_args())# initialize a rectangular and square structuring kernelrectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (13, 5))sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (21, 21))
Las líneas 2-6 importan nuestros paquetes necesarios. Asumo que ya tiene instalado OpenCV. También necesitará imutils, mi colección de funciones de conveniencia para facilitar las operaciones básicas de procesamiento de imágenes con OpenCV. Puede instalar imutils
usando pip
:
$ pip install --upgrade imutils
A partir de ahí, las líneas 9-11 manejan el análisis de nuestro argumento de línea de comandos. Aquí solo necesitamos un interruptor, --images
, que es la ruta al directorio que contiene las imágenes de pasaporte que vamos a procesar.
Finalmente, las Líneas 14 y 15 inicializan dos núcleos que utilizaremos más adelante al aplicar operaciones morfológicas, específicamente la operación de cierre. Por el momento, simplemente tenga en cuenta que el primer núcleo es rectangular con un ancho aproximadamente 3 veces mayor que la altura. El segundo núcleo es cuadrado. Estos núcleos nos permitirán cerrar huecos entre caracteres MRZ y aberturas entre líneas MRZ.
Ahora que se analizan los argumentos de la línea de comandos, podemos comenzar a recorrer en bucle cada una de las imágenes de nuestro conjunto de datos y procesarlas:
# loop over the input image pathsfor imagePath in paths.list_images(args):# load the image, resize it, and convert it to grayscaleimage = cv2.imread(imagePath)image = imutils.resize(image, height=600)gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# smooth the image using a 3x3 Gaussian, then apply the blackhat# morphological operator to find dark regions on a light backgroundgray = cv2.GaussianBlur(gray, (3, 3), 0)blackhat = cv2.morphologyEx(gray, cv2.MORPH_BLACKHAT, rectKernel)
Las líneas 20 y 21 cargan nuestra imagen original desde el disco y la redimensionan para que tenga una altura máxima de 600 píxeles. Puede ver un ejemplo de una imagen original a continuación:
El desenfoque gaussiano se aplica en la línea 26 para reducir el ruido de alta frecuencia. Luego aplicamos una operación morfológica de sombrero negro a la imagen borrosa en escala de grises en la Línea 27.
Un operador blackhat se utiliza para revelar regiones oscuras (es decir, texto MRZ) contra fondos claros (es decir, el fondo del pasaporte en sí). Dado que el texto del pasaporte siempre es negro sobre un fondo claro (al menos en términos de este conjunto de datos), una operación blackhat es apropiada. A continuación puede ver la salida de la aplicación del operador blackhat:
El siguiente paso en la detección de MRZ es calcular la representación de magnitud de gradiente de la imagen blackhat utilizando el operador Scharr:
# compute the Scharr gradient of the blackhat image and scale the# result into the range gradX = cv2.Sobel(blackhat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)gradX = np.absolute(gradX)(minVal, maxVal) = (np.min(gradX), np.max(gradX))gradX = (255 * ((gradX - minVal) / (maxVal - minVal))).astype("uint8")
Aquí calculamos el gradiente de Scharr a lo largo del eje x de la imagen blackhat, revelando regiones de la imagen que no solo son oscuras sobre un fondo claro, sino que también contienen cambios verticales en el gradiente, como la región de texto MRZ. Luego tomamos esta imagen de degradado y la escalamos de nuevo en el rango usando escala mínima / máxima:
Aunque no es del todo obvio por qué aplicamos este paso, diré que es extremadamente útil para reducir las detecciones de MRZ falsos positivos. Sin él, podemos marcar accidentalmente regiones embellecidas o diseñadas del pasaporte como la MRZ. Dejaré esto como un ejercicio para que verifiquen que el cálculo del gradiente de la imagen de blackhat puede mejorar la precisión de detección de MRZ.
El siguiente paso es intentar detectar las líneas reales de la MRZ:
# apply a closing operation using the rectangular kernel to close# gaps in between letters -- then apply Otsu's thresholding methodgradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)thresh = cv2.threshold(gradX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
Primero, aplicamos una operación de cierre utilizando nuestro núcleo rectangular. Esta operación de cierre está destinada a cerrar las brechas entre los caracteres MRZ. A continuación, aplicamos umbrales utilizando el método de Otsu para umbral automático de la imagen:
Como podemos ver en la figura de arriba, cada una de las líneas MRZ está presente en nuestro mapa de umbrales.
El siguiente paso es cerrar los espacios entre las líneas reales, dándonos una gran región rectangular que corresponde a la MRZ:
# perform another closing operation, this time using the square# kernel to close gaps between lines of the MRZ, then perform a# series of erosions to break apart connected componentsthresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)thresh = cv2.erode(thresh, None, iterations=4)
Aquí realizamos otra operación de cierre, esta vez usando nuestro núcleo cuadrado. Este núcleo se utiliza para cerrar las brechas entre las líneas individuales de la MRZ, dándonos una gran región que corresponde a la MRZ. A continuación, se realizan una serie de erosiones para separar los componentes conectados que pueden haberse unido durante la operación de cierre. Estas erosiones también son útiles para eliminar pequeñas manchas que son irrelevantes para la MRZ.
Para algunos escaneos de pasaportes, la frontera del pasaporte puede haberse unido a la región MRZ durante las operaciones de cierre. Para remediar esto, establecemos el 5% de los bordes izquierdo y derecho de la imagen en cero (es decir, negro):
# during thresholding, it's possible that border pixels were# included in the thresholding, so let's set 5% of the left and# right borders to zerop = int(image.shape * 0.05)thresh = 0thresh - p:] = 0
Puede ver el resultado de nuestra eliminación de fronteras a continuación.
En comparación con la figura 5 anterior, ahora puede ver que el borde se ha eliminado.
El último paso es encontrar los contornos en nuestra imagen con umbral y usar las propiedades de contorno para identificar el MRZ:
# find contours in the thresholded image and sort them by their# sizecnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)cnts = sorted(cnts, key=cv2.contourArea, reverse=True)# loop over the contoursfor c in cnts:# compute the bounding box of the contour and use the contour to# compute the aspect ratio and coverage ratio of the bounding box# width to the width of the image(x, y, w, h) = cv2.boundingRect(c)ar = w / float(h)crWidth = w / float(gray.shape)# check to see if the aspect ratio and coverage width are within# acceptable criteriaif ar > 5 and crWidth > 0.75:# pad the bounding box since we applied erosions and now need# to re-grow itpX = int((x + w) * 0.03)pY = int((y + h) * 0.03)(x, y) = (x - pX, y - pY)(w, h) = (w + (pX * 2), h + (pY * 2))# extract the ROI from the image and draw a bounding box# surrounding the MRZroi = image.copy()cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)break# show the output imagescv2.imshow("Image", image)cv2.imshow("ROI", roi)cv2.waitKey(0)
En la línea 56-58 calculamos los contornos (es decir, contornos) de nuestra imagen con umbral. Luego tomamos estos contornos y los clasificamos en función de su tamaño en orden descendente en la línea 59 (lo que implica que los contornos más grandes están primero en la lista).
En la línea 62 comenzamos a recorrer nuestra lista ordenada de contornos. Para cada uno de estos contornos, calcularemos el cuadro delimitador (Línea 66) y lo usaremos para calcular dos propiedades: la relación de aspecto y la relación de cobertura. La relación de aspecto es simplemente el ancho del cuadro delimitador dividido por la altura. La relación de cobertura es el ancho del cuadro delimitador dividido por el ancho de la imagen real.
Usando estas dos propiedades podemos hacer una comprobación en la línea 72 para ver si estamos examinando la región MRZ. La MRZ es rectangular, con un ancho mucho mayor que la altura. La MRZ también debe abarcar al menos el 75% de la imagen de entrada.
Siempre que estos dos casos se mantengan, las líneas 75-84 usan las coordenadas (x, y) del cuadro delimitador para extraer el MRZ y dibujar el cuadro delimitador en nuestra imagen de entrada.
Finalmente, las líneas 87-89 muestran nuestros resultados.
Resultados
Para ver nuestro detector MRZ en acción, simplemente ejecute el siguiente comando:
$ python detect_mrz.py --images examples
A continuación puede ver un ejemplo de detección exitosa de MRZ, con el MRZ delineado en verde:
Aquí hay otro ejemplo de detección de la Zona legible por máquina en una imagen de pasaporte utilizando Python y OpenCV:
No importa si la región MRZ está en la parte superior o inferior de la imagen. Mediante la aplicación de operaciones morfológicas, la extracción de contornos y el cálculo de propiedades de contornos, podemos extraer el MRZ sin problemas.
Lo mismo es cierto para la siguiente imagen:
Probemos otra imagen:
Hasta ahora solo hemos visto MRZ de tipo 1 que contienen tres líneas. Sin embargo, nuestro método funciona igual de bien con MRZ de tipo 3 que contienen solo dos líneas:
Este es otro ejemplo de detección de un MRZ de tipo 3:
¿Qué sigue? Recomiendo PyImageSearch University.
30 + clases totales * 39h 44m video * Última actualización: 12/2021
★★★★★ 4.84 (128 Calificaciones) * Más de 3000 estudiantes inscritos
Creo firmemente que si tuviera el profesor adecuado, podría dominar la visión artificial y el aprendizaje profundo.
¿Cree que el aprendizaje de la visión artificial y el aprendizaje profundo debe llevar mucho tiempo, ser abrumador y complicado? ¿O tiene que involucrar matemáticas y ecuaciones complejas? ¿O requiere un título en informática?
Ese no es el caso.
Todo lo que necesitas para dominar la visión artificial y el aprendizaje profundo es que alguien te explique las cosas en términos simples e intuitivos. Y eso es exactamente lo que hago. Mi misión es cambiar la educación y la forma en que se enseñan temas complejos de Inteligencia Artificial.
Si te tomas en serio el aprendizaje de la visión artificial, tu próxima parada debería ser PyImageSearch University, el curso online de visión artificial, aprendizaje profundo y OpenCV más completo de la actualidad. Aquí aprenderá a aplicar con éxito y confianza la visión artificial a su trabajo, investigación y proyectos. Únete a mí en el dominio de la visión artificial.
Dentro de PyImageSearch University encontrarás:
- &comprobar; más de 30 cursos sobre temas esenciales de visión artificial, aprendizaje profundo y OpenCV
- &comprobar; más de 30 certificados de finalización
- &comprobar; vídeo a la carta de 39h 44m
- &comprobar; Nuevos cursos lanzados cada mes, lo que garantiza que pueda mantenerse al día con técnicas de vanguardia
- &comprobar; Cuadernos Jupyter preconfigurados en Google Colab
- &comprobar; Ejecutar todos los ejemplos de código en su navegador web: funciona en Windows, macOS y Linux (¡no se requiere configuración de entorno de desarrollo!)
- &comprobar; Acceso a repositorios de código centralizados para más de 500 tutoriales en PyImageSearch
- &comprobar; Descargas sencillas con un solo clic para código, conjuntos de datos, modelos preentrenados, etc.
- &comprobación; Acceso en dispositivos móviles, portátiles, de escritorio, etc.
Haga clic aquí para unirse a PyImageSearch University
Resumen
En esta entrada de blog aprendimos a detectar Zonas legibles por máquina (MRZ) en escaneos de pasaportes utilizando solo técnicas básicas de procesamiento de imágenes, a saber:
- Umbral.Gradientes
- .
- Operaciones morfológicas (específicamente, cierres y erosiones).
- Propiedades de contorno.
Estas operaciones, aunque simples, nos permitieron detectar las regiones MRZ en imágenes sin tener que depender de métodos de extracción de funciones y aprendizaje automático más avanzados, como SVM + HOG lineal para la detección de objetos.
Recuerde, cuando se enfrente a un problema de visión por computadora desafiante, ¡siempre considere el problema y sus suposiciones! Como demuestra esta publicación de blog, puede sorprenderte lo que pueden lograr las funciones básicas de procesamiento de imágenes que se usan en tándem.
Una vez más, muchas gracias a Hans Boone, miembro de PyImageSearch Gurus, que nos proporcionó estas imágenes de pasaporte de ejemplo. Gracias Hans!