Hétvégi projekt: jelnyelv és statikus gesztusfelismerés scikit-learn segítségével

Készítsünk egy gépi tanulási folyamatot, amely képes elolvasni a jelnyelvi ábécét, csak megnézve az ember kezének nyers képét.

Ennek a problémának két része van:

  1. Statikus gesztusfelismerő építése, amely egy többosztályos osztályozó, amely megjósolja a statikus jelnyelvi gesztusokat.
  2. A kéz megkeresése a nyers képen és a kép ezen szakaszának betáplálása a statikus gesztusfelismerőbe (többosztályos osztályozó).

A projekt példakódomat és az adatkészletemet itt szerezheti be.

Először néhány háttér.

A gesztusfelismerés nyitott probléma a gépi látás területén, a számítástechnika területén, amely lehetővé teszi a rendszerek számára az emberi látás emulálását. A gesztusfelismerésnek számos alkalmazása van az ember és a számítógép közötti interakció javításában, és az egyik a jelnyelvi fordítás területén található, ahol a szimbolikus kézmozdulatok videoszekvenciáját lefordítják természetes nyelvre.

Számos fejlett módszert fejlesztettek ki ugyanezekre. Itt megvizsgáljuk, hogyan lehet a statikus gesztusfelismerést végrehajtani a scikit learn és scikit képkönyvtárak segítségével.

1. rész: Statikus gesztusfelismerő építése

Ehhez a részhez nyers képeket és egy megfelelő csv fájlt tartalmazó koordinátákat használunk, amelyek koordinátáival jelzik az egyes képek kezének határoló mezőjét. (Használja a Dataset.zip fájlt a minta adatkészlet megszerzéséhez. Kivonat a readme fájl utasításainak megfelelően)

Ez az adatkészlet felhasználónként szervezett, és az adatkészlet könyvtárszerkezete a következő. A képnevek a kép által ábrázolt ábécét jelzik.

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

A statikus gesztusfelismerő lényegében egy többosztályos osztályozó, amely a 24 statikus jelnyelvi gesztust (AY kivételével J) ábrázoló bemeneti képekre van kiképezve.

A statikus gesztusfelismerő felépítése a nyers képek és a csv fájl segítségével meglehetősen egyszerű.

A scikit learning könyvtár többosztályos osztályozóinak használatához először fel kell építenünk az adatkészletet - vagyis minden képet át kell alakítani jellemzővektorrá (X), és minden képen lesz egy címke, amely megfelel a jelnyelvi ábécé, amelyet (Y) jelöl.

A legfontosabb most egy megfelelő stratégia használata a kép vektorizálására és az értelmes információk kinyerésére az osztályozó számára. A nyers pixelértékek egyszerű használata nem fog működni, ha egyszerű, többosztályos osztályozók használatát tervezzük (szemben a Convolution Networks használatával).

Képeink vektorizálásához a Histogram of Oriented Gradients (HOG) megközelítést alkalmazzuk, mivel bebizonyosodott, hogy jó eredményeket hoz olyan problémáknál, mint ez. További használható funkciók a helyi bináris minták és a Haar-szűrők.

Kód:

A get_data () függvényben pandákat használunk a CSV fájl betöltésére. Két függvény (crop)és convertToGrayToHog ()használják a szükséges disznóvektor megszerzésére és a többosztályos osztályozó kiképzéséhez csatolják az épülő vektorok listájához.

# 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

A következő lépés a kimeneti címkék (az Y-értékek) numerikus értékekké történő kódolása. Ezt a sklearn címkekódolójával használjuk.

Kódunkban ezt a következőképpen tettük:

Y_mul = self.label_encoder.fit_transform(Y_mul)

ahol a label_encoder objektum a következőképpen épül fel a gesztus-felismerő osztály konstruktorán belül:

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

Miután ez megtörtént, a modell betanítható bármely, a scikit tanulás eszköztárból választott tetszőleges többosztályos osztályozási algoritmus segítségével. Képeztük a mieinket a Support Vector Classification segítségével, lineáris kernellel.

A modell sklearn használatával történő képzése nem tartalmaz kettőnél több kódsort. Így csinálod:

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

A hiperparamétereket (azaz C = 0,9 ebben az esetben) a Rács kereséssel lehet hangolni. További információ erről itt.

Ebben az esetben nem sokat tudunk az adatokról mint olyanokról (azaz a disznó vektorokról). Szóval jó lenne kipróbálni olyan algoritmusokat, mint az xgboost (Extreme Gradient Boosting) vagy a Random Forest Classifiers, és megnézni, hogyan teljesítenek ezek az algoritmusok.

2. rész: A Localizer felépítése

Ez a rész valamivel több erőfeszítést igényel az elsőhöz képest.

Általánosságban a következő lépéseket fogjuk végrehajtani a feladat végrehajtásához.

  1. Készítsen egy adatsort, amely a kezek és a nem kézi részek képeit tartalmazza, az adott képkészlet és az egyes képek határoló mező értékeinek felhasználásával.
  2. Képezzen egy bináris osztályozót a kézi / nem kézi képek észlelésére a fenti adatsor felhasználásával.
  3. (Opcionális) Használja a Hard Negative Mining alkalmazást az osztályozó fejlesztéséhez.
  4. Használjon csúszóablakos megközelítést különféle léptékekkel a lekérdezés képén az érdeklődési körzet elkülönítéséhez.

Itt nem fogunk használni semmilyen képfeldolgozási technikát, például szűrést, színszegmentálást stb. A scikit képkönyvtárat a képek olvasására, kivágására, méretezésére, szürkeárnyalatos konvertálására és a disznó vektorok kivonására használják.

A kéz / nem kéz adatkészlet felépítése:

Az adatkészlet bármilyen tetszőleges stratégiával felépíthető. Ennek egyik módja a véletlenszerű koordináták előállítása, majd a kereszteződés és az egyesülés területének arányának (azaz az adott határoló mezővel való átfedés mértékének) az arányának ellenőrzése annak megállapítására, hogy nem kézi szakaszról van-e szó. (Egy másik megközelítés lehet egy csúszó ablak használata a koordináták meghatározásához. De ez rettenetesen lassú és felesleges)

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

Bináris osztályozó képzése:

Miután elkészült az adatkészlet, az osztályozó betanítása pontosan úgy történhet, ahogyan azt az 1. rész korábban látta.

Általában ebben az esetben a Hard Negative Mining nevű technikát alkalmazzák a hamis pozitív észlelések számának csökkentésére és az osztályozó fejlesztésére. Egy vagy két nehéz negatív bányászat véletlenszerű erdei osztályozóval történő elvégzése elegendő annak biztosításához, hogy osztályozója elfogadható osztályozási pontosságot érjen el, ami ebben az esetben meghaladja a 80% -ot.

Vessen egy pillantást az itt található kódra annak mintavételére.

Kéz észlelése a tesztképeken:

A fenti osztályozó tényleges használatához a tesztképet különféle tényezőkkel méretezzük, majd mindegyiken csúszóablakos megközelítéssel választjuk ki azt az ablakot, amely tökéletesen megragadja az érdeklődési körzetet. Ez úgy történik, hogy kiválasztjuk azt a régiót, amely megfelel a bináris (kézi / nem-kézi) osztályozó által az összes skálán elosztott megbízhatósági pontszám max.

A tesztképeket méretezni kell, mert egy meghatározott méretű ablakot futtatunk (esetünkben 128x128) az összes képen, hogy kiválasszuk az érdeklődési területet, és lehetséges, hogy az érdeklődési terület nem illeszkedik tökéletesen ebbe az ablakméretbe .

Minta megvalósítás és átfogó felismerés minden skálán.

Összedobva az egészet

Miután mindkét rész elkészült, csak annyit kell tennie, hogy egymás után hívja őket, hogy megkapják a végső kimenetet, ha tesztképpel látják el.

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. Using the above classifiers one after the other to perform the required task.

Suks and I worked on this project as part of the Machine Learning course that we took up in college. A big shout out to her for all her contributions!

Also, we wanted to mention Pyimagesearch, which is a wonderful blog that we used extensively while we were working on the project! Do check it out for content on image processing and opencv related content.

Cheers!