Condividi:

Condividi su facebook
Condividi su twitter
Condividi su linkedin
Condividi su whatsapp
Condividi su telegram

Il tutto è iniziato da una domanda che mi sono posto: “potrei aiutare le persone sorde a comunicare anche con chi non conosce il linguaggio dei segni?”

Partiamo da un presupposto: non sono un esperto del settore, ma la mia voglia di apprendere e cimentarmi in nuove avventure è davvero tanta.

Inoltre, non avendo esperienza professionale pregressa ho deciso da un po’ di tempo di costruirmi un portfolio che possa rispecchiare le mie abilità.

Così ho deciso di fare un progetto sul linguaggio dei segni.

La prima versione di questo progetto è stata fatta sull’alfabeto della lingua dei segni, ma solo una volta realizzato mi son detto:

“Le persone non posso comunicare tra di loro se devono gesticolare lettera per lettera ogni parola.”, una sola conversazione durerebbe ore.

Pensaci un po’.

Pensa se per dire un semplice “Ciao” dovresti comunicarlo lettera per lettera “C-i-a-o”.

Sarebbe una catastrofe!

Ed è così che ho deciso: “Antonio qui dobbiamo costruire un algoritmo che identifichi le parole”.

E così è stato.

La mia ricerca

Mi sono subito messo alla ricerca di un dataset del linguaggio dei segni, purtroppo però senza risultati.

Ogni dataset sul linguaggio dei segni che trovavo, era sull’alfabeto.

Niente di più!

Per questo dopo un bel po’ di ore di ricerca stavo incominciando a demoralizzarmi, non trovavo niente.

E’ stato così che ho preso una decisione.

Avrei fatto una cosa che prima ad ora non avevo mai fatto (alla fine era pur giunto il momento):

Avrei costruito un dataset tutto mio!


Non conoscendo il linguaggio dei segni, la prima cosa è stata fare una ricerca esplorativa su Google.

Ti spiego.

Come potrai immaginare, anche il linguaggio dei segni ha tante parole che bisogna interpretate con simboli diversi tra di loro.

Da solo non avrei potuto creare un dataset per le migliaia e migliaia di parole. Così ho deciso di costruire il mio dataset solo sulle parole che ritenevo più comuni nel linguaggio dei segni.

Dopodiché ho iniziato a pensare ad un piano d’azione. Un processo che dovevo seguire segno per segno.

Processo di costruzione

Prima di procedere quello ho fatto è stato individuare i passaggi che dovevo compiere fino al rilevamento del linguaggio dei segni.

Pertanto avevo stilato una scaletta da seguire e visto che ci sono la utilizzerò anche per il resto di questo articolo, spiegandoti quello che ho fatto:

  1. Decidere quali parole tradurre nel linguaggio dei segni
  2. Catturare le immagini per ogni segno
  3. Etichettare tutte le immagini raccolte
  4. Addestrare il mio modello con una rete pre-addestrata.
  5. Riconoscere i segni con la webcam

Se sei pronto, partiamo!

1. Decidere quali parole tradurre nel linguaggio dei segni

Come ti ho anticipato prima, il linguaggio dei segni è un linguaggio che conta molte parole.

Avendo risorse limitate non potevo creare un dataset con tutte le parole che esistono nella lingua dei segni. Per questo motivo ho deciso che avrei scelto solo 6 parole da far riconoscere al mio algoritmo.

E’ vero, così non sarei riuscito mai a mettere in piedi una vera e propria applicazione per aiutare le persone a comunicare meglio tra di loro. Ma l’obiettivo era ed è un altro.

Con questo progetto oltre a mettermi in gioco ed esercitare le mie skills in ambito Computer Vision, voglio ispirare altre persone a fare progetti di questo tipo. Progetti con lo scopo di aiutare le persone in difficoltà.

Progetti “inclusive” per così dire.

Ma tornando a noi, quali segni ho scelto?

Ho deciso di utilizzare i segni che mi sembravano più comuni. Ecco quali:

  • Hello
  • Thank you
  • I love you
  • Please
  • Yes
  • No

Una volta fatto ciò potevo passare allo step successivo:

2. Catturare le immagini per ogni segno

Ok, dopo che avevo deciso quali parole utilizzare dovevo passare allo step successivo.

Catturare le immagini che mi sarebbero servite per costruire il mio dataset!

Prima di farlo però, mi serviva emulare quelle parole scelte, nel linguaggio dei segni.

Eccoli qua:

linguaggio dei segni

Dopo aver appreso come si facessero i segni scelti, ho iniziato a catturare le immagini dalla fotocamera del cellulare trasferendo poi le stesse immagini sul PC.

Se sei esperto nel settore magari ti starai chiedendo perché non l’ho fatto dalla webcam del PC e con uno script Python, giusto?

Beh la risposta è alquanto semplice.

Volevo catturare immagini di alta qualità (dato che la mia webcam non è delle migliori) così che anche gli stessi dati che davo in pasto all’algoritmo sarebbero stati buoni.

Perciò, dopo aver catturato 30 immagini per ogni segno, dovevo etichettarle.

3. Etichettare le immagini

Qui devo confessare che mi sono trovato in difficoltà.

Questo tipo di lavoro non lo avevo mai fatto fino ad ora, ma non mi sono demoralizzato. Infatti, dopo qualche ricerca in rete ho trovato due tipi di strumenti per etichettare gli oggetti presenti nelle immagini.

  • Il primo tool è il classico labelImg che richiede l’installazione sul PC e il suo avvio tramite comando (vedi la repository ufficiale per seguire il processo di installazione).
  • Il secondo tool, invece, è makesense.ai. Uno strumento del tutto online che non richiede registrazione e con cui puoi etichettare le immagini molto facilmente. La sua pecca è che essendo online se per sbaglio chiudi la finestra o perdi la connessione, perderai anche i tuoi progressi.

Per semplificare il lavoro e non fare troppe installazioni ho deciso di utilizzare la seconda opzione che ho sopracitato. Questo perché oltre alla sua semplicità il mio dataset non era grandissimo.

Una volta finito di etichettare tutte le immagini ho scaricato tutti i file .xml che mi servivano e gli ho spostati nella cartella dove avevo raccolto le immagini originali.

4. Addestrare il modello per il linguaggio dei segni

Ecco la parte più interessante: La fase di addestramento del modello.

In questo caso per ottenere dei buoni risultati, ho deciso di utilizzare un algoritmo pre-addestrato. Anche perché le immagini raccolte erano poche.

Ecco cosa ho fatto.

Per prima cosa ho importato tutte le librerie necessarie per fare quello che dovevo fare.

import os import cv2 import numpy as np from sklearn.feature_extraction import image from tensorflow.keras import utils from tensorflow.keras.optimizers import Adam from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Flatten, Conv2D, MaxPool2D, BatchNormalization from tensorflow.keras.applications import VGG19 from sklearn.model_selection import train_test_split from tensorflow.keras.utils import to_categorical from tensorflow.keras.preprocessing.image import ImageDataGenerator import xml.etree.ElementTree as ET import h5py
Code language: Python (python)

Successivamente dopo aver importato le librerie, sono partito con il creare le variabili.

La prima mi serviva per definire il percorso della cartella sulla quale stavo lavorando, la seconda per indicare dove si trovavano le immagini e la terza per indicare la dimensione dell’immagine che si adattasse al modello scelto per l’addestramento; infine con l’ultima ho creato un dizionario con il nome delle labels e i rispettivi ID.

BASE_DIR = '../6 Language/' IMAGE_DIR = BASE_DIR + 'images' IMAGE_SIZE = 224 label = {'Hello': 0, 'Yes': 1, 'No': 2, 'Thank you': 3, 'I love you': 4, 'Please': 5}
Code language: Python (python)

Il passo successivo è stato quello di definire una funzione per far caricare e leggere le immagini al computer.

La funzione serviva per distingue i file contenti le labels da quelli che contenevano le immagini. Posizionandoli così in due liste che ho chiamato “labels” e “images”.

Liste che la funzione mi avrebbe restituito.

def load_data(path): images = [] labels = [] for filename in os.listdir(path): if filename.endswith('.png'): img = cv2.imread(os.path.join(path, filename)) img = cv2.resize(img, (IMAGE_SIZE, IMAGE_SIZE)) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) images.append(img) label_file = os.path.join(path, filename[:-4] + '.xml') tree = ET.parse(label_file) root = tree.getroot() label_text = root.find('object').find('name').text labels.append(label[label_text]) return images, labels
Code language: Python (python)

Una volta fatto questo ho dovuto richiamare la funzione per trasformare le mie liste in array e convertire le “labels” in categoriche.

images, labels = load_data(IMAGE_DIR) images = np.array(images) labels = np.array(labels) labels = to_categorical(labels)
Code language: Python (python)

ImageDataGenerator

Cosa mi avrebbe potuto avvantaggiare?

L’ImageDataGenerator. Questo mi avrebbe fatto ricavare più immagini dal dataset che avevo costruito.

Così non ho perso tempo e dalle immagini catturate in precedenza ho generato altre immagini che sono state divise in immagini per il mio training set e immagini per il mio test set.

#using image augmentation and generate more data datagen = ImageDataGenerator( rotation_range=2, shear_range=0.2, zoom_range=0.1, fill_mode='nearest') TRAIN_AUG_DIR = BASE_DIR +'train' TEST_AUG_DIR = BASE_DIR +'test' train_gen = datagen.flow(images, labels, batch_size=32, save_to_dir=TRAIN_AUG_DIR, save_prefix='train', save_format='png') test_gen = datagen.flow(images, labels, batch_size=32, save_to_dir=TEST_AUG_DIR, save_prefix='test', save_format='png')
Code language: Python (python)

Parte finale: definizione e allenamento del modello VGG19

Come hai potuto leggere prima, ho deciso per questo progetto, di utilizzare una rete pre-addestrata.

La mia scelta è ricaduta sul VGG19 perché anche se è un algoritmo non recente, lo ritengo adatto per il tipo di riconoscimento che dovevo fare.

Prima di passare alla fase di allenamento ho definito i pesi e dato al modello l’input delle immagini, aggiungendo infine altri 3 strati con le relative funzioni di attivazione.

Fatto ciò ho dato il via all’allenamento e alla valutazione del modello.

#define model vgg = VGG19(weights='imagenet', include_top=False, input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3)) vgg.trainable = False model = Sequential() model.add(vgg) model.add(Flatten()) model.add(Dense(256, activation='relu')) model.add(Dense(6, activation='softmax')) #model.summary() model.compile(loss='categorical_crossentropy', optimizer=Adam(lr=0.001), metrics=['accuracy']) model.fit(train_gen, steps_per_epoch=len(images) / 32, epochs=8, validation_data=test_gen, validation_steps=len(images) / 32) model.save('7lang') #evaluate model scores = model.evaluate(images, labels) print("\n%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))
Code language: Python (python)

5. Rilevamento del linguaggio dei segni con OpenCV

In seguito aver verificato di avere delle buone metriche, mi mancava solo un ultimo step.

Rilevare le parole che avevo scelto tramite la webcam del mio PC.

Una volta aver scaricato il modello salvato:

model.save('7lang')
Code language: Python (python)

potevo aprire un nuovo file e scrivere l’ultima parte che mi serviva per finire questo progetto.

Grazie a qualche riga sono riuscito a utilizzare la webcam per predire le parole del linguaggio dei segni scelto.

Nel file che ho deciso di chiamare detection.py ho utilizzato mediapipe per rintracciare la posizione delle mie mani e successivamente fare su di esse la predizione e mostrare la label rispettiva.

Conclusioni

Questo modello può essere migliorato, non solo a livello di immagini e quindi di numero di parole rilevate, ma anche a livello di precisione.

Come ti ho detto prima ho fatto questo progetto per ispirare e coinvolgere più persone possibili in questo tipo di progetti “inclusive”.

Spero che questo ti abbia ispirato e inoltre, se desideri conoscere il codice che ho utilizzato nell’altro file, non esitare a contattarmi a questa mail :D.

Alla prossima,

Antonio.

Condividi su facebook
Condividi su twitter
Condividi su linkedin
Condividi su whatsapp
Condividi su telegram
Antonio Furioso

Antonio Furioso

Fondatore di Neuragate. Credo molto in quello che le immagini possono comunicare, per questo sono fortemente attratto dalla Computer Vision. Mi piace tutto quello che è nuovo. La curiosità è quella che mi spinge oltre le aspettative e a fare sempre di più.

Iscriviti
Notificami
guest
0 Commenti
Inline Feedback
Vedi tutti i commenti