Maschinenlesbare Zonen in Passbildern erkennen

mrz_output_04

Der heutige Blogbeitrag wäre ohne PyImageSearch Gurus-Mitglied Hans Boone nicht möglich. Hans arbeitet an einem Computer-Vision-Projekt, um maschinenlesbare Zonen (MRZs) in Passbildern automatisch zu erkennen – ähnlich wie die im obigen Bild erkannte Region.

Die MRZ-Region in Pässen oder Reisekarten fällt in zwei Klassen: Typ 1 und Typ 3. Typ 1 MRZs sind drei Zeilen, wobei jede Zeile 30 Zeichen enthält. Der Typ 3 MRZ hat nur zwei Zeilen, aber jede Zeile enthält 44 Zeichen. In beiden Fällen kodiert die MRZ identifizierende Informationen eines bestimmten Bürgers, einschließlich der Art des Passes, der Pass-ID, des Ausstellungslandes, des Namens, der Nationalität, des Ablaufdatums usw.

Im PyImageSearch Gurus Kurs zeigte Hans mir seine Fortschritte bei dem Projekt und ich wurde sofort interessiert. Ich wollte schon immer Computer-Vision-Algorithmen auf Passbilder anwenden (hauptsächlich nur zum Spaß), aber es fehlte der Datensatz dafür. Angesichts der persönlichen Identifikationsinformationen, die ein Reisepass enthält, konnte ich offensichtlich keinen Blogbeitrag zu diesem Thema schreiben und die Bilder teilen, die ich zur Entwicklung des Algorithmus verwendet habe.

Zum Glück stimmte Hans zu, einige der Muster- / Musterpassbilder zu teilen, auf die er Zugriff hat — und ich ergriff die Gelegenheit, mit diesen Bildern zu spielen.

Nun, bevor wir zu weit kommen, ist es wichtig zu beachten, dass diese Pässe nicht „real“ in dem Sinne sind, dass sie mit einem tatsächlichen Menschen verbunden werden können. Es handelt sich jedoch um echte Pässe, die mit gefälschten Namen, Adressen usw. erstellt wurden. für Entwickler zu arbeiten.

Sie könnten denken, dass Sie, um die MRZ—Region eines Passes zu erkennen, ein wenig maschinelles Lernen benötigen, vielleicht das lineare SVM + HOG-Framework verwenden, um einen „MRZ-Detektor“ zu konstruieren – aber das wäre übertrieben.

Stattdessen können wir die MRZ-Erkennung nur mit grundlegenden Bildverarbeitungstechniken wie Schwellenwerten, morphologischen Operationen und Kontureigenschaften durchführen. Im Rest dieses Blogbeitrags werde ich meine eigene Vorgehensweise zur Anwendung dieser Methoden zur Erkennung der MRZ-Region eines Passes erläutern.

Suchen Sie den Quellcode zu diesem Beitrag?

Direkt zum Download-Bereich

Erkennung maschinenlesbarer Zonen in Passbildern

Lassen Sie uns dieses Projekt starten. Öffnen Sie eine neue Datei, nennen Sie sie detect_mrz.py und fügen Sie den folgenden Code ein:

# 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))

Zeilen 2-6 importieren unsere notwendigen Pakete. Ich gehe davon aus, dass Sie OpenCV bereits installiert haben. Sie benötigen auch imutils, meine Sammlung von Komfortfunktionen, um grundlegende Bildverarbeitungsvorgänge mit OpenCV zu vereinfachen. Sie können imutils mit pip installieren :

$ pip install --upgrade imutils

Von dort aus behandeln die Zeilen 9-11 das Parsen unseres Befehlszeilenarguments. Wir brauchen hier nur einen einzigen Schalter, --images , der der Pfad zu dem Verzeichnis ist, das die Passbilder enthält, die wir verarbeiten werden.

Schließlich initialisieren die Zeilen 14 und 15 zwei Kernel, die wir später verwenden werden, wenn wir morphologische Operationen anwenden, insbesondere die Schließoperation. Beachten Sie vorerst einfach, dass der erste Kernel rechteckig ist und eine Breite hat, die ungefähr 3x größer ist als die Höhe. Der zweite Kern ist quadratisch. Diese Kernel ermöglichen es uns, Lücken zwischen MRZ-Zeichen und Öffnungen zwischen MRZ-Zeilen zu schließen.

Nachdem unsere Befehlszeilenargumente analysiert wurden, können wir jedes der Bilder in unserem Datensatz durchlaufen und verarbeiten:

# 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)

Die Zeilen 20 und 21 laden unser Originalbild von der Festplatte und ändern die Größe auf eine maximale Höhe von 600 Pixel. Unten sehen Sie ein Beispiel für ein Originalbild:

 Abbildung 1: Unser ursprüngliches Passbild, in dem wir versuchen, die MRZ zu erkennen.
Abbildung 1: Unser ursprüngliches Passbild, in dem wir versuchen, die MRZ zu erkennen.

Gaußsche Unschärfe wird auf Zeile 26 angewendet, um hochfrequentes Rauschen zu reduzieren. Wir wenden dann eine morphologische Blackhat-Operation auf das unscharfe Graustufenbild in Zeile 27 an.

Ein Blackhat-Operator wird verwendet, um dunkle Bereiche (d. H. MRZ-Text) vor hellem Hintergrund (d. h. Dem Hintergrund des Passes selbst) anzuzeigen. Da der Passtext auf hellem Hintergrund (zumindest in Bezug auf diesen Datensatz) immer schwarz ist, ist eine Blackhat-Operation angebracht. Unten sehen Sie die Ausgabe der Anwendung des Blackhat-Operators:

 Abbildung 2: Wenn Sie den morphologischen Operator Blackhat anwenden, wird der schwarze MRZ-Text vor dem hellgrauen Hintergrund angezeigt.
Abbildung 2: Durch Anwenden des morphologischen Operators Blackhat wird der schwarze MRZ-Text vor dem hellgrauen Hintergrund angezeigt.

Der nächste Schritt bei der MRZ-Erkennung besteht darin, die Gradientengrößendarstellung des Blackhat-Bildes mit dem Scharr-Operator zu berechnen:

# 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")

Hier berechnen wir den Scharr-Gradienten entlang der x-Achse des Blackhat-Bildes und enthüllen Bereiche des Bildes, die nicht nur dunkel vor einem hellen Hintergrund sind, sondern auch vertikale Änderungen im Gradienten enthalten, wie z. B. die MRZ-Textregion. Wir nehmen dann dieses Verlaufsbild und skalieren es mithilfe der Min / Max-Skalierung wieder in den Bereich:

 Abbildung 3: Die Anwendung des Scharr-Operators auf unser Blackhat-Bild zeigt Regionen mit starken vertikalen Gradientenänderungen.
Abbildung 3: Die Anwendung des Scharr-Operators auf unser Blackhat-Bild zeigt Regionen mit starken vertikalen Gradientenänderungen.

Obwohl es nicht ganz offensichtlich ist, warum wir diesen Schritt anwenden, werde ich sagen, dass er äußerst hilfreich ist, um falsch positive MRZ-Erkennungen zu reduzieren. Ohne sie können wir versehentlich verschönerte oder gestaltete Bereiche des Passes als MRZ markieren. Ich überlasse Ihnen dies als Übung, um zu überprüfen, ob die Berechnung des Gradienten des Blackhat-Bildes die MRZ-Erkennungsgenauigkeit verbessern kann.

Der nächste Schritt besteht darin, die tatsächlichen Linien der MRZ zu erkennen:

# 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)

Zuerst wenden wir eine Schließoperation mit unserem rechteckigen Kernel an. Dieser Schließvorgang soll Lücken zwischen MRZ-Zeichen schließen. Wir wenden dann Schwellenwerte mit der Otsu-Methode an, um das Bild automatisch zu schwellen:

 Abbildung 4: Anwenden einer Schließoperation mit einem rechteckigen Kernel (der breiter als hoch ist), um Lücken zwischen den MRZ-Zeichen zu schließen
Abbildung 4: Anwenden einer Schließoperation unter Verwendung eines rechteckigen Kernels (der breiter als hoch ist), um Lücken zwischen den MRZ-Zeichen zu schließen

Wie wir aus der obigen Abbildung sehen können, ist jede der MRZ-Linien in unserer Schwellenwertkarte vorhanden.

Der nächste Schritt besteht darin, die Lücken zwischen den tatsächlichen Linien zu schließen und uns einen großen rechteckigen Bereich zu geben, der der MRZ entspricht:

# 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)

Hier führen wir eine weitere Schließoperation durch, diesmal mit unserem quadratischen Kernel. Dieser Kernel wird verwendet, um Lücken zwischen den einzelnen Linien der MRZ zu schließen, wodurch wir eine große Region erhalten, die der MRZ entspricht. Eine Reihe von Erosionen wird dann durchgeführt, um verbundene Komponenten, die während des Schließvorgangs verbunden worden sein können, auseinander zu brechen. Diese Erosionen sind auch hilfreich beim Entfernen kleiner Blobs, die für die MRZ irrelevant sind.

Abbildung 5: Ein zweiter Schließvorgang wird durchgeführt, diesmal mit einem quadratischen Kern, um die Lücken zwischen den einzelnen MRZ-Linien zu schließen.
Abbildung 5: Ein zweiter Schließvorgang wird durchgeführt, diesmal unter Verwendung eines quadratischen Kerns, um die Lücken zwischen einzelnen MRZ-Linien zu schließen.

Bei einigen Pass-Scans ist der Rand des Passes während der Schließvorgänge möglicherweise mit der MRZ-Region verbunden. Um dies zu beheben, setzen wir 5% des linken und rechten Bildrandes auf Null (d. H. Schwarz):

# 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

Sie können die Ausgabe unserer Border Removal unten sehen.

Abbildung 6: Setzen Sie 5% des linken und rechten Randpixels auf Null, um sicherzustellen, dass der MRZ-Bereich nicht an den gescannten Rand des Passes angehängt wird.
Abbildung 6: Setzen Sie 5% des linken und rechten Randpixels auf Null, um sicherzustellen, dass der MRZ-Bereich nicht an den gescannten Rand des Passes angehängt wird.

Im Vergleich zu Abbildung 5 oben sehen Sie nun, dass der Rand entfernt wurde.

Der letzte Schritt besteht darin, die Konturen in unserem Schwellwertbild zu finden und die Kontureigenschaften zu verwenden, um die MRZ zu identifizieren:

# 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)

In Zeile 56-58 berechnen wir die Konturen (d. H. Umrisse) unseres Schwellenbildes. Wir nehmen dann diese Konturen und sortieren sie anhand ihrer Größe in absteigender Reihenfolge in Zeile 59 (was bedeutet, dass die größten Konturen an erster Stelle in der Liste stehen).

In Zeile 62 beginnen wir mit der Schleife über unsere sortierte Liste von Konturen. Für jede dieser Konturen berechnen wir den Begrenzungsrahmen (Zeile 66) und verwenden ihn, um zwei Eigenschaften zu berechnen: das Seitenverhältnis und das Abdeckungsverhältnis. Das Seitenverhältnis ist einfach die Breite des Begrenzungsrahmens geteilt durch die Höhe. Das Abdeckungsverhältnis ist die Breite des Begrenzungsrahmens geteilt durch die Breite des tatsächlichen Bildes.

Mit diesen beiden Eigenschaften können wir in Zeile 72 überprüfen, ob wir die MRZ-Region untersuchen. Die MRZ ist rechteckig, mit einer Breite, die viel größer als die Höhe ist. Die MRZ sollte auch mindestens 75% des Eingabebildes umfassen.

Sofern diese beiden Fälle zutreffen, verwenden die Zeilen 75-84 die (x, y) -Koordinaten des Begrenzungsrahmens, um die MRZ zu extrahieren und den Begrenzungsrahmen auf unser Eingabebild zu zeichnen.

Schließlich zeigen die Zeilen 87-89 unsere Ergebnisse an.

Ergebnisse

Um unseren MRZ-Detektor in Aktion zu sehen, führen Sie einfach den folgenden Befehl aus:

$ python detect_mrz.py --images examples

Unten sehen Sie ein Beispiel für eine erfolgreiche MRZ-Erkennung, wobei die MRZ grün umrandet ist:

 Abbildung 7: Links haben wir unser Eingabebild. Und rechts haben wir die MRZ-Region, die erfolgreich erkannt wurde.
Abbildung 7: Links haben wir unser Eingabebild. Und rechts haben wir die MRZ-Region, die erfolgreich erkannt wurde.

Hier ist ein weiteres Beispiel für die Erkennung der maschinenlesbaren Zone in einem Passbild mit Python und OpenCV:

 Abbildung 8: Anwenden der MRZ-Erkennung auf einen gescannten Reisepass.
Abbildung 8: Anwenden der MRZ-Erkennung auf einen gescannten Reisepass.

Es spielt keine Rolle, ob sich der MRZ-Bereich oben oder unten im Bild befindet. Durch Anwendung morphologischer Operationen, Extrahieren von Konturen und Berechnen von Kontureigenschaften können wir die MRZ problemlos extrahieren.

Das gleiche gilt für das folgende Bild:

 Abbildung 9: Erkennung maschinenlesbarer Zonen in Bildern mithilfe von Computer Vision.
Abbildung 9: Erkennung maschinenlesbarer Zonen in Bildern mithilfe von Computer Vision.

Probieren wir ein anderes Bild aus:

Abbildung 10: Auch hier können wir die MRZ im Passscan mit grundlegenden Bildverarbeitungstechniken erkennen.
Abbildung 10: Auch hier können wir die MRZ im Passscan mit grundlegenden Bildverarbeitungstechniken erkennen.

Bisher haben wir nur MRZs vom Typ 1 gesehen, die drei Zeilen enthalten. Unsere Methode funktioniert jedoch genauso gut mit MRZs vom Typ 3, die nur zwei Zeilen enthalten:

 Abbildung 11: Erkennen der MRZ in einem Typ-3-Passbild mit Python und OpenCV.
Abbildung 11: Erkennen der MRZ in einem Typ-3-Passbild mit Python und OpenCV.

Hier ist ein weiteres Beispiel für die Erkennung einer MRZ vom Typ 3:

 Abbildung 12: Anwenden von Computer Vision und Bildverarbeitung zur Erkennung maschinenlesbarer Zonen in Bildern.
Abbildung 12: Anwenden von Computer Vision und Bildverarbeitung zur Erkennung maschinenlesbarer Zonen in Bildern.

Was kommt als nächstes? Ich empfehle PyImageSearch University.

Kursinformationen:
30+ Gesamtklassen • 39h 44m Video • Zuletzt aktualisiert: 12/2021
★★★★★ 4.84 (128 Bewertungen) * Über 3.000 eingeschriebene Schüler

Ich glaube fest daran, dass Sie Computer Vision und Deep Learning beherrschen könnten, wenn Sie den richtigen Lehrer hätten.

Denken Sie, dass das Erlernen von Computer Vision und Deep Learning zeitaufwändig, überwältigend und kompliziert sein muss? Oder muss komplexe Mathematik und Gleichungen beinhalten? Oder erfordert einen Abschluss in Informatik?

Das ist nicht der Fall.

Alles, was Sie brauchen, um Computer Vision und Deep Learning zu beherrschen, ist, dass Ihnen jemand die Dinge in einfachen, intuitiven Begriffen erklärt. Und genau das mache ich. Meine Mission ist es, die Bildung und die Art und Weise, wie komplexe Themen der künstlichen Intelligenz unterrichtet werden, zu verändern.

Wenn Sie es ernst meinen mit dem Erlernen von Computer Vision, sollte Ihre nächste Station die PyImageSearch University sein, der umfassendste Online-Kurs für Computer Vision, Deep Learning und OpenCV. Hier erfahren Sie, wie Sie Computer Vision erfolgreich und sicher auf Ihre Arbeit, Forschung und Projekte anwenden können. Begleiten Sie mich in Computer Vision Mastery.

Innerhalb PyImageSearch Universität finden Sie:

  • & prüfen; 30+ Kurse zu wichtigen Themen wie Computer Vision, Deep Learning und OpenCV
  • &Check; 30+ Abschlusszertifikate
  • &Check; 39h 44m On-Demand-Video
  • &Check; Jeden Monat werden brandneue Kurse veröffentlicht, die sicherstellen, dass Sie mit den neuesten Techniken Schritt halten können
  • & überprüfen; Vorkonfigurierte Jupyter-Notebooks in Google Colab
  • & überprüfen; Führen Sie alle Codebeispiele in Ihrem Webbrowser aus – funktioniert unter Windows, macOS und Linux (keine Konfiguration der Entwicklungsumgebung erforderlich!)
  • & prüfen; Zugriff auf zentralisierte Code-Repos für alle über 500 Tutorials auf PyImageSearch
  • ✓ Einfache Ein-Klick-Downloads für Code, Datensätze, vortrainierte Modelle usw.
  • &überprüfen; Zugriff auf Handy, Laptop, Desktop usw.

Klicken Sie hier, um der PyImageSearch University beizutreten

Zusammenfassung

In diesem Blogbeitrag haben wir gelernt, wie maschinenlesbare Zonen (MRZs) in Passscans nur mit grundlegenden Bildverarbeitungstechniken erkannt werden, nämlich:

  • Schwellenwert.
  • Verläufe.
  • Morphologische Operationen (insbesondere Verschlüsse und Erosionen).
  • Kontureigenschaften.

Diese einfachen Operationen ermöglichten es uns, die MRZ-Regionen in Bildern zu erkennen, ohne uns auf fortschrittlichere Merkmalsextraktions- und maschinelle Lernmethoden wie Linear SVM + HOG für die Objekterkennung verlassen zu müssen.

Denken Sie daran, wenn Sie mit einem herausfordernden Computer—Vision-Problem konfrontiert werden – denken Sie immer an das Problem und Ihre Annahmen! Wie dieser Blogbeitrag zeigt, werden Sie überrascht sein, welche grundlegenden Bildverarbeitungsfunktionen im Tandem verwendet werden können.

Noch einmal ein großes Dankeschön an PyImageSearch Gurus Mitglied Hans Boone, der uns diese Beispiel-Passbilder zur Verfügung gestellt hat! Danke Hans!

Leave a Reply

Deine E-Mail-Adresse wird nicht veröffentlicht.