Détection des zones lisibles par machine dans les images de passeport
Le billet de blog d’aujourd’hui ne serait pas possible sans Hans Boone, membre de PyImageSearch Gurus. Hans travaille sur un projet de vision par ordinateur pour détecter automatiquement les zones lisibles par machine (ZMR) dans les images de passeport – un peu comme la région détectée dans l’image ci—dessus.
La région MRZ dans les passeports ou les cartes de voyage se divise en deux classes: Type 1 et Type 3. Les ZMR de type 1 sont composées de trois lignes, chaque ligne contenant 30 caractères. La zone MRZ de type 3 ne comporte que deux lignes, mais chaque ligne contient 44 caractères. Dans les deux cas, le MRZ code les informations d’identification d’un citoyen donné, y compris le type de passeport, la pièce d’identité du passeport, le pays émetteur, le nom, la nationalité, la date d’expiration, etc.
Dans le cours de Gourous PyImageSearch, Hans m’a montré ses progrès sur le projet et je me suis immédiatement intéressé. J’ai toujours voulu appliquer des algorithmes de vision par ordinateur aux images de passeport (principalement pour le plaisir), mais je n’avais pas l’ensemble de données pour le faire. Compte tenu des informations d’identification personnelle qu’un passeport contient, je ne pouvais évidemment pas écrire un article de blog sur le sujet et partager les images que j’ai utilisées pour développer l’algorithme.
Heureusement, Hans a accepté de partager certaines des images de passeport d’échantillon / spécimen auxquelles il a accès — et j’ai sauté sur l’occasion de jouer avec ces images.
Maintenant, avant d’aller loin, il est important de noter que ces passeports ne sont pas « réels » dans le sens où ils peuvent être liés à un être humain réel. Mais ce sont de véritables passeports qui ont été générés à l’aide de faux noms, adresses, etc. pour les développeurs de travailler avec.
Vous pourriez penser que pour détecter la région MRZ d’un passeport, vous avez besoin d’un peu d’apprentissage automatique, peut—être en utilisant le framework SVM + HOG linéaire pour construire un « détecteur MRZ » – mais ce serait exagéré.
Au lieu de cela, nous pouvons effectuer une détection MRZ en utilisant uniquement des techniques de traitement d’image de base telles que le seuillage, les opérations morphologiques et les propriétés de contour. Dans le reste de cet article de blog, je détaillerai mon propre point de vue sur la façon d’appliquer ces méthodes pour détecter la région MRZ d’un passeport.
Vous cherchez le code source de ce message?
Accédez Directement À La Section Téléchargements
Détection des zones lisibles par machine dans les images de passeport
Allons de l’avant et commençons ce projet. Ouvrez un nouveau fichier, nommez-le detect_mrz.py
et insérez le code suivant:
# 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))
Les lignes 2 à 6 importent nos paquets nécessaires. Je suppose que vous avez déjà installé OpenCV. Vous aurez également besoin d’imutils, ma collection de fonctions pratiques pour faciliter les opérations de traitement d’image de base avec OpenCV. Vous pouvez installer imutils
en utilisant pip
:
$ pip install --upgrade imutils
À partir de là, les lignes 9 à 11 gèrent l’analyse de notre argument de ligne de commande. Nous n’avons besoin que d’un seul commutateur ici, --images
, qui est le chemin d’accès au répertoire contenant les images de passeport que nous allons traiter.
Enfin, les lignes 14 et 15 initialisent deux noyaux que nous utiliserons plus tard lors de l’application d’opérations morphologiques, en particulier l’opération de fermeture. Pour le moment, il suffit de noter que le premier noyau est rectangulaire avec une largeur environ 3x supérieure à la hauteur. Le deuxième noyau est carré. Ces noyaux nous permettront de combler les espaces entre les caractères MRZ et les ouvertures entre les lignes MRZ.
Maintenant que nos arguments de ligne de commande sont analysés, nous pouvons commencer à parcourir en boucle chacune des images de notre jeu de données et les traiter:
# 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)
Les lignes 20 et 21 chargent notre image d’origine à partir du disque et la redimensionnent pour avoir une hauteur maximale de 600 pixels. Vous pouvez voir un exemple d’image originale ci-dessous:
Un flou gaussien est appliqué sur la ligne 26 pour réduire le bruit à haute fréquence. Nous appliquons ensuite une opération morphologique blackhat à l’image floue en niveaux de gris de la ligne 27.
Un opérateur blackhat est utilisé pour révéler des régions sombres (c’est-à-dire du texte MRZ) sur des arrière-plans clairs (c’est-à-dire l’arrière-plan du passeport lui-même). Étant donné que le texte du passeport est toujours noir sur un fond clair (du moins en ce qui concerne cet ensemble de données), une opération blackhat est appropriée. Ci-dessous, vous pouvez voir la sortie de l’application de l’opérateur blackhat:
L’étape suivante de la détection MRZ consiste à calculer la représentation de l’amplitude du gradient de l’image blackhat à l’aide de l’opérateur 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")
Ici, nous calculons le gradient de Scharr le long de l’axe des abscisses de l’image blackhat, révélant des régions de l’image non seulement sombres sur un fond clair, mais contenant également des changements verticaux dans le dégradé, tels que la région de texte MRZ. Nous prenons ensuite cette image de dégradé et la redimensionnons dans la plage en utilisant la mise à l’échelle min / max:
Bien qu’il ne soit pas tout à fait évident pourquoi nous appliquons cette étape, je dirai qu’elle est extrêmement utile pour réduire les détections de MRZ faussement positives. Sans cela, nous pouvons marquer accidentellement des régions embellies ou conçues du passeport comme la MRZ. Je vais vous laisser cela comme un exercice pour vérifier que le calcul du gradient de l’image blackhat peut améliorer la précision de détection de MRZ.
L’étape suivante consiste à essayer de détecter les lignes réelles 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)
Tout d’abord, nous appliquons une opération de fermeture à l’aide de notre noyau rectangulaire. Cette opération de fermeture est destinée à combler les espaces entre les caractères MRZ. Nous appliquons ensuite le seuillage en utilisant la méthode d’Otsu pour seuil automatiquement l’image:
Comme nous pouvons le voir sur la figure ci-dessus, chacune des lignes MRZ est présente dans notre carte de seuil.
L’étape suivante consiste à combler les écarts entre les lignes réelles, en nous donnant une grande région rectangulaire qui correspond à la ZMR:
# 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)
Ici, nous effectuons une autre opération de fermeture, cette fois en utilisant notre noyau carré. Ce noyau est utilisé pour combler les espaces entre les lignes individuelles de la MRZ, nous donnant une grande région qui correspond à la MRZ. Une série d’érosions est ensuite effectuée pour briser les composants connectés qui ont pu être joints lors de l’opération de fermeture. Ces érosions sont également utiles pour éliminer les petites taches qui ne sont pas pertinentes pour la ZMR.
Pour certaines analyses de passeport, la bordure du passeport peut s’être attachée à la région de la zone MRZ lors des opérations de fermeture. Pour remédier à cela, nous mettons 5% des bordures gauche et droite de l’image à zéro (c’est-à-dire noir):
# 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
Vous pouvez voir la sortie de notre suppression de la frontière ci-dessous.
Par rapport à la figure 5 ci-dessus, vous pouvez maintenant voir que la bordure a été supprimée.
La dernière étape consiste à trouver les contours dans notre image seuillée et à utiliser les propriétés des contours pour identifier la zone 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)
À la ligne 56-58, nous calculons les contours (c’est-à-dire les contours) de notre image seuillée. Nous prenons ensuite ces contours et les trions en fonction de leur taille par ordre décroissant à la ligne 59 (ce qui implique que les contours les plus grands sont les premiers de la liste).
À la ligne 62, nous commençons à parcourir notre liste triée de contours. Pour chacun de ces contours, nous allons calculer la boîte englobante (ligne 66) et l’utiliser pour calculer deux propriétés: le rapport d’aspect et le rapport de couverture. Le rapport d’aspect est simplement la largeur de la boîte englobante divisée par la hauteur. Le rapport de couverture est la largeur de la boîte englobante divisée par la largeur de l’image réelle.
En utilisant ces deux propriétés, nous pouvons vérifier à la ligne 72 si nous examinons la région MRZ. Le MRZ est rectangulaire, avec une largeur beaucoup plus grande que la hauteur. La MRZ doit également couvrir au moins 75% de l’image d’entrée.
Si ces deux cas sont maintenus, les lignes 75 à 84 utilisent les coordonnées (x, y) de la boîte englobante pour extraire la ZMR et dessiner la boîte englobante sur notre image d’entrée.
Enfin, les lignes 87-89 affichent nos résultats.
Résultats
Pour voir notre détecteur MRZ en action, il suffit d’exécuter la commande suivante:
$ python detect_mrz.py --images examples
Ci-dessous, vous pouvez voir un exemple de détection réussie de MRZ, avec la MRZ indiquée en vert:
Voici un autre exemple de détection de la zone lisible par machine dans une image de passeport en utilisant Python et OpenCV:
Peu importe si la région MRZ est en haut ou en bas de l’image. En appliquant des opérations morphologiques, en extrayant des contours et en calculant les propriétés des contours, nous sommes en mesure d’extraire la MRZ sans problème.
Il en va de même pour l’image suivante:
Essayons une autre image:
Jusqu’à présent, nous n’avons vu que des ZMR de type 1 contenant trois lignes. Cependant, notre méthode fonctionne tout aussi bien avec les MRZ de type 3 qui ne contiennent que deux lignes:
Voici un autre exemple de détection d’une MRZ de type 3:
Quelle est la prochaine étape ? Je recommande l’Université PyImageSearch.
30+ total des cours * vidéo 39h 44m • Dernière mise à jour: 12/2021
★★★★★ 4.84 (128 Évaluations) * Plus de 3 000 étudiants inscrits
Je crois fermement que si vous aviez le bon professeur, vous pourriez maîtriser la vision par ordinateur et l’apprentissage en profondeur.
Pensez-vous que l’apprentissage de la vision par ordinateur et de l’apprentissage en profondeur doit être long, accablant et compliqué? Ou doit impliquer des mathématiques et des équations complexes? Ou nécessite un diplôme en informatique?
Ce n’est pas le cas.
Tout ce dont vous avez besoin pour maîtriser la vision par ordinateur et l’apprentissage en profondeur, c’est que quelqu’un vous explique les choses en termes simples et intuitifs. Et c’est exactement ce que je fais. Ma mission est de changer l’éducation et la façon dont les sujets complexes de l’intelligence artificielle sont enseignés.
Si vous êtes sérieux dans l’apprentissage de la vision par ordinateur, votre prochain arrêt devrait être PyImageSearch University, le cours de vision par ordinateur, d’apprentissage profond et OpenCV le plus complet en ligne aujourd’hui. Ici, vous apprendrez à appliquer avec succès et confiance la vision par ordinateur à votre travail, à vos recherches et à vos projets. Rejoignez-moi dans la maîtrise de la vision par ordinateur.
À l’intérieur de l’Université PyImageSearch, vous trouverez:
- & vérifier; Plus de 30 cours sur des sujets essentiels de vision par ordinateur, d’apprentissage en profondeur et d’OpenCV
- & check; Plus de 30 certificats d’achèvement
- & check; vidéo à la demande 39h 44m
- & check; De nouveaux cours sortent chaque mois, vous permettant de suivre les techniques de pointe
- & check; Blocs-notes Jupyter préconfigurés dans Google Colab
- ✓ Exécutez tous les exemples de code dans votre navigateur Web – fonctionne sous Windows, macOS et Linux (aucune configuration d’environnement de développement requise!)
- & vérifier; Accès aux dépôts de code centralisés pour tous les 500 tutoriels sur PyImageSearch
- & check; Téléchargements faciles en un clic pour le code, les jeux de données, les modèles pré-formés, etc.
- & contrôle; Accès sur mobile, ordinateur portable, ordinateur de bureau, etc.
Cliquez ici pour rejoindre l’Université PyImageSearch
Résumé
Dans cet article de blog, nous avons appris à détecter les zones lisibles par machine (ZMR) dans les numérisations de passeports en utilisant uniquement des techniques de traitement d’image de base, à savoir:
- Seuillage.
- Dégradés.
- Opérations morphologiques (plus précisément, fermetures et érosions).
- Propriétés du contour.
Ces opérations, bien que simples, nous ont permis de détecter les régions MRZ dans les images sans avoir à recourir à des méthodes d’extraction de fonctionnalités et d’apprentissage automatique plus avancées telles que SVM + HOG linéaire pour la détection d’objets.
Rappelez-vous, lorsque vous êtes confronté à un problème de vision par ordinateur difficile, tenez toujours compte du problème et de vos hypothèses! Comme le montre cet article de blog, vous pourriez être surpris de ce que les fonctions de traitement d’image de base utilisées en tandem peuvent accomplir.
Encore une fois, un grand merci à Hans Boone, membre de PyImageSearch Gurus, qui nous a fourni ces exemples d’images de passeport! Merci Hans!