wykrywanie stref do odczytu maszynowego na zdjęciach paszportowych

mrz_output_04

dzisiejszy wpis na blogu nie byłby możliwy bez członka PyImageSearch Guru, Hansa Boone ’ a. Hans pracuje nad projektem komputerowej wizji, aby automatycznie wykrywać strefy odczytywalne maszynowo (MRZS) na zdjęciach paszportowych — podobnie jak region wykryty na powyższym zdjęciu.

region MRZ w paszportach lub kartach podróży dzieli się na dwie klasy: typ 1 i typ 3. MRZ typu 1 to trzy linie, z których każda zawiera 30 znaków. MRZ typu 3 ma tylko dwie linie, ale każda linia zawiera 44 znaki. W obu przypadkach MRZ koduje dane identyfikacyjne danego obywatela, w tym rodzaj paszportu, dowód osobisty, kraj wydający, imię i nazwisko, obywatelstwo, datę ważności itp.

w trakcie kursu Guru PyImageSearch Hans pokazał mi swoje postępy w projekcie i natychmiast zainteresowałem się nim. Zawsze chciałem zastosować algorytmy widzenia komputerowego do zdjęć paszportowych (głównie dla zabawy), ale brakowało mi zestawu danych, aby to zrobić. Biorąc pod uwagę dane osobowe, które zawiera paszport, oczywiście nie mogłem napisać posta na blogu na ten temat i udostępnić zdjęć, których użyłem do opracowania algorytmu.

na szczęście Hans zgodził się udostępnić kilka przykładowych zdjęć paszportowych, do których ma dostęp — a ja skorzystałem z okazji, aby pobawić się tymi zdjęciami.

teraz, zanim przejdziemy daleko, ważne jest, aby pamiętać, że te paszporty nie są „prawdziwe” w tym sensie, że można je powiązać z rzeczywistą istotą ludzką. Ale są to prawdziwe paszporty, które zostały wygenerowane przy użyciu fałszywych nazwisk, adresów itp. dla programistów do współpracy.

możesz pomyśleć, że aby wykryć region MRZ w paszporcie, potrzebujesz trochę uczenia maszynowego, być może używając liniowego frameworka SVM + HOG do skonstruowania „detektora MRZ” — ale to byłoby przesadą.

zamiast tego możemy wykonywać detekcję MRZ przy użyciu tylko podstawowych technik przetwarzania obrazu, takich jak progowanie, operacje morfologiczne i właściwości konturu. W dalszej części tego postu na blogu opiszę moje własne podejście do stosowania tych metod w celu wykrycia regionu MRZ paszportu.

szukasz kodu źródłowego do tego postu?

przejdź do sekcji Pliki do pobrania

wykrywanie stref odczytywalnych maszynowo na zdjęciach paszportowych

rozpocznijmy ten projekt. Otwórz nowy plik, nazwij go detect_mrz.py i wstaw następujący kod:

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

linie 2-6 importują nasze niezbędne pakiety. Zakładam, że masz już zainstalowany OpenCV. Będziesz także potrzebował imutils, mojej kolekcji wygodnych funkcji, aby ułatwić podstawowe operacje przetwarzania obrazu z OpenCV. Możesz zainstalować imutils używając pip :

$ pip install --upgrade imutils

stamtąd linie 9-11 zajmują się analizowaniem naszego argumentu wiersza poleceń. Potrzebujemy tylko jednego przełącznika, --images, który jest ścieżką do katalogu zawierającego zdjęcia paszportowe, które zamierzamy przetworzyć.

wreszcie, linie 14 i 15 inicjują dwa jądra, których będziemy później używać przy stosowaniu operacji morfologicznych, w szczególności operacji zamykania. Na razie po prostu zauważ, że pierwsze jądro jest prostokątne o szerokości około 3x większej niż wysokość. Drugie jądro jest kwadratowe. Jądra te pozwolą nam na zamknięcie luk między znakami MRZ i otworów między liniami MRZ.

teraz, gdy nasze argumenty wiersza poleceń są przetwarzane, możemy rozpocząć zapętlanie każdego z obrazów w naszym zbiorze danych i przetwarzać je:

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

linie 20 i 21 ładują nasz oryginalny obraz z dysku i zmieniają jego rozmiar na maksymalną wysokość 600 pikseli. Przykład oryginalnego obrazu można zobaczyć poniżej:

Rysunek 1: nasz oryginalny obraz paszportowy, w którym próbujemy wykryć MRZ.
Rysunek 1: nasze oryginalne zdjęcie paszportowe, w którym próbujemy wykryć MRZ.

rozmycie Gaussa jest stosowane na linii 26 w celu zmniejszenia szumu o wysokiej częstotliwości. Następnie stosujemy operację morfologiczną blackhat do rozmytego obrazu w skali szarości na linii 27.

Operator blackhat jest używany do ujawniania ciemnych obszarów (np. tekstu MRZ) na jasnym tle (np. tle samego paszportu). Ponieważ tekst paszportu jest zawsze czarny na jasnym tle (przynajmniej w odniesieniu do tego zestawu danych), operacja blackhat jest właściwa. Poniżej możesz zobaczyć wynik zastosowania operatora blackhat:

Rysunek 2: Zastosowanie operatora morfologicznego blackhat ujawnia czarny tekst MRZ na tle jasnego paszportu.
Rysunek 2: Zastosowanie operatora morfologicznego blackhat ujawnia czarny tekst MRZ na tle jasnego paszportu.

następnym krokiem w wykrywaniu MRZ jest obliczenie reprezentacji gradientu wielkości obrazu blackhata za pomocą operatora Scharra:

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

tutaj obliczamy gradient Scharra wzdłuż osi x obrazu blackhat, odsłaniając obszary obrazu, które są nie tylko ciemne na jasnym tle, ale także zawierają pionowe zmiany gradientu, takie jak obszar tekstowy MRZ. Następnie bierzemy ten gradientowy obraz i przeskalowujemy go z powrotem do zakresu za pomocą skalowania min / max:

Rysunek 3: Zastosowanie operatora Scharra do naszego obrazu blackhat ujawnia obszary, które zawierają silne pionowe zmiany gradientu.
Rysunek 3: Zastosowanie operatora Scharra do naszego obrazu blackhat ujawnia obszary, które zawierają silne pionowe zmiany gradientu.

chociaż nie jest do końca oczywiste, dlaczego stosujemy ten krok, powiem, że jest to niezwykle pomocne w zmniejszaniu fałszywie dodatnich wykrywalności MRZ. Bez niego możemy przypadkowo oznaczyć upiększone lub zaprojektowane regiony paszportu jako MRZ. Zostawię to jako ćwiczenie, aby sprawdzić, czy obliczanie gradientu obrazu blackhat może poprawić dokładność wykrywania MRZ.

następnym krokiem jest próba wykrycia rzeczywistych linii 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)

po pierwsze, stosujemy operację zamykania używając naszego prostokątnego jądra. Ta operacja zamykania ma na celu zamknięcie luk pomiędzy znakami MRZ. Następnie stosujemy progowanie za pomocą metody Otsu, aby automatycznie progować obraz:

Rysunek 4: zastosowanie operacji zamykania przy użyciu prostokątnego jądra (które jest szersze niż jest wysokie)w celu zamknięcia luk między znakami MRZ
Rysunek 4: Zastosowanie operacji zamykania za pomocą prostokątnego jądra (które jest szersze niż jest wysokie) w celu zamknięcia luk między znakami MRZ

jak widać na powyższym rysunku, każda z linii MRZ jest obecna na naszej mapie progowej.

następnym krokiem jest zamknięcie luk między rzeczywistymi liniami, dając nam jeden duży prostokątny obszar, który odpowiada 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)

tutaj wykonujemy kolejną operację zamykania, tym razem używając naszego kwadratowego jądra. Jądro to służy do zamykania luk między poszczególnymi liniami MRZ, dając nam jeden duży obszar, który odpowiada MRZ. Następnie wykonuje się serię nadżerek, aby rozdzielić połączone elementy, które mogły zostać połączone podczas operacji zamykania. Te nadżerki są również pomocne w usuwaniu małych plam, które są nieistotne dla MRZ.

Rysunek 5: wykonywana jest druga operacja zamykania, tym razem przy użyciu kwadratowego jądra do zamykania luk między poszczególnymi liniami MRZ.
Rysunek 5: Wykonywana jest druga operacja zamykania, tym razem przy użyciu kwadratowego jądra do zamykania luk między poszczególnymi liniami MRZ.

w przypadku niektórych skanów paszportowych granica paszportu mogła zostać dołączona do regionu MRZ podczas operacji zamykania. Aby temu zaradzić, ustawiliśmy 5% lewej i prawej krawędzi obrazu na zero (tj.):

# 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

poniżej możesz zobaczyć wyniki naszego usuwania granic.

Rysunek 6: ustawienie 5% pikseli lewej i prawej krawędzi na zero, upewnienie się, że region MRZ nie jest dołączony do zeskanowanego marginesu paszportu.
Rysunek 6: ustawienie 5% pikseli lewej i prawej krawędzi na zero, upewnienie się, że region MRZ nie jest dołączony do zeskanowanego marginesu paszportu.

w porównaniu z rysunkiem 5 powyżej, możesz teraz zobaczyć, że ramka została usunięta.

ostatnim krokiem jest znalezienie konturów w naszym progowanym obrazie i użycie właściwości konturu do identyfikacji 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)

w linii 56-58 obliczamy kontury (tj. kontury) naszego rozmnożonego obrazu. Następnie bierzemy te kontury i sortujemy je na podstawie ich wielkości w porządku malejącym na linii 59 (co oznacza, że największe kontury są pierwsze na liście).

na linii 62 zaczynamy zapętlać naszą posortowaną listę konturów. Dla każdego z tych konturów obliczymy obwiednię (linia 66) i użyjemy jej do obliczenia dwóch właściwości: współczynnika kształtu i współczynnika pokrycia. Proporcje to po prostu szerokość obwiedni podzielona przez wysokość. Współczynnik pokrycia to szerokość obwiedni podzielona przez szerokość rzeczywistego obrazu.

korzystając z tych dwóch właściwości możemy sprawdzić na linii 72, aby sprawdzić, czy badamy region MRZ. MRZ jest prostokątny, o szerokości znacznie większej niż wysokość. MRZ powinien również obejmować co najmniej 75% obrazu wejściowego.

pod warunkiem, że te dwa przypadki się trzymają, linie 75-84 używają współrzędnych (x, y) obwiedni, aby wyodrębnić MRZ i narysować obwiednię na naszym obrazku wejściowym.

wreszcie linie 87-89 wyświetlają nasze wyniki.

wyniki

aby zobaczyć nasz detektor MRZ w akcji, wystarczy wykonać następujące polecenie:

$ python detect_mrz.py --images examples

poniżej można zobaczyć przykład udanego wykrycia MRZ, z MRZ zaznaczonym na Zielono:

Rysunek 7: po lewej stronie mamy obraz wejściowy. A po prawej mamy obszar MRZ, który został pomyślnie wykryty.
Rysunek 7: po lewej stronie mamy nasz obraz wejściowy. A po prawej mamy obszar MRZ, który został pomyślnie wykryty.

oto kolejny przykład wykrywania strefy do odczytu maszynowego w obrazie paszportowym za pomocą Pythona i OpenCV:

Rysunek 8: Zastosowanie wykrywania MRZ do zeskanowanego paszportu.
Rysunek 8: Zastosowanie wykrywania MRZ do zeskanowanego paszportu.

nie ma znaczenia, czy region MRZ znajduje się u góry, czy u dołu obrazu. Stosując operacje morfologiczne, wyodrębniając kontury i obliczając właściwości konturów, jesteśmy w stanie bez problemu wyodrębnić MRZ.

to samo dotyczy następującego obrazu:

Rysunek 9: wykrywanie stref odczytywalnych maszynowo na obrazach za pomocą wizji komputerowej.
Rysunek 9: wykrywanie stref odczytywalnych maszynowo na obrazach za pomocą wizji komputerowej.

spróbujmy innego obrazu:

Rysunek 10: ponownie jesteśmy w stanie wykryć MRZ w skanie paszportu przy użyciu podstawowych technik przetwarzania obrazu.
Rysunek 10: ponownie jesteśmy w stanie wykryć MRZ na skanie paszportu przy użyciu podstawowych technik przetwarzania obrazu.

do tej pory widzieliśmy tylko MRZ typu 1, które zawierają trzy linie. Jednak nasza metoda działa równie dobrze z MRZ typu 3, które zawierają tylko dwie linie:

Rysunek 11: wykrywanie MRZ na obrazie paszportowym typu 3 przy użyciu Pythona i OpenCV.
Rysunek 11: Wykrywanie MRZ w obrazie paszportowym typu 3 przy użyciu Pythona i OpenCV.

oto kolejny przykład wykrywania MRZ typu 3:

Rysunek 12: Zastosowanie wizji komputerowej i przetwarzania obrazu do wykrywania stref odczytywalnych maszynowo na obrazach.
Rysunek 12: Zastosowanie wizji komputerowej i przetwarzania obrazu do wykrywania stref odczytywalnych maszynowo na obrazach.

co dalej? Polecam PyImageSearch University.

informacje o kursie:
30 + wszystkich klas * 39h 44m video * Ostatnia aktualizacja: 12/2021
★★★★★ 4.84 (128 oceny) * ponad 3000 uczniów

mocno wierzę, że gdybyś miał odpowiedniego nauczyciela, mógłbyś opanować widzenie komputerowe i głębokie uczenie się.

czy uważasz, że uczenie się wizji komputerowej i uczenia głębokiego musi być czasochłonne, przytłaczające i skomplikowane? A może wymaga skomplikowanej matematyki i równań? Czy wymaga Dyplomu z informatyki?

wszystko, czego potrzebujesz, aby opanować widzenie komputerowe i głębokie uczenie się, to ktoś, kto wyjaśni ci rzeczy w prosty, intuicyjny sposób. I to właśnie robię. Moją misją jest zmiana edukacji i sposobu nauczania złożonych tematów sztucznej inteligencji.

jeśli poważnie myślisz o nauce widzenia komputerowego, następnym przystankiem powinien być Uniwersytet PyImageSearch, najbardziej wszechstronny komputerowy wzrok, głębokie uczenie się i kurs OpenCV online dzisiaj. Tutaj dowiesz się, jak skutecznie i pewnie zastosować wizję komputerową w swojej pracy, badaniach i projektach. Dołącz do mnie w opanowaniu widzenia komputerowego.

w PyImageSearch University znajdziesz:

  • &sprawdź; 30 + kursów na temat niezbędnej wizji komputerowej, głębokiego uczenia się i tematów OpenCV
  • &sprawdź; 30+ certyfikatów ukończenia
  • &sprawdź; 39h 44m wideo na żądanie
  • &sprawdź; zupełnie nowe kursy wydawane co miesiąc, dzięki czemu możesz nadążyć za najnowocześniejszymi technikami
  • &sprawdź; wstępnie skonfigurowane Notebooki Jupyter w Google Colab
  • &sprawdź; Uruchom wszystkie przykłady kodu w przeglądarce internetowej-działa na Windows, MacOS i Linux (nie wymaga konfiguracji środowiska dev!)
  • &sprawdź; Dostęp do scentralizowanych repo kodu dla wszystkich 500 + samouczków na PyImageSearch
  • & sprawdź; łatwe pobieranie kodu jednym kliknięciem, zestawów danych, wstępnie przeszkolonych modeli itp.
  • &sprawdź; dostęp na telefonie komórkowym, laptopie, komputerze stacjonarnym itp.

Kliknij tutaj, aby dołączyć do Pyimagesearch University

podsumowanie

w tym poście na blogu dowiedzieliśmy się, jak wykrywać strefy czytelne maszynowo (MRZS) w skanach paszportów przy użyciu tylko podstawowych technik przetwarzania obrazu, a mianowicie:

  • próg.
  • operacje morfologiczne (w szczególności zamknięcia i nadżerki).
  • właściwości konturu.

te operacje, choć proste, pozwoliły nam wykryć obszary MRZ na obrazach bez konieczności korzystania z bardziej zaawansowanych metod ekstrakcji funkcji i uczenia maszynowego, takich jak Linear SVM + HOG do wykrywania obiektów.

pamiętaj, w obliczu trudnego problemu widzenia komputerowego – zawsze rozważ problem i swoje założenia! Jak pokazuje ten post na blogu, możesz być zaskoczony, jakie podstawowe funkcje przetwarzania obrazu używane w tandemie mogą osiągnąć.

jeszcze raz wielkie podziękowania dla członka PyImageSearch Guru, Hansa Boone ’ a, który dostarczył nam te przykładowe zdjęcia paszportowe! Dzięki Hans!

Leave a Reply

Twój adres e-mail nie zostanie opublikowany.