Tutorial > Caso di studio: Computer Vision in Python

Caso di studio: Computer Vision in Python

Pubblicato il: 06 giugno 2021

Computer Vision Python

Comprensione visiva del mondo

La Computer Vision è la parte di Intelligenza Artificiale che riguarda i dati visivi. Con l’avvento dei modelli di machine e deep learning, i sistemi odierni possono processare immagini o video digitali per studiarne e identificarne le caratteristiche. La Computer Vision è un concetto introdotto già nel 1950, quando furono usate alcune reti neurali per distinguere i contorni degli oggetti in maniera simile a quanto visto nell’Edge Detection del capitolo 11 della serie. Questo concetto si è poi evoluto al riconoscimento del testo scritto.

Esistono svariati casi d’uso che giustificano l’uso della Computer Vision nell’industria odierna. Alcuni usi molto basici si vedono, ad esempio, online, dove una webcam può leggere le espressioni dell’utente per interpretarne lo stato d’animo. Ciò è utile anche per testare, ad esempio, la tenuta emotiva di piloti e autisti da corsa. Oggi molti robot, inclusi gli assistenti vocali come Alexa e Siri, sono in grado di imitare il comportamento umano e rispondere in modo abbastanza emozionale.

Scienze Cognitive e Sentiment Analysis

Oggi l’Intelligenza Artificiale ha raggiunto livelli che fino a pochi anni fa erano impensabili. I software e i sistemi che imitano il comportamento, le reazioni e le risposte umane ora raggiungono elevati livelli di accuratezza. Prima di continuare con l’implementazione di altre tecniche di Computer Vision, andiamo ad apprendere alcuni concetti di scienza cognitiva e di analisi del sentimento.

Sentiment Analysis

L’analisi dei sentimenti umani, anche nota come Mining of Opinions o Emotion AI a seconda delle circostanze, è lo studio dei diversi stati d’animo del cervello umano. I fattori che rendono possibile l’analisi del sentiment sono sicuramente il Natural Language Processing (NLP), la linguistica computazionale, il text mining e l’analisi delle biometriche. Abbiamo già implementato l’NLP e lo Speech Processing, quindi in questo capitolo ci concentriamo su un ramo particolare della linguistica computazionale, le espressioni facciali.

Il compito base di qualsiasi programma di sentiment analysis è di isolare la polarità dell’input, che può essere un testo, un discorso, un’espressione facciale o altro, al fine di capire se il sentimento prevalente è positivo, negativo o neutro. Sulla base di questa analisi iniziale, i programmi solitamente vanno anche più a fondo per riconoscere il tipo di emozione, come felicità, disgusto, rabbia, paura o sorpresa. Esistono due fasi preliminari di questa analisi. La prima è la quantificazione dei dati di input che gli algoritmi devono leggere ed elaborare, la seconda è la ricerca psicologica che aiuta a identificare a quale espressione è associata una certa emozione.

Il diagramma rappresenta il flusso di un algoritmo di sentiment analysis, in sequenza: dati di input, isolamento degli aspetti chiave, comparazione con ricerche psicologiche, output (emozione).

Tutti gli algoritmi di sentiment analysis prendono spunto dal flusso di lavoro mostrato nell’immagine. Andiamo ora a vedere come le immagini e i dati visivi aiutano l’analisi del sentiment, studiando la scienza cognitiva e le sue applicazioni nell’ambito della Sentiment Analysis.

Scienza cognitiva

In termini di sistemi informatici, la scienza cognitiva è lo studio dei processi scientifici che si verificano nel cervello umano. È responsabile dell'esame delle funzioni cognitive, cioè la percezione dei pensieri, le lingue, la memoria, il ragionamento e l'elaborazione delle informazioni. Da un punto di vista più astratto, è lo studio dell'intelligenza e del comportamento.

Il diagramma rappresenta le componenti della scienza cognitiva, ovvero lo studio di: sentimenti, filosofia, linguistica, antropologia, neuroscienza.

L’obiettivo della scienza cognitiva è studiare il cervello umano e capire i principi alla base dell’intelligenza. Tale studio serve nella speranza di costruire, da questa conoscenza dell’intelligenza umana, sistemi automatici, macchine capaci di imitare i meccanismi di apprendimento e di sviluppare modelli di comportamento intelligenti come gli umani. La scienza cognitiva opera in tre diversi livelli di analisi:

  1. La teoria computazionale: in questo livello vengono specificati gli obiettivi delle analisi al sistema informatico. Tali obiettivi potrebbero essere ad esempio l’imitazione del parlato o la comprensione delle emozioni.
  2. Rappresentazione e algoritmi: sarebbe la fase di training dell’algoritmo di machine learning, in cui vengono presentati alla macchina gli scenari ideali di input e di output e vengono messi in atto algoritmi che alla fine saranno responsabili della trasformazione dell'input in output.
  3. Implementazione hardware: questa è la fase cognitiva finale. È la messa in atto dell'algoritmo nel mondo reale e l'analisi della sua traiettoria di lavoro.

Proseguiamo con questi concetti nello studio delle librerie e i metodi che aiuteranno a eseguire la sentiment analysis utilizzando le espressioni facciali.

Analisi delle espressioni facciali per la Sentiment Analysis

Si sente dire spesso che i sentimenti del nostro cuore si riflettano nel viso. Le espressioni facciali sono una modalità di comunicazione fondamentale sia per gli esseri umani e che per gli animali. Il comportamento umano e i tratti psicologici sono tutti facilmente analizzabili con le espressioni facciali e quest’analisi si usa ampiamente anche nei trattamenti e nelle terapie mediche.

In questa sezione lavoreremo su ritratti e immagini di espressioni facciali per interpretare il sentimento presente nell'immagine. Nella parte successiva, eseguiremo gli stessi passaggi su un video.

Face Emotion Recognizer

Il Face Emotion Recognizer, noto anche come FER, è una libreria open–source di Python implementata e mantenuta da Justin Shenk che viene usata per la sentiment analysis di video e immagini. Il progetto è stato sviluppato su una versione che fa uso di una rete neurale convoluzionale i cui pesi sono disponibili nel file HDF5 del source code della libreria su Github (qui scopriamo anche come eseguire il FER). Questa cosa può essere tralasciata utilizzando il costruttore FER quando si invoca il modello.

  • mtcnn: è uno dei parametri del costruttore e specifica la tecnica di riconoscimento facciale usata. Se è settato a True per riconoscere i volti viene usato il modello MTCNN (multi cascade convolutional network), mentre se settato a False viene usato il classificatore di default Haarcascade di OpenCV.
  • detect_emotions(): è la funzione usata per classificare le emozioni in sei categorie: fear, neutral, happy, sad, anger, e disgust. Viene assegnata una probabilità a ogni emozione in una scala da 0 a 1.

Il programma inizia prendendo in input l'immagine o il video da analizzare. Si inzializza il costruttore FER() assegnandogli un classificatore per la Face Detection (Open CV Haarcascade o MTCNN). Viene quindi invocata la funzione di rilevamento delle emozioni del costruttore, passando in input l'oggetto (immagine o video). Il risultato ottenuto sarà una serie di emozioni, ciascuna con un valore assegnato. Infine, la funzione top_emotion può isolare e restituire l'emozione con probabilità più alta.

Le dipendenze per installare FER sono:

  • OpenCV versione 3.2 o superiore;
  • TensorFlow versione 1.7 o superiore;
  • Python 3.6.

Vediamo come implementare l’algoritmo FER per le immagini.


# Installiamo la libreria FER per il riconoscimento facciale
# L’installer si occuperà di scaricare le dipendenze qualora non siano già presenti
pip install fer

>>> 

Downloading fer–20.1.3–py3–none–any.whl (810 kB)
Collecting keras
  Downloading Keras–2.4.3–py2.py3–none–any.whl (36 kB)
Collecting opencv–contrib–python
  Downloading opencv_contrib_python–4.5.1.48–cp38–cp38–win_amd64.whl (41.2 MB)
Requirement already satisfied: matplotlib in d:\users\anaconda\lib\site–packages (from fer) (3.3.2)
Collecting mtcnn>=0.1.0
  Downloading mtcnn–0.1.0–py3–none–any.whl (2.3 MB)
Collecting tensorflow~=2.0
  Downloading tensorflow–2.4.1–cp38–cp38–win_amd64.whl (370.7 MB)

from fer import FER
import matplotlib.pyplot as plt 
%matplotlib inline
# Leggiamo l’immagine dalla directory di lavoro
test_image_one = plt.imread("Image–One.jpeg")
# Creiamo un oggetto di classe FER() con mtcnn
emo_detector = FER(mtcnn=True)
# Andiamo a catturare le emozioni presenti nell’immagine
captured_emotions = emo_detector.detect_emotions(test_image_one)
# Stampiamo le emozioni coi loro valori
print(captured_emotions)
plt.imshow(test_image_one)

>>> [{'box': (94, 47, 293, 293), 'emotions': {'angry': 0.01, 'disgust': 0.0, 'fear': 0.0, 'happy': 0.01, 'sad': 0.01, 'surprise': 0.0, 'neutral': 0.97}}]
>>> <matplotlib.image.AxesImage at 0x13c1c5704c0>
>>> 
Un'immagine di test. Un ragazzo che ha un'espressione neutra.

# Usiamo la funzione top_emotion() per ottenere l’emozione predominante dell’immagine
dominant_emotion, emotion_score = emo_detector.top_emotion(test_image_one)
print(dominant_emotion, emotion_score)

>>> neutral 0.97

# Ripetiamo gli spessi passaggi per altre immagini per confermare le prestazioni di FER()
test_image_two = plt.imread("Image–Two.jpg")
captured_emotions_two = emo_detector.detect_emotions(test_image_two)
print(captured_emotions_two)
plt.imshow(test_image_two)
dominant_emotion_two, emotion_score_two = emo_detector.top_emotion(test_image_two)
print(dominant_emotion_two, emotion_score_two)

>>> [{'box': (30, 48, 110, 110), 'emotions': {'angry': 0.0, 'disgust': 0.0, 'fear': 0.0, 'happy': 0.98, 'sad': 0.0, 'surprise': 0.0, 'neutral': 0.01}}]
>>> happy 0.98
>>>  

Un'immagine di test. Un ragazzo che ha un'espressione felice.

# Terzo test
test_image_three = plt.imread("Image–Three.jpg")
captured_emotions_three = emo_detector.detect_emotions(test_image_three)
print(captured_emotions_three)
plt.imshow(test_image_three)
dominant_emotion_three, emotion_score_three = emo_detector.top_emotion(test_image_three)
print(dominant_emotion_three, emotion_score_three)

>>> [{'box': (155, 193, 675, 675), 'emotions': {'angry': 0.01, 'disgust': 0.0, 'fear': 0.0, 'happy': 0.46, 'sad': 0.02, 'surprise': 0.0, 'neutral': 0.51}}]
>>> neutral 0.51
>>> 

Un'immagine di test. Un ragazzo che ha un'espressione vagamente felice.

# Quarto test
test_image_four = plt.imread("Image–Four.jpg")
captured_emotions_four = emo_detector.detect_emotions(test_image_four)
print(captured_emotions_four)
plt.imshow(test_image_four)
dominant_emotion_four, emotion_score_four = emo_detector.top_emotion(test_image_four)
print(dominant_emotion_four, emotion_score_four)

>>> [{'box': (150, 75, 236, 236), 'emotions': {'angry': 0.84, 'disgust': 0.0, 'fear': 0.1, 'happy': 0.0, 'sad': 0.02, 'surprise': 0.01, 'neutral': 0.03}}]
>>> angry 0.84
>>>  

Un'immagine di test. Una bambina che ha un'espressione arrabbiata.

Abbiamo osservato come si possono analizzare immagini per estrarre le espressioni e gli stati emotivi dei soggetti inquadrati. Nella prossima parte effettueremo la stessa analisi anche sui video.

Rilevare le Emozioni dai video

In questa sezione lavoreremo sui video in maniera simile a quanto fatto per estrarre il sentiment dalle immagini. In teoria un video è una combinazione continua di immagini in movimento, dette frame. In sostanza quindi il funzionamento di un algoritmo è lo stesso sia per i video che per le immagini, l’unico passaggio aggiuntivo nell’elaborazione dei video è la suddivisione del video nei suoi singoli frame e l’applicazione degli algoritmi di Image Processing su tutti questi frame.

Sebbene l’algoritmo alla base sia lo stesso sia per le immagini che per i video, ci sono alcune modifiche importanti da aggiungere quando lavoriamo coi video.

  1. La funzione analyze() è responsabile dell’estrarre i frame da un video per analizzarli separatamente.
  2. Ogni frame analizzato dalla funzione viene memorizzato in un’immagine separata nella directory corrente. Inoltre, alla fine la funzione crea una copia del video originale applicando un box intorno ai volti e mostrando in diretta le emozioni nel video.
  3. Possiamo quindi creare un Pandas DataFrame per memorizzare i valori analizzati e visualizzare graficamente il dataframe con matplotlib. Nel grafico potremo vedere tutte le emozioni rilevate sull’asse temporale.
  4. Infine possiamo analizzare il dataframe prendendo i valori delle singole emozioni riconosciute dal modello e trovare il sentiment predominante dell’intero video.

In questo modo, siamo in grado di lavorare sui video estraendo e analizzando le singole immagini frame. Questo processo si può vedere anche nel diagramma seguente, che mostra il passaggio aggiuntivo nell'elaborazione dei video. Vedremo l’implementazione nella prossima sezione di codice.

Il diagramma rappresenta il processo di suddivisione di un video. Dato un input, il video viene suddiviso in un numero indefinito N di frames, un algoritmo lavora le immaginie viene prodotto un output.

# Effettuiamo l’analisi delle espressioni facciali anche sui video
# Importiamo i moduli necessari di FER per l’elaborazione di video
from fer import Video
from fer import FER
import os
import sys
import pandas as pd
# Definiamo il path del video
location_videofile = "/ Video_One.mp4"

# Creiamo il Face Detector
face_detector = FER(mtcnn=True)
# Diamo in input il video per l’elaborazione
input_video = Video(location_videofile)

# La funzione analyze() eseguirà l’analisi di tutti i frame del video in input
# Creerà un box rettangolare intorno a ogni immagine e mostrerà a fianco i valori delle emozioni
# Infine pubblicherà un nuovo video avente un box intorno al volto del soggetto con i valori live delle emozioni
processing_data = input_video.analyze(face_detector, display=False)

>>> 
Starting to Zip
Compressing: 8%
Compressing: 17%
Compressing: 25%
Compressing: 34%
Compressing: 42%
Compressing: 51%
Compressing: 60%
Compressing: 68%
Compressing: 77%
Compressing: 85%
Compressing: 94%
Zip has finished

# Convertiamo le informazioni ottenute in un dataframe
# Questo ci aiuterà a esportare i dati in un file .csv per eventuali analisi successive
vid_df = video.to_pandas(processing_data)
vid_df = video.get_first_face(vid_df)
vid_df = video.get_emotions(vid_df)

# Visualizziamo graficamente le emozioni del video nel tempo
pltfig = vid_df.plot(figsize=(20, 8), fontsize=16).get_figure()

>>> 

Il grafico rappresenta le emozioni del primo video di esempio (quantificate in termini di probabilità sull'asse verticale) nel tempo (asse orizzontale). Le curve corrispondono ai valori 'arrabbiato', 'disgustato', 'impaurito', 'felice', 'trieste', 'sorpreso' e 'neutrale'. Si può osservare come nel mezzo del video la curva predominante sia quella del valore  'felice'. È il risultato del blocco codice di esempio.


# Lavoriamo col dataframe per estrarre l’emozione predominante del video
angry = sum(vid_df.angry)
disgust = sum(vid_df.disgust)
fear = sum(vid_df.fear)
happy = sum(vid_df.happy)
sad = sum(vid_df.sad)
surprise = sum(vid_df.surprise)
neutral = sum(vid_df.neutral)

emotions = ['Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral']
emotions_values = [angry, disgust, fear, happy, sad, surprise, neutral]

score_comparisons = pd.DataFrame(emotions, columns = ['Human Emotions'])
score_comparisons['Emotion Value from the Video'] = emotions_values
score_comparisons

>>> 

	Human Emotions	     Emotion Value from the Video
0	Angry	                      76.51
1	Disgust	                      0.02
2	Fear	                      154.88
3	Happy	                      162.85
4	Sad	                      91.33
5	Surprise	                    28.19
6	Neutral	                    68.25

# Terminiamo il progetto sperimentando il codice su un ultimo video
location_videofile_two = " /Video_Two.mp4"
input_video_two = Video(location_videofile_two)
processing_data_two = input_video_two.analyze(face_detector, display=False)

vid_df_2 = input_video_two.to_pandas(processing_data_two)
vid_df_2 = input_video_two.get_first_face(vid_df_2)
vid_df_2 = input_video_two.get_emotions(vid_df_2)

pltfig = vid_df_2.plot(figsize=(20, 8), fontsize=16).get_figure()

>>> 

Il grafico rappresenta le emozioni del secondo video di esempio (quantificate in termini di probabilità sull'asse verticale) nel tempo (asse orizzontale). Le curve corrispondono ai valori 'arrabbiato', 'disgustato', 'impaurito', 'felice', 'trieste', 'sorpreso' e 'neutrale'. Si può osservare come all'inizio del video la curva predominante sia quella del valore  'felice'. È il risultato del blocco codice di esempio.
 

angry_2 = sum(vid_df_2.angry)
disgust_2 = sum(vid_df_2.disgust)
fear_2 = sum(vid_df_2.fear)
happy_2 = sum(vid_df_2.happy)
sad_2 = sum(vid_df_2.sad)
surprise_2 = sum(vid_df_2.surprise)
neutral_2 = sum(vid_df_2.neutral)

emotions_values_2 = [angry_2, disgust_2, fear_2, happy_2, sad_2, surprise_2, neutral_2]
score_comparisons = pd.DataFrame(emotions, columns = ['Human Emotions'])
score_comparisons['Emotion Value from the Video'] = emotions_values_2
score_comparisons

>>> 

	Human Emotions	       Emotion Value from the Video
0	Angry	                       21.02
1	Disgust	                       0.00
2	Fear	                       32.47
3	Happy	                       137.04
4	Sad	                       77.69
5	Surprise	                       13.09
6	Neutral	                       176.34

# Vediamo un esempio di come appare una porzione del video finale analizzato
# Tutte queste immagini vengono zippate nella directory “output” dell’ambiente di lavoro
>>>   

Il volto di una donna con un'espressione sorridente. Il volto è inquadrato da un rettangolo con i bordi color ocra. In sovrimpressione sono stampati i valori di probabilità dell'analisi. Un valore di 0.98 per la categoria 'felice' indica che l'analisi è riuscita. È il risultato del blocco codice di esempio.

Con questo possiamo concludere la nostra analisi di immagini e video per l’Emotion Recognition. Siamo stati in grado di lavorare con successo con volti umani e riconoscere i sentimenti presenti nelle espressioni facciali.

Riassunto del progetto e conclusioni

La Sentiment Analysis e la Face Detection singolarmente si applicano a numerosissimi casi d'uso nel mondo di oggi. Ad esempio, esistono algoritmi di object detection nei parcheggi pubblici, nei sistemi di monitoraggio del traffico e in altro ancora, che acquisiscono immagini delle persone alla guida dei veicoli per tenerne traccia. La Sentiment Analysis viene usata ad esempio nelle terapie in cui terapeuta e paziente non possono incontrarsi di persona. Lo studio del pensiero umano è stato di aiuto anche nello sviluppo di alcuni farmaci. Sul fronte tecnologico, gli assistenti virtuali, gli assistenti di profiling e i robot automatizzati vengono realizzati per imitare le azioni degli umani e sostituirli in compiti specifici, con la speranza di aumentare la precisione e ridurre gli errori.

Queste tecnologie sono quindi una parte molto importante del mondo pervaso di IA in cui viviamo oggi. Un approccio più avvincente e complicato alla Computer Vision consiste nell'usare algoritmi basati su cloud come i servizi di Azure o i modelli di deep learning, che non abbiamo trattato in questo corso, ma che potrebbero tornare utili per scenari più complessi. Attraverso il nostro studio degli ultimi due capitoli, abbiamo appreso:

  • la scienza cognitiva, cioè lo studio dei processi del pensiero umano che mira a riprodurre le stesse reazioni e emozioni umane nelle macchine mediante l’uso di algoritmi.
  • la Computer Vision, il ramo dell’intelligenza artificiale che implementa la scienza cognitiva nel monto reale applicandola a dati umani sotto forma di immagini e video.
  • l’Image Processing, cioè la parte di algoritmi di Computer Vision di supporto all’elaborazione e alla comprensione delle immagini che fa uso di matrici e vettori numerici per effettuare le operazioni necessarie.

In questo e nel precedente capitolo, abbiamo usato il potere dell'intelligenza artificiale per lavorare con la scienza cognitiva e trattare i volti umani. Questa tecnologia è generalmente nota come Computer Vision. Siamo stati in grado di estrapolare le emozioni da foto e video raffiguranti volti umani.