Викенд пројекат: језик знакова и препознавање статичних геста помоћу сцикит-леарн

Изградимо цевовод за машинско учење који може читати абецеду знаковног језика само гледајући сирову слику човекове руке.

Овај проблем се састоји из два дела:

  1. Изградња препознавача статичких геста, који је вишеразредни класификатор који предвиђа статичке гесте знаковног језика.
  2. Проналажење руке на необрађеној слици и додавање овог одељка слике у статички препознавач покрета (вишеразредни класификатор).

Мој пример кода и скупа података за овај пројекат можете добити овде.

Прво, мало позадине.

Препознавање геста је отворени проблем у области машинског вида, пољу рачунарских наука које омогућава системима да опонашају људски вид. Препознавање геста има много примена у побољшању интеракције човек-рачунар, а једна од њих је у пољу Превод знаковног језика, при чему је видео секвенца симболичних геста руку преведена на природни језик.

Развијен је низ напредних метода за исте. Овде ћемо погледати како да извршимо препознавање статичких геста помоћу библиотека сцикит леарн и сцикит слика.

1. део: Изградња препознавача статичких геста

У овом делу користимо скуп података који садржи сирове слике и одговарајућу цсв датотеку са координатама које означавају гранични оквир за руку на свакој слици. (Користите датотеку Датасет.зип да бисте добили узорак скупа података. Издвојите према упутствима у датотеци реадме)

Овај скуп података организован је према кориснику, а структура директорија скупа података је следећа. Имена слика означавају абецеду представљену сликом.

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

Препознавач статичких геста је у основи вишекласни класификатор који се обучава на улазним сликама које представљају 24 статична геста знаковног језика (АИ, искључујући Ј).

Изградња препознавача статичких геста помоћу сирових слика и цсв датотеке је прилично једноставна.

Да бисмо користили вишеразредне класификаторе из сцикит леарн библиотеке, прво ћемо морати да изградимо скуп података - то јест, свака слика мора да се претвори у вектор обележја (Кс) и свака слика ће имати ознаку која одговара абецеда знаковног језика коју означава (И).

Кључ је сада употреба одговарајуће стратегије за векторизацију слике и издвајање значајних информација за унос у класификатор. Једноставно коришћење необрађених вредности пиксела неће успети ако планирамо да користимо једноставне вишекласне класификаторе (за разлику од коришћења Цонволутион Нетворкс).

За векторизацију наших слика користимо приступ хистограма оријентисаних градијената (ХОГ), јер је доказано да даје добре резултате код проблема попут овог. Остали екстрактори карактеристика који се могу користити укључују локалне бинарне узорке и Хаар филтере.

Шифра:

За учитавање ЦСВ датотеке користимо панде у функцији гет_дата (). Две функције-обрезивање ()и цонвертТоГраиТоХог ()се користе за добијање потребног вектора свиња и његово додавање на листу вектора које градимо, како би се обучио вишеразредни класификатор.

# 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

Следећи корак је кодирање излазних ознака (И-вредности) у нумеричке вредности. То радимо помоћу склеарн-овог кодера за налепнице.

У нашем коду смо то урадили на следећи начин:

Y_mul = self.label_encoder.fit_transform(Y_mul)

при чему је објект лабел_енцодер конструисан на следећи начин у конструктору класе препознавача покрета:

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

Једном када се то уради, модел се може обучити помоћу било ког алгоритма за класификацију по вашем избору из сцикит леарн тоолбок-а. Обучили смо наше користећи класификацију вектора подршке, са линеарним језгром.

Обука модела помоћу склеарн-а не укључује више од две линије кода. Ево како се то ради:

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

Хиперпараметри (тј. Ц = 0,9 у овом случају) могу се подесити помоћу претраживања мреже. Прочитајте више о овоме овде.

У овом случају не знамо пуно података о подацима као таквима (тј. Свињским векторима). Дакле, било би добро да испробате и користите алгоритме као што су кгбоост (Ектреме Градиент Боостинг) или Рандом Форест Цлассифиерс и видите како ови алгоритми раде.

2. део: Изградња локализатора

Овај део захтева мало више напора у односу на први.

Уопште узевши, користићемо следеће кораке у извршавању овог задатка.

  1. Направите скуп података који садржи слике руку и делова који нису ручни, користећи дати скуп података и вредности граничног оквира за сваку слику.
  2. Обучите бинарни класификатор за откривање слика руку / руку које не користе руке користећи горњи скуп података.
  3. (Необавезно) Користите Хард Негативе Мининг да бисте побољшали класификатор.
  4. Користите приступ клизним прозорима са разним скалама на слици упита да бисте изоловали подручје од интереса.

Овде нећемо користити никакве технике обраде слика као што су филтрирање, сегментација боја итд. Сцикит библиотека слика се користи за читање, обрезивање, скалирање, претварање слика у сиву скалу и издвајање вектора свиња.

Израда скупа података „рука / рука“:

Скуп података може да се направи помоћу било које стратегије која вам се свиђа. Један од начина да се то постигне је генерисање случајних координата, а затим проверавање односа површине пресека и површине спајања (тј. Степена преклапања са датим граничним оквиром) да би се утврдило да ли је реч о не-ручном пресеку. (Други приступ би могао бити употреба клизног прозора за одређивање координата. Али ово је ужасно споро и непотребно)

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

Обука бинарног класификатора:

Једном када је скуп података спреман, оспособљавање класификатора може се обавити тачно онако како је раније приказано у првом делу.

Обично се у овом случају користи техника која се назива Хард Негативе Мининг како би се смањио број лажно позитивних детекција и побољшао класификатор. Једна или две итерације јаког негативног рударства помоћу случајног класификатора шума довољне су да осигурају да ваш класификатор достигне прихватљиве тачности класификације, што је у овом случају нешто изнад 80%.

Погледајте код овде за пример примене истог.

Откривање руку на тест сликама:

Сада, да бисмо у ствари користили горњи класификатор, пробну слику прилагођавамо различитим факторима, а затим користимо приступ клизним прозорима на свима њима да бисмо изабрали прозор који савршено обухвата подручје од интереса. То се постиже одабиром региона који одговара максимуму резултата поверења додељених бинарним (ручним / не-ручним) класификатором на свим скалама.

Пробне слике треба скалирати, јер покрећемо постављени прозор величине (у нашем случају је 128к128) на свим сликама да би изабрали област која вас занима, а могуће је да се област од интереса не уклапа савршено у ову величину прозора .

Примена узорка и свеукупна детекција на свим скалама.

Све састављање

По завршетку оба дела преостаје само да их позовите узастопно да бисте добили коначни излаз када су добили пробну слику.

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. Коришћење горњих класификатора један за другим за извршавање потребног задатка.

Сукс и ја смо радили на овом пројекту у оквиру курса машинског учења који смо похађали на факултету. Велики узвик за све њене доприносе!

Такође, желели смо да поменемо Пиимагесеарцх, предиван блог који смо интензивно користили док смо радили на пројекту! Проверите садржај за обраду слика и садржај који се односи на опенцв.

Живели!