Proyek akhir pekan: pengenalan bahasa isyarat dan gerakan statis menggunakan scikit-learn

Mari buat pipeline machine learning yang dapat membaca alfabet bahasa isyarat hanya dengan melihat gambar mentah dari tangan seseorang.

Masalah ini memiliki dua bagian:

  1. Membangun pengenal isyarat statis, yang merupakan pengklasifikasi multi-kelas yang memprediksi isyarat bahasa isyarat statis.
  2. Menemukan tangan dalam gambar mentah dan memasukkan bagian gambar ini ke pengenal isyarat statis (pengklasifikasi multi-kelas).

Anda bisa mendapatkan kode contoh dan dataset saya untuk proyek ini di sini.

Pertama, beberapa latar belakang.

Pengenalan isyarat adalah masalah terbuka di bidang visi mesin, bidang ilmu komputer yang memungkinkan sistem meniru penglihatan manusia. Pengenalan isyarat memiliki banyak aplikasi dalam meningkatkan interaksi manusia-komputer, dan salah satunya di bidang Terjemahan Bahasa Isyarat, di mana rangkaian video isyarat tangan simbolik diterjemahkan ke dalam bahasa alami.

Berbagai metode lanjutan untuk hal yang sama telah dikembangkan. Di sini, kita akan melihat cara melakukan pengenalan gerakan statis menggunakan pustaka gambar scikit learn dan scikit.

Bagian 1: Membangun pengenal isyarat statis

Untuk bagian ini, kami menggunakan kumpulan data yang terdiri dari gambar mentah dan file csv yang sesuai dengan koordinat yang menunjukkan kotak pembatas untuk tangan di setiap gambar. (Gunakan file Dataset.zip untuk mendapatkan contoh kumpulan data. Ekstrak sesuai petunjuk di file readme)

Kumpulan data ini diatur menurut pengguna dan struktur direktori kumpulan data adalah sebagai berikut. Nama gambar menunjukkan alfabet yang diwakili oleh gambar.

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

Pengenal isyarat statis pada dasarnya adalah pengklasifikasi multi-kelas yang dilatih pada gambar masukan yang mewakili 24 isyarat bahasa isyarat statis (AY, tidak termasuk J).

Membangun pengenal isyarat statis menggunakan gambar mentah dan file csv cukup sederhana.

Untuk menggunakan pengklasifikasi multi-kelas dari pustaka scikit learn, kita harus terlebih dahulu membangun kumpulan data - yaitu, setiap gambar harus diubah menjadi vektor fitur (X) dan setiap gambar akan memiliki label yang sesuai dengan bahasa isyarat alfabet yang menunjukkan (Y).

Kuncinya sekarang adalah menggunakan strategi yang tepat untuk membuat vektor gambar dan mengekstrak informasi yang bermakna untuk dimasukkan ke pengklasifikasi. Hanya menggunakan nilai piksel mentah tidak akan berfungsi jika kita berencana menggunakan pengklasifikasi multi-kelas sederhana (sebagai lawan menggunakan Convolution Networks).

Untuk memvektorisasi gambar, kami menggunakan pendekatan Histogram of Oriented Gradients (HOG), karena telah terbukti memberikan hasil yang baik pada masalah seperti ini. Ekstraktor fitur lain yang dapat digunakan termasuk Pola Biner Lokal dan Filter Haar.

Kode:

Kami menggunakan panda dalam fungsi get_data () untuk memuat file CSV. Dua fungsi-crop ()dan convertToGrayToHog ()digunakan untuk mendapatkan vektor babi yang diperlukan dan menambahkannya ke daftar vektor yang sedang kita buat, untuk melatih pengklasifikasi multi-kelas.

# 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

Langkah selanjutnya adalah menyandikan label keluaran (nilai-Y) menjadi nilai numerik. Kami melakukan ini menggunakan encoder label sklearn.

Dalam kode kami, kami telah melakukan ini sebagai berikut:

Y_mul = self.label_encoder.fit_transform(Y_mul)

di mana, objek label_encoder dibuat sebagai berikut dalam konstruktor kelas pengenal isyarat:

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

Setelah ini selesai, model dapat dilatih menggunakan algoritme klasifikasi kelas jamak apa pun pilihan Anda dari scikit learn toolbox. Kami telah melatih kami menggunakan Klasifikasi Vektor Dukungan, dengan kernel linier.

Melatih model menggunakan sklearn tidak melibatkan lebih dari dua baris kode. Inilah cara Anda melakukannya:

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

Hyperparameter (yaitu, C = 0,9 dalam kasus ini) dapat disetel menggunakan Pencarian Grid. Baca lebih lanjut tentang ini di sini.

Dalam hal ini, kita tidak tahu banyak tentang data seperti itu (yaitu, vektor babi). Jadi, akan menjadi ide yang baik untuk mencoba dan menggunakan algoritma seperti xgboost (Extreme Gradient Boosting) atau Random Forest Classifiers dan melihat bagaimana kinerja algoritma ini.

Bagian 2: Membangun Localizer

Bagian ini membutuhkan usaha yang lebih sedikit dibandingkan dengan yang pertama.

Secara umum, kami akan menerapkan langkah-langkah berikut dalam menyelesaikan tugas ini.

  1. Buat kumpulan data yang terdiri dari gambar tangan dan bagian yang bukan tangan, menggunakan kumpulan data yang diberikan dan nilai kotak pembatas untuk setiap gambar.
  2. Latih pengklasifikasi biner untuk mendeteksi gambar tangan / bukan tangan menggunakan kumpulan data di atas.
  3. (Opsional) Gunakan Hard Negative Mining untuk meningkatkan pengklasifikasi.
  4. Gunakan pendekatan jendela geser dengan berbagai skala , pada gambar kueri untuk mengisolasi wilayah yang diinginkan.

Di sini, kita tidak akan menggunakan teknik pemrosesan gambar seperti pemfilteran, segmentasi warna, dll. Pustaka gambar scikit digunakan untuk membaca, memotong, menskalakan, mengubah gambar menjadi skala abu-abu dan mengekstrak vektor babi.

Membangun set data tangan / bukan tangan:

Kumpulan data dapat dibuat menggunakan strategi apa pun yang Anda suka. Salah satu cara untuk melakukan ini, adalah dengan membuat koordinat acak dan kemudian memeriksa rasio area persimpangan ke area persatuan (yaitu, tingkat tumpang tindih dengan kotak pembatas yang diberikan) untuk menentukan apakah itu bagian non-tangan. (Pendekatan lain dapat menggunakan jendela geser untuk menentukan koordinat. Tapi ini sangat lambat dan tidak perlu)

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

Melatih pengklasifikasi biner:

Setelah kumpulan data siap, melatih pengklasifikasi dapat dilakukan persis seperti yang terlihat sebelumnya di bagian 1.

Biasanya, dalam kasus ini, teknik yang disebut Hard Negative Mining digunakan untuk mengurangi jumlah deteksi positif palsu dan meningkatkan pengklasifikasi. Satu atau dua iterasi dari hard negative mining menggunakan Random Forest Classifier, cukup untuk memastikan bahwa pengklasifikasi Anda mencapai akurasi klasifikasi yang dapat diterima, yang dalam hal ini adalah di atas 80%.

Lihat kode di sini untuk contoh implementasi yang sama.

Mendeteksi tangan dalam gambar uji:

Sekarang, untuk benar-benar menggunakan pengklasifikasi di atas, kami menskalakan gambar uji dengan berbagai faktor dan kemudian menggunakan pendekatan jendela geser pada semuanya untuk memilih jendela yang menangkap wilayah yang diinginkan dengan sempurna. Ini dilakukan dengan memilih wilayah yang sesuai dengan nilai keyakinan maksimum yang dialokasikan oleh pengklasifikasi biner (tangan / bukan tangan) di semua skala.

Gambar uji perlu diskalakan karena, kami menjalankan jendela ukuran yang ditetapkan (dalam kasus kami, 128x128) di semua gambar untuk memilih wilayah yang diinginkan dan ada kemungkinan bahwa wilayah yang diinginkan tidak cocok dengan ukuran jendela ini .

Implementasi sampel dan deteksi keseluruhan di semua skala.

Menyatukan semuanya

Setelah kedua bagian selesai, yang harus dilakukan adalah memanggilnya secara berurutan untuk mendapatkan hasil akhir saat diberikan gambar uji.

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!