Viikonloppuprojekti: viittomakieli ja staattisten eleiden tunnistaminen scikit-learn-toiminnolla

Rakennetaan koneoppimisputki, joka pystyy lukemaan viittomakielen aakkoset katsomalla raakakuvaa ihmisen kädestä.

Tässä ongelmassa on kaksi osaa:

  1. Staattisen eleentunnistimen rakentaminen, joka on moniluokkainen luokittelija, joka ennustaa staattiset viittomakielen eleet.
  2. Käden sijainti raakakuvassa ja kuvan tämän osan syöttäminen staattiselle eletunnistimelle (moniluokkaluokittaja).

Voit saada esimerkkikoodini ja tietoaineiston tälle projektille täältä.

Ensinnäkin jonkinlainen tausta.

Eleiden tunnistaminen on avoin ongelma konenäön alueella, tietojenkäsittelytieteessä, jonka avulla järjestelmät voivat jäljitellä ihmisen näkemystä. Eleentunnistuksella on monia sovelluksia ihmisen ja tietokoneen välisen vuorovaikutuksen parantamiseksi, ja yksi niistä on viittomakielen kääntämisen alalla, jossa symbolisten käeeleiden videosarja käännetään luonnolliselle kielelle.

Samalle on kehitetty joukko edistyneitä menetelmiä. Tässä tarkastellaan, kuinka staattinen eleentunnistus suoritetaan scikit-oppimisen ja skikit-kuvakirjastojen avulla.

Osa 1: Staattisten eleiden tunnistimen rakentaminen

Tässä osassa käytämme tietojoukkoa, joka käsittää raakakuvat ja vastaavan csv-tiedoston, jonka koordinaatit osoittavat käden rajoittavan ruudun jokaisessa kuvassa. (Käytä Dataset.zip-tiedostoa saadaksesi esimerkkitietojoukon. Pura readme-tiedoston ohjeiden mukaisesti)

Tämä tietojoukko on järjestetty käyttäjäkohtaisesti, ja tietojoukon hakemistorakenne on seuraava. Kuvanimet osoittavat kuvan edustaman aakkosen.

dataset |----user_1 |---A0.jpg |---A1.jpg |---A2.jpg |---... |---Y9.jpg |----user_2 |---A0.jpg |---A1.jpg |---A2.jpg |---... |---Y9.jpg |---- ... |---- ...

Staattinen eleentunnistin on pohjimmiltaan moniluokkainen luokittelija, joka on koulutettu 24 staattista viittomakielen elettä (AY lukuun ottamatta J) edustaviin tulokuviin.

Staattisen eleentunnistimen rakentaminen raakakuvien ja csv-tiedoston avulla on melko yksinkertaista.

Jotta voisimme käyttää scikit-oppimiskirjaston moniluokkaluokituksia, meidän on ensin rakennettava tietojoukko - jokainen kuva on muunnettava ominaisuusvektoriksi (X) ja jokaisella kuvalla on tarra, joka vastaa viittomakielen aakkoset, joita se tarkoittaa (Y).

Tärkeintä on nyt käyttää asianmukaista strategiaa kuvan vektorointiin ja poimia mielekästä tietoa luokittelijalle syötettäväksi. Pelkkä raakapikseliarvojen käyttö ei toimi, jos aiomme käyttää yksinkertaisia ​​moniluokkaluokituksia (toisin kuin Convolution Networks).

Kuvien vektorointiin käytämme HOG (Oriogram of Oriented Gradients) -lähestymistapaa, koska sen on osoitettu tuottavan hyviä tuloksia tämän kaltaisissa ongelmissa. Muita käytettäviä ominaisuuspuristimia ovat paikalliset binaarikuviot ja Haar-suodattimet.

Koodi:

Käytämme pandoja get_data () -toiminnossa CSV-tiedoston lataamiseen. Kaksi toimintoa - rajaus ()ja convertToGrayToHog ()Niitä käytetään vaaditun sika-vektorin hankkimiseen ja sen liittämiseen rakentamiemme vektorien luetteloon moniluokkaisen luokittelijan kouluttamiseksi.

# returns hog vector of a particular image vector def convertToGrayToHOG(imgVector): rgbImage = rgb2gray(imgVector) return hog(rgbImage) # returns cropped image def crop(img, x1, x2, y1, y2, scale): crp=img[y1:y2,x1:x2] crp=resize(crp,((scale, scale))) return crp #loads data for multiclass classification def get_data(user_list, img_dict, data_directory): X = [] Y = [] for user in user_list: user_images = glob.glob(data_directory+user+'/*.jpg') boundingbox_df = pd.read_csv(data_directory + user + '/' + user + '_loc.csv') for rows in boundingbox_df.iterrows(): cropped_img = crop( img_dict[rows[1]['image']], rows[1]['top_left_x'], rows[1]['bottom_right_x'], rows[1]['top_left_y'], rows[1]['bottom_right_y'], 128 ) hogvector = convertToGrayToHOG(cropped_img) X.append(hogvector.tolist()) Y.append(rows[1]['image'].split('/')[1][0]) return X, Y

Seuraava vaihe on koodata tulostustarrat (Y-arvot) numeerisiin arvoihin. Teemme tämän sklearnin tarra-kooderilla.

Koodissamme olemme tehneet tämän seuraavasti:

Y_mul = self.label_encoder.fit_transform(Y_mul)

missä label_encoder-objekti rakennetaan seuraavasti eleentunnistinluokan konstruktorissa:

self.label_encoder = LabelEncoder().fit(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'])

Kun tämä on tehty, malli voidaan kouluttaa millä tahansa valitsemallasi usean luokan luokitusalgoritmilla scikit learn -työkaluryhmästä. Olemme kouluttaneet omiamme käyttämällä tukivektoriluokitusta, lineaarisella ytimellä.

Mallin kouluttaminen sklearnin avulla ei sisällä enempää kuin kaksi koodiriviä. Näin teet sen:

svcmodel = SVC(kernel='linear', C=0.9, probability=True) self.signDetector = svcmodel.fit(X_mul, Y_mul) 

Hyperparametrit (ts. C = 0,9 tässä tapauksessa) voidaan virittää ruudukkohaulla. Lue lisää täältä.

Tässä tapauksessa emme tiedä paljon tiedoista sinänsä (ts. Sika-vektorit). Joten olisi hyvä kokeilla algoritmeja, kuten xgboost (Extreme Gradient Boosting) tai Random Forest Classifiers ja nähdä, miten nämä algoritmit toimivat.

Osa 2: Localizerin rakentaminen

Tämä osa vaatii hieman enemmän vaivaa kuin ensimmäinen.

Suoritamme yleensä seuraavat vaiheet tämän tehtävän suorittamiseksi.

  1. Rakenna tietojoukko, joka sisältää käsien ja osien kuvia, jotka eivät ole käsin, käyttämällä annettua tietojoukkoa ja kunkin kuvan rajoituslaatikon arvoja.
  2. Kouluta binääriluokittelija havaitsemaan käden / ei käden kuvat käyttämällä yllä olevaa tietojoukkoa.
  3. (Valinnainen) Käytä Hard Negative Mining -sovellusta luokituksen parantamiseen.
  4. Eristä kiinnostava alue kyselykuvassa käyttämällä liukuvan ikkunan lähestymistapaa useilla asteikoilla .

Täällä emme aio käyttää mitään kuvankäsittelytekniikoita, kuten suodatusta, värisegmenttiä jne. Scikit-kuvakirjastoa käytetään lukemaan, rajaamaan, skaalaamaan, muuntamaan kuvat harmaasävyiksi ja poimimaan sika-vektorit.

Käsi / ei käsi -tietojoukon rakentaminen:

Tietojoukko voitaisiin rakentaa haluamallasi strategialla. Yksi tapa tehdä tämä on tuottaa satunnaiset koordinaatit ja tarkistaa sitten leikkauspinta-alan suhde liitosalueeseen (ts. Päällekkäisyyden määrättyyn laatikkoon) sen selvittämiseksi, onko kyseessä muu kuin käsiosa. (Toinen lähestymistapa voisi olla liukuvan ikkunan käyttäminen koordinaattien määrittämiseen. Mutta tämä on hirvittävän hidasta ja tarpeetonta)

""" This function randomly generates bounding boxes Returns hog vector of those cropped bounding boxes along with label Label : 1 if hand ,0 otherwise """ def buildhandnothand_lis(frame,imgset): poslis =[] neglis =[] for nameimg in frame.image: tupl = frame[frame['image']==nameimg].values[0] x_tl = tupl[1] y_tl = tupl[2] side = tupl[5] conf = 0 dic = [0, 0] arg1 = [x_tl,y_tl,conf,side,side] poslis.append( convertToGrayToHOG(crop(imgset[nameimg], x_tl,x_tl+side,y_tl,y_tl+side))) while dic[0] <= 1 or dic[1] < 1: x = random.randint(0,320-side) y = random.randint(0,240-side) crp = crop(imgset[nameimg],x,x+side,y,y+side) hogv = convertToGrayToHOG(crp) arg2 = [x,y, conf, side, side] z = overlapping_area(arg1,arg2) if dic[0] <= 1 and z <= 0.5: neglis.append(hogv) dic[0] += 1 if dic[0]== 1: break label_1 = [1 for i in range(0,len(poslis)) ] label_0 = [0 for i in range(0,len(neglis))] label_1.extend(label_0) poslis.extend(neglis) return poslis,label_1

Binaarisen luokittelijan koulutus:

Kun tietojoukko on valmis, luokittelijan koulutus voidaan suorittaa täsmälleen kuten osassa 1 nähtiin.

Yleensä tässä tapauksessa käytetään tekniikkaa nimeltä Hard Negative Mining väärien positiivisten havaintojen määrän vähentämiseksi ja luokittelun parantamiseksi. Yksi tai kaksi iteraatiota kovasta negatiivisesta kaivoksesta käyttämällä satunnaista metsäluokitinta riittää varmistamaan, että luokittelija saavuttaa hyväksyttävän luokitustarkkuuden, mikä tässä tapauksessa on yli 80%.

Katsokaa tässä olevaa koodia saadaksesi esimerkin siitä.

Käsien tunnistaminen testikuvista:

Nyt, kun haluat käyttää yllä olevaa luokitinta, skaalamme testikuvan useilla tekijöillä ja valitsemme sitten liukuvan ikkunan lähestymistavan kaikille niille valitsemaan ikkunan, joka sieppaa kiinnostavan alueen täydellisesti. Tämä tehdään valitsemalla alue, joka vastaa binäärisen (käsi / ei-käsi) luokittelijan jakamien luottamuspisteiden maksimiä kaikissa asteikoissa.

Testikuvat on skaalattava, koska suoritamme määrätyn kokoisen ikkunan (meidän tapauksessamme se on 128x128) kaikkien kuvien kohdalla valitaksesi kiinnostavan alueen ja on mahdollista, että kiinnostava alue ei sovi täydellisesti tähän ikkunakokoon .

Näytteen toteutus ja yleinen havaitseminen kaikilla asteikoilla.

Yhdistämällä kaikki yhteen

Kun molemmat osat ovat valmiit, on jäljellä vain soittaa heille peräkkäin saadakseen lopullinen tulos testikuvan mukana.

That is, given a test image, we first get the various detected regions across different scales of the image and pick the best one among them. This region is then cropped out, rescaled (to 128x128) and its corresponding hog vector is fed to the multi-class classifier (i.e., the gesture recognizer). The gesture recognizer then predicts the gesture denoted by the hand in the image.

Key points

To summarize, this project involves the following steps. The links refer to the relevant code in the github repository.

  1. Building the hand/not-hand dataset.
  2. Converting all the images i.e., cropped sections with the gestures and the hand, not-hand images, to its vectorized form.
  3. Building a binary classifier for detecting the section with the hand and building a multi-class classifier for identifying the gesture using these data sets.
  4. Edellä mainittujen luokittelijoiden käyttö peräkkäin vaaditun tehtävän suorittamiseksi.

Suks ja minä työskentelimme tämän projektin parissa koneoppimiskurssilla, jonka aloitimme yliopistossa. Suuri huuto hänelle kaikesta panoksestaan!

Halusimme myös mainita Pyimagesearchin, joka on upea blogi, jota käytimme laajasti projektin parissa! Tarkista se kuvankäsittelyn sisällöstä ja avoimeen sisältöön liittyvästä sisällöstä.

Kippis!