koneellisesti luettavien vyöhykkeiden havaitseminen passikuvissa
tänään blogikirjoitus ei olisi mahdollista ilman PyImageSearch Gurus jäsen, Hans Boone. Hans työskentelee tietokonenäköprojektissa tunnistaakseen automaattisesti koneellisesti luettavat alueet (Mrzs) passikuvissa-aivan kuten yllä olevassa kuvassa havaittu alue.
passeissa tai matkakorteissa MRZ-alue jakautuu kahteen luokkaan: tyyppiin 1 ja tyyppiin 3. Tyypin 1 MRZ: t ovat kolme riviä, joista jokainen rivi sisältää 30 merkkiä. Tyypin 3 MRZ: ssä on vain kaksi riviä, mutta jokainen rivi sisältää 44 merkkiä. Kummassakin tapauksessa MRZ koodaa tietyn kansalaisen tunnistetiedot, mukaan lukien passin tyyppi, passin tunnus, myöntävä maa, nimi, kansalaisuus, viimeinen voimassaolopäivä jne.
PyImageSearch gurujen kurssilla Hans näytti minulle edistymisensä projektissa ja kiinnostuin heti. Olen aina halunnut soveltaa passikuviin tietokonenäköalgoritmeja (lähinnä huvin vuoksi), mutta siihen ei ollut aineistoa. Passin sisältämien henkilötunnistetietojen vuoksi en tietenkään voinut kirjoittaa aiheesta blogikirjoitusta ja jakaa kuvia, joita käytin algoritmin kehittämiseen.
onneksi Hans suostui jakamaan osan näytteistä/näytekuvista, joihin hänellä on pääsy — ja tartuin tilaisuuteen leikkiä näillä kuvilla.
nyt, ennen kuin päästään pitkälle, on tärkeää huomata, että nämä passit eivät ole ”todellisia” siinä mielessä, että ne voidaan yhdistää todelliseen ihmiseen. Mutta ne ovat aitoja passeja, jotka on luotu väärillä nimillä, osoitteilla jne. kehittäjille, joiden kanssa työskennellä.
voisi ajatella, että passin MRZ — alueen havaitsemiseen tarvitaan hieman koneoppimista, ehkä lineaarisen SVM + HOG-kehyksen avulla ”MRZ-ilmaisimen” rakentaminen-mutta se olisi liioittelua.
sen sijaan MRZ-tunnistus voidaan suorittaa vain kuvankäsittelyn perustekniikoilla, kuten puinnilla, morfologisilla operaatioilla ja ääriviivaominaisuuksilla. Tämän blogikirjoituksen loppuosassa kerron yksityiskohtaisesti oman näkemykseni siitä, miten näitä menetelmiä voidaan soveltaa passin MRZ-alueen havaitsemiseen.
Etsitkö lähdekoodia tähän viestiin?
siirry suoraan lataukset-osioon
koneellisesti luettavien vyöhykkeiden havaitseminen passikuvissa
mennään eteenpäin ja aloitetaan tämä projekti. Avaa uusi tiedosto, nimeä se detect_mrz.py
ja lisää seuraava koodi:
# 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))
linjat 2-6 tuo tarvittavat paketit. Oletan, että sinulla on jo OpenCV asennettuna. Tarvitset myös imutils, my collection of convenience-toiminnot, jotta perus kuvankäsittelytoiminnot OpenCV: llä helpottuvat. Voit asentaa imutils
käyttämällä pip
:
$ pip install --upgrade imutils
sieltä rivit 9-11 käsittelevät komentoriviargumentin jäsentämistä. Tarvitsemme vain yhden kytkimen, --images
, joka on polku hakemistoon, joka sisältää passikuvat, joita aiomme käsitellä.
lopuksi rivit 14 ja 15 alustavat kaksi ydintä, joita myöhemmin käytämme morfologisissa operaatioissa, erityisesti sulkuoperaatiossa. Toistaiseksi, yksinkertaisesti huomaa, että ensimmäinen ydin on suorakulmainen leveys noin 3x suurempi kuin korkeus. Toinen ydin on neliö. Näiden ytimien avulla voimme sulkea aukot MRZ-merkkien ja aukkojen välillä MRZ-viivojen välillä.
nyt kun komentoriviargumenttimme on jäsennetty, voimme aloittaa jokaisen datajoukon kuvan silmukoinnin ja käsitellä niitä:
# 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)
linjat 20 ja 21 lataavat alkuperäisen kuvan levyltä ja muuttavat sen maksimikorkeudeksi 600 pikseliä. Näet esimerkin alkuperäisestä kuvasta alla:
Gaussin sumennusta käytetään linjalla 26 suurtaajuuskohinan vähentämiseksi. Sen jälkeen tehdään Mustahat-morfologinen operaatio sumeaan, harmaasävyiseen kuvaan rivillä 27.
mustahatunoperaattoria käytetään paljastamaan tummia alueita (eli MRZ-tekstiä) vaaleita taustoja (eli itse passin taustaa) vasten. Koska passiteksti on aina musta vaalealla pohjalla (ainakin tämän aineiston osalta), blackhat-operaatio on paikallaan. Alla näet tuotoksen soveltamalla blackhat operaattori:
seuraava vaihe MRZ-tunnistuksessa on laskea mustahat-kuvan gradienttimagnitudiesitys Scharr-operaattorilla:
# 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")
tässä lasketaan Scharr-gradientti blackhat-kuvan x-akselia pitkin paljastaen kuvan alueet, jotka eivät ole ainoastaan tummia vaaleaa taustaa vasten, vaan sisältävät myös pystysuoria muutoksia gradientissä, kuten MRZ-tekstialue. Otamme tämän gradienttikuvan ja Skaalaamme sen takaisin alueelle käyttäen min / max-skaalausta:
vaikka ei ole täysin selvää, miksi käytämme tätä vaihetta, sanon, että se on erittäin hyödyllinen väärien positiivisten MRZ-havaintojen vähentämisessä. Ilman sitä voimme vahingossa merkitä passin koristellut tai suunnitellut alueet MRZ: ksi. Jätän tämän tehtäväksenne varmistaaksenne, että Blackhat-kuvan gradientin laskeminen voi parantaa MRZ-tunnistustarkkuutta.
seuraava vaihe on yrittää havaita MRZ: n todelliset viivat:
# 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)
ensin tehdään sulkuoperaatio suorakulmaisen ytimen avulla. Sulkemisoperaation tarkoituksena on paikata MRZ-merkkien välisiä aukkoja. Sitten sovellamme thresholding Otsun menetelmällä automaattisesti kynnys kuvan:
välisten aukkojen sulkemiseksi, kuten voimme nähdä yllä olevasta kuvasta, jokainen MRZ-viiva on läsnä kynnyskartassamme.
seuraava vaihe on sulkea varsinaisten viivojen väliset raot, jolloin saadaan yksi suuri suorakulmainen alue, joka vastaa 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)
tässä suoritamme toisen sulkemisoperaation, tällä kertaa käyttäen neliöydintämme. Tätä ydintä käytetään MRZ: n yksittäisten rivien välisten aukkojen sulkemiseen, jolloin saadaan yksi suuri alue, joka vastaa MRZ: ää. Tämän jälkeen suoritetaan sarja eroosioita, jotka hajottavat toisiinsa kytkettyjä osia, jotka ovat saattaneet olla yhdistettyinä sulkemisoperaation aikana. Nämä eroosiot auttavat myös poistamaan pieniä möykkyjä, jotka eivät ole MRZ: n kannalta merkityksellisiä.
joissakin passikuvauksissa passin raja on saattanut kiinnittyä MRZ-alueeseen sulkemisoperaatioiden aikana. Tämän korjaamiseksi asetamme 5% kuvan vasemmasta ja oikeasta reunasta nollaan (eli mustaan):
# 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
rajanpoistomme tuotoksen näet alta.
verrattuna yllä olevaan kuvioon 5, voi nyt nähdä, että raja on poistettu.
viimeinen vaihe on löytää ääriviivat kuvastamme ja käyttää ääriviivaominaisuuksia MRZ: n tunnistamiseen:
# 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)
rivillä 56-58 laskemme kuvamme ääriviivat (eli ääriviivat). Sitten otamme nämä ääriviivat ja lajittelemme ne niiden koon perusteella alenevassa järjestyksessä rivillä 59 (mikä tarkoittaa, että suurimmat ääriviivat ovat ensimmäisenä luettelossa).
linjalla 62 alamme silmukoida lajiteltuja ääriviivojamme. Kullekin ääriviivoille laskemme rajauslaatikon (rivi 66) ja käytämme sitä laskemaan kahta ominaisuutta: kuvasuhdetta ja peittosuhdetta. Kuvasuhde on yksinkertaisesti rajauslaatikon leveys jaettuna korkeudella. Peittävyyssuhde on rajauskentän leveys jaettuna varsinaisen kuvan leveydellä.
näiden kahden ominaisuuden avulla voimme tarkistaa riviltä 72, tutkimmeko MRZ-aluetta. MRZ on suorakulmainen, jonka leveys on paljon suurempi kuin korkeus. MRZ: n pitäisi myös kattaa vähintään 75% syötetystä kuvasta.
jos nämä kaksi tapausta pitävät, rivit 75-84 käyttävät rajauslaatikon (x, y)-koordinaatteja MRZ: n purkamiseen ja rajauslaatikon piirtämiseen syötekuvastamme.
lopulta rivit 87-89 näyttävät tuloksemme.
tulokset
jos haluat nähdä MRZ-ilmaisimen toiminnassa, suorita seuraava komento:
$ python detect_mrz.py --images examples
alla on esimerkki onnistuneesta MRZ-tunnistuksesta, jossa MRZ on hahmoteltu vihreällä:
tässä on toinen esimerkki koneellisesti luettavan alueen havaitsemisesta passikuvassa Pythonin ja OpenCV: n avulla:
sillä ei ole väliä, onko MRZ-alue kuvan ylä-vai alaosassa. Käyttämällä morfologisia operaatioita, poimimalla ääriviivat ja laskemalla ääriviivat ominaisuudet, voimme poimia MRZ ilman ongelmia.
sama pätee myös seuraavaan kuvaan:
kokeillaan toista kuvaa:
tähän mennessä on tavattu vain tyypin 1 MRZ: iä, joissa on kolme riviä. Menetelmämme toimii kuitenkin yhtä hyvin tyypin 3 MRZ: ien kanssa, jotka sisältävät vain kaksi riviä:
Tässä toinen esimerkki tyypin 3 MRZ: n havaitsemisesta:
mitä seuraavaksi? Suosittelen PyImageSearch University.
30 + yhteensä luokat • 39h 44m video * päivitetty viimeksi: 12/2021
★★★★★ 4.84 (128 arvio) • 3000 + opiskelijaa ilmoittautui
uskon vahvasti, että jos sinulla olisi oikea opettaja, voisit hallita tietokonenäön ja syväoppimisen.
pitääkö tietokonenäön ja syväoppimisen olla mielestäsi aikaa vievää, musertavaa ja monimutkaista? Vai täytyykö siihen liittyä monimutkaista matematiikkaa ja yhtälöitä? Tai vaatii tietojenkäsittelytieteen tutkinnon?
näin ei ole.
tietokonenäön ja syväoppimisen hallitsemiseen tarvitaan vain se, että joku selittää asiat sinulle yksinkertaisilla, intuitiivisilla termeillä. Ja juuri niin minä teen. Tehtäväni on muuttaa koulutusta ja sitä, miten monimutkaisia Tekoälyaiheita opetetaan.
jos olet tosissasi tietokonenäön oppimisesta, seuraava pysäkkisi pitäisi olla PyImageSearch University, kattavin tietokonenäkö, syväoppiminen ja OpenCV-kurssi verkossa tänään. Täällä opit, miten voit menestyksekkäästi ja luottavaisesti soveltaa tietokonenäköä työhösi, tutkimuksiisi ja projekteihisi. Tule kanssani tietokonenäön hallintaan.
PyImageSearch Universityn sisältä löydät:
- &tarkista; 30+ kurssia, jotka käsittelevät olennaista tietokonenäköä, syväoppimista ja Openenssia
- ✓ 30+ todistukset suorittamisesta
- ✓ 39h 44m tilausvideo
- ✓ upouudet kurssit, jotka julkaistaan joka kuukausi varmistaen, että pysyt ajan tasalla huipputekniikan kanssa
- &tarkista; valmiiksi konfiguroidut jupyter-muistikirjat Google colabissa
- &tarkista; suorita kaikki koodiesimerkit selaimessasi-toimii Windowsissa, MacOS: ssa ja Linuxissa (dev-ympäristön määritystä ei tarvita!)
- &tarkista; Pääsy keskitettyyn koodirepos kaikille 500 + tutorials PyImageSearch
- &tarkista; Helppo yhdellä napsautuksella lataukset koodi, tietokokonaisuudet, ennalta koulutetut mallit, jne.
- & check; Access on mobile, laptop, desktop, jne.
Klikkaa tästä liittyäksesi PyImageSearch University
Summary
tässä blogikirjoituksessa opimme tunnistamaan koneellisesti luettavia alueita (Mrzs) passien skannauksissa käyttäen vain peruskuvankäsittelytekniikoita, eli:
- puinti.
- kaltevuudet.
- morfologiset operaatiot (erityisesti sulkemiset ja eroosiot).
- Ääriviivaominaisuudet.
nämä toiminnot, vaikkakin yksinkertaiset, mahdollistivat MRZ-alueiden havaitsemisen kuvista ilman, että jouduimme turvautumaan kehittyneempiin piirteiden louhinta-ja koneoppimismenetelmiin, kuten lineaariseen SVM + HOG-menetelmään objektien havaitsemisessa.
muista, kun kohtaat haastavan tietokonenäköongelman-ota aina huomioon ongelma ja oletuksesi! Kuten tämä blogikirjoitus osoittaa, saatat olla yllättynyt, mitä perus kuvankäsittely toimintoja käytetään yhdessä voi saavuttaa.
vielä kerran suuret kiitokset PyImageSearch Gurun jäsenelle Hans Boonelle, joka toimitti meille nämä esimerkkipassikuvat! Kiitos Hans!