Weekendprojekt: tegnsprog og anerkendelse af statisk gestus ved hjælp af scikit-learning

Lad os bygge en maskinlæringsrørledning, der kan læse tegnsprog-alfabetet bare ved at se på et rå billede af en persons hånd.

Dette problem består af to dele:

  1. Opbygning af en genkendelse af statisk gestus, som er en klassificering i flere klasser, der forudsiger de statiske tegnsprogbevægelser.
  2. Placering af hånden i det rå billede og indføring af dette afsnit af billedet til den statiske genkendelsesgenerator (klassificering i flere klasser).

Du kan få min eksempelkode og datasæt til dette projekt her.

Først lidt baggrund.

Gestusgenkendelse er et åbent problem inden for maskinsyn, et felt inden for datalogi, der gør det muligt for systemer at efterligne menneskelig vision. Gestusgenkendelse har mange applikationer til forbedring af interaktion mellem menneske og computer, og en af ​​dem er inden for tegnsprogsoversættelse, hvor en videosekvens af symbolske håndbevægelser oversættes til naturligt sprog.

En række avancerede metoder til det samme er blevet udviklet. Her ser vi på, hvordan man udfører statisk gestusgenkendelse ved hjælp af scikit-lærings- og scikit-billedbibliotekerne.

Del 1: Opbygning af en genkendelse af statisk gestus

Til denne del bruger vi et datasæt, der indeholder rå billeder og en tilsvarende csv-fil med koordinater, der angiver afgrænsningsboksen for hånden i hvert billede. (Brug Dataset.zip-filen til at hente eksempeldatasættet. Uddrag efter instruktionerne i readme-filen)

Dette datasæt er organiseret brugervenligt, og katalogets struktur i datasættet er som følger. Billednavne angiver alfabetet repræsenteret af billedet.

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

Den statiske gestusgenkenderen er i det væsentlige en klassifikator i flere klasser, der trænes i inputbilleder, der repræsenterer de 24 statiske tegnsprogbevægelser (AY, eksklusive J).

Opbygning af en statisk gestusgenkender ved hjælp af de rå billeder og csv-filen er ret enkel.

For at bruge klassifikatorerne i flere klasser fra scikit-læringsbiblioteket skal vi først oprette datasættet - det vil sige, hvert billede skal konverteres til en funktionsvektor (X), og hvert billede vil have en etiket svarende til tegnsprog alfabet, som det betegner (Y).

Nøglen er nu at bruge en passende strategi til at vektorisere billedet og udtrække meningsfuld information til feed til klassifikatoren. Blot at bruge de rå pixelværdier fungerer ikke, hvis vi planlægger at bruge enkle klassifikatorer i flere klasser (i modsætning til at bruge Convolution Networks).

For at vektorisere vores billeder bruger vi HOG-metoden Histogram of Oriented Gradients, da det har vist sig at give gode resultater på problemer som denne. Andre funktionsekstraktorer, der kan bruges, inkluderer lokale binære mønstre og Haar-filtre.

Kode:

Vi bruger pandaer i get_data () -funktionen til at indlæse CSV-filen. To funktioner-beskæring ()og convertToGrayToHog ()bruges til at hente den krævede svinevektor og føje den til listen over vektorer, som vi bygger, for at træne multi-klassifikatoren.

# 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

Det næste trin er at kode outputetiketterne (Y-værdierne) til numeriske værdier. Vi gør dette ved hjælp af sklearns labelkoder.

I vores kode har vi gjort dette som følger:

Y_mul = self.label_encoder.fit_transform(Y_mul)

hvor label_encoder-objektet er konstrueret som følger inden for gestus-genkenderklassekonstruktøren:

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'])

Når dette er gjort, kan modellen trænes ved hjælp af en hvilken som helst Multi-class klassificeringsalgoritme efter eget valg fra scikit learning-værktøjskassen. Vi har trænet vores ved hjælp af Support Vector Classification med en lineær kerne.

Træning af en model ved hjælp af sklearn involverer ikke mere end to linjer kode. Sådan gør du det:

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

Hyperparametrene (dvs. C = 0,9 i dette tilfælde) kan indstilles ved hjælp af en gittersøgning. Læs mere om dette her.

I dette tilfælde ved vi ikke meget om dataene som sådan (dvs. svinevektorerne). Så det ville være en god ide at prøve at bruge algoritmer som xgboost (Extreme Gradient Boosting) eller Random Forest Classifiers og se, hvordan disse algoritmer fungerer.

Del 2: Opbygning af Localizer

Denne del kræver en lidt mere indsats sammenlignet med den første.

Generelt anvender vi følgende trin til at udføre denne opgave.

  1. Byg et datasæt, der indeholder billeder af hænder og dele, der ikke er hånd, ved hjælp af det givne datasæt og afgrænsningsfeltets værdier for hvert billede.
  2. Træn en binær klassifikator til at opdage hånd- / ikke-håndbilleder ved hjælp af ovenstående datasæt.
  3. (Valgfrit) Brug Hard Negative Mining til at forbedre klassificeringen.
  4. Brug en glidende vindues tilgang med forskellige skalaer på forespørgselsbilledet for at isolere det interessante område.

Her vil vi ikke bruge nogen billedbehandlingsteknikker som filtrering, farvesegmentering osv. Scikit-billedbiblioteket bruges til at læse, beskære, skalere, konvertere billeder til gråskala og udtrække svinvektorer.

Bygge hånd / ikke hånddatasættet:

Datasættet kunne bygges ved hjælp af enhver strategi, du kan lide. En måde at gøre dette på er at generere tilfældige koordinater og derefter kontrollere forholdet mellem skæringsarealet og områdets foreningsområde (dvs. graden af ​​overlapning med det givne afgrænsningsfelt) for at afgøre, om det er et ikke-håndsnit. (En anden tilgang kan være at bruge et glidende vindue til at bestemme koordinaterne. Men dette er forfærdeligt langsomt og unødvendigt)

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

Uddannelse af en binær klassifikator:

Når datasættet er klar, kan træning af klassificeringen udføres nøjagtigt som set før i del 1.

Normalt anvendes i dette tilfælde en teknik kaldet Hard Negative Mining til at reducere antallet af falske positive detektioner og forbedre klassifikatoren. En eller to iterationer af hård negativ minedrift ved hjælp af en tilfældig skovklassificering er nok til at sikre, at din klassifikator når acceptabel klassificeringsnøjagtighed, hvilket i dette tilfælde er noget over 80%.

Se koden her for en prøveimplementering af den samme.

Registrering af hænder i testbilleder:

For faktisk at bruge ovennævnte klassifikator skalerer vi testbilledet efter forskellige faktorer og bruger derefter en glidende vinduetilgang til dem alle for at vælge det vindue, der perfekt fanger regionen af ​​interesse. Dette gøres ved at vælge det område, der svarer til det maksimale antal konfidensscorer tildelt af den binære (hånd / ikke-hånd) klassifikator på tværs af alle skalaer.

Testbillederne skaleres, fordi vi kører et vindue i en bestemt størrelse (i vores tilfælde er det 128x128) på tværs af alle billeder for at vælge det interesseregion, og det er muligt, at regionen af ​​interesse ikke passer perfekt ind i denne vinduesstørrelse .

Eksempel på implementering og samlet detektion på tværs af alle skalaer.

Samler det hele

Når begge dele er færdige, er alt, hvad der er tilbage at gøre, at kalde dem i rækkefølge for at få det endelige output, når de forsynes med et testbillede.

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. Brug af ovenstående klassifikatorer efter hinanden til at udføre den krævede opgave.

Suks og jeg arbejdede på dette projekt som en del af Machine Learning-kurset, som vi tog på college. Et stort råb til hende for alle hendes bidrag!

Vi ønskede også at nævne Pyimagesearch, som er en vidunderlig blog, som vi brugte meget, mens vi arbejdede på projektet! Tjek det for indhold på billedbehandling og opencv-relateret indhold.

Skål!