Rilevamento facciale e sorriso in tempo reale con OpenCV 4 e Raspberry Pi

Sperimentiamo con la libreria OpenCV 4 in un progetto di riconoscimento facciale e rilevamento del sorriso in tempo reale.

Nellโ€™articolo โ€œRealizzare un sistema di sorveglianza con Raspberry Pi e OpenCVโ€ abbiamo introdotto la libreria OpenCV 4 per Raspberry Pi, che rappresenta un potente strumento in grado di realizzare applicazioni in ambito di riconoscimento dโ€™immagine con il semplice ausilio di una telecamera specifica per Raspberry Pi.

Nella stessa occasione vi abbiamo spiegato come si installa la libreria OpenCV 4 per la piattaforma Raspbian e in che modo si puรฒ utilizzare una scheda Raspberry Pi per creare un semplice sistema di riconoscimento del movimento attraverso lโ€™analisi delle immagini riprese dalla specifica telecamera per la stessa board.

Adesso proseguiamo sullo stesso filone analizzando nuove funzionalitร  della libreria con lโ€™obiettivo di realizzare un sistema di riconoscimento facciale in grado di rilevare un volto, gli occhi e una bocca sorridente; il tutto in tempo reale.

Haar Cascades

Una tecnica utilizzata da OpenCV 4 per il rilevamento dei volti si basa sulle cosiddette Haar Cascades. In altre parole, sono classificazioni in cascata basate sullโ€™algoritmo di Haar, chiamate cosรฌ in onore al matematico ungherese Alfrรฉd Haar, famoso per i suoi studi a inizio 1900 e al quale รจ stata riconosciuta la wavelet di Haar.

Le Haar Cascades rappresentano un metodo di rilevamento ottico degli oggetti molto efficace, proposto da Paul Viola e Michael Jones nel loro articolo โ€œRapid Object Detection using a Boosted Cascade of Simple Featuresโ€ del 2001, che tradotto suona come โ€œRilevamento rapido degli oggetti usando cascate incrementate di caratteristiche sempliciโ€.

Si tratta di un approccio al machine learning basato su una funzione a cascata che viene โ€œaddestrataโ€ da caratteristiche semplici. Come spieghiamo a breve, la tecnica con wavelet di Haar crea dei riquadri in positivo e negativo da usare come filtri da sovrapporre in sequenza a unโ€™immagine, dalla cui interazione si estraggono le informazioni necessarie per capire dove si trovi una certa caratteristica dellโ€™oggetto, per esempio, un volto, gli occhi e la bocca (Fig. 1).

Fig. 1 Esempi di Haar Cascades.

 

Come si puรฒ vedere nella figura, i riquadri che si ottengono con la wavelet di Haar si suddividono in tre Features (termine traducibile come โ€œcaratteristicheโ€, ma lo lasceremo in inglese perchรฉ normalmente si utilizza tale termine gergale):

(a) Edge Features
(b) Line Features
(c) Four-rectangle Features
Queste Feature vengono applicate in cascade (cascata) e, inizialmente, lโ€™algoritmo richiede molte immagini di volti e immagini senza volti.

Questo รจ il metodo per โ€œaddestrareโ€ il cosiddetto classifier (classificatore). A questo scopo, vengono utilizzate le Features di Haar, la cui applicazione รจ visibile nella Fig. 2. รˆ facile intuire come lโ€™algoritmo di Haar, produca riquadri rettangolari bianchi e neri, tramite una matrice a onda quadra.

Fig. 2 Rilevamento di un volto usando le Features di Haar in cascata.

 

Si fa notare che le immagini da elaborare devono essere trasformate in una scala di grigi, se sono a colori. Questo per facilitare il calcolo con i riquadri bianchi e neri.

Successivamente, una volta trovata la caratteristica di un volto, degli occhi eccetera, si potrร  riutilizzare lโ€™immagine a colori.

Ogni Feature viene estratta da un singolo valore, ottenuto sottraendo la somma dei pixel sotto il rettangolo bianco dalla somma dei pixel sotto il rettangolo nero. I riquadri si muovono velocemente su tutta lโ€™immagine e vengono utilizzate tutte le dimensioni e le posizioni possibili del volto per calcolare le Feature.

Per una finestra di 24×24 pixel servono oltre 160.000 Features e per ogni calcolo di Feature, รจ necessario trovare la somma dei pixel sotto i rettangoli bianchi e neri.

Per risolvere questo problema e per quanto grande sia lโ€™immagine da elaborare, i calcoli per un dato pixel vengono ridotti a unโ€™operazione che coinvolge solo quattro pixel alla volta, rendendo il tutto molto veloce.

Di tutte queste Feature che vengono calcolate, la maggior parte รจ irrilevante. Per esempio, se osserviamo la Fig. 2, la linea in alto mostra due buone Feature. La prima Feature selezionata sembra concentrarsi sulla proprietร  che la regione degli occhi รจ spesso piรน scura della regione del naso e delle guance.

La seconda Feature si basa sulla proprietร  che gli occhi sono piรน scuri del naso. Ma le stesse finestre applicate sulle guance o su qualsiasi altro posto sono irrilevanti.

Quindi, per selezionare le migliori Feature fra 160.000 รจ stato realizzato un algoritmo Adaboost, con il quale viene trovata la soglia migliore per la classificazione dei volti. Per la cronaca, AdaBoost, abbreviazione di Adaptive Boosting, รจ un meta-algoritmo di apprendimento automatico, formulato per essere utilizzato nel machine learning.

Ovviamente, durante lโ€™operazione di estrazione delle Feature, ci saranno errori o errate classificazioni, per cui vengono selezionate le Feature con un tasso di errore minimo per rilevare piรน accuratamente le immagini di volti.

Il processo non รจ cosรฌ semplice: ad ogni immagine viene dato un peso uguale allโ€™inizio, dopo ogni classificazione vengono aumentati i pesi delle immagini errate, quindi viene eseguito lo stesso processo e vengono calcolati nuovi tassi di errore e nuovi pesi.

Il processo prosegue fino a quando viene raggiunta la precisione richiesta o il tasso di errore minimo. Il classificatore finale รจ una somma ponderata di questi classificatori โ€œdeboliโ€. Si chiamano deboli perchรฉ da soli non possono classificare lโ€™immagine, ma insieme ad altri formano un classificatore forte. Lโ€™esperienza fatta sul campo ci dice che anche 200 Feature forniscono il rilevamento con unโ€™accuratezza del 95%.

La configurazione finale avrร  circa 6.000 Feature e questa riduzione da 160.000 a 6.000 รจ un grande vantaggio. Come vedremo, tutti i parametri dei classificatori (classifier) sono salvati in file pronti allโ€™uso (file pre-addestrati).

Cascade of Classifiers

Nonostante la riduzione a circa 6.000 Feature, per ridurre il tempo per il rilevamento di un volto, รจ stato introdotto il concetto di Cascade of Classifiers (cascata di classificatori).

Di solito, in un fotogramma la maggior parte dellโ€™immagine non รจ una faccia, quindi il metodo migliore รจ quello di verificare se una regione della foto non รจ una faccia.

Se non lo รจ, questa regione viene scartata subito e non viene elaborata di nuovo, a tutto vantaggio dellโ€™ottimizzazione delle risorse e dei tempi di elaborazione. Invece, le regioni in cui puรฒ esserci una faccia vengono elaborate per controllare e analizzare le possibili aree del viso.

Per ottenere questo risultato il concetto di Cascade of Classifiers invece di applicare tutte le 6.000 Feature in una finestra, le raggruppa in diversi stadi di classificatori e quindi applicate una per una. Se una finestra fallisce il primo stadio, viene scartato e non vengono considerate le restanti Feature. Se invece passa, viene applicata la seconda fase delle Feature e il processo continua.

La finestra che passa tutte le fasi รจ una regione del viso.

Questa regione viene chiamata ROI (Region of Interest) e sarร  quella che verrร  presa in considerazione per una successiva analisi.

Haar-cascade di OpenCV 4

OpenCV รจ dotato di un allenatore e di un rilevatore. Se si vuole โ€œallenareโ€ il classificatore per identificare qualsiasi oggetto come auto, aerei ecc. si puรฒ usare OpenCV per crearne uno.

I dettagli completi non possiamo trattarli (per brevitร ) in questo articolo, ma sappiate che si trovano sul sito Internet ufficiale di OpenCV, alla pagina web Cascade Classifier Training.

In questa sede ci occuperemo solo del rilevamento. OpenCV 4 contiene giร  molti classificatori pre-addestrati per il riconoscimento di viso, occhi, sorrisi, corpi, targhe automobilistiche ecc. I relativi file XML sono disponibili nella cartella opencv/data/haarcascades (almeno, se avete eseguito lโ€™installazione di OpenCV in modo corretto).

 

Rilevamento di volto e occhi con OpenCV

Qui di seguito presentiamo un semplice listato in Python in grado di effettuare un rilevamento di volto e occhi da unโ€™immagine fissa.

Per prima cosa dobbiamo caricare i classificatori XML richiesti per il rilevamento del viso e degli occhi:

haarcascade_frontalface_default.xml
haarcascade_eye.xml

I piรน curiosi vorranno sapere che cosa contengono questi file XML. Giusto per dare unโ€™idea della struttura, affrermeremo che, oltre alla tipica struttura di un file XML, si possono distinguere i tag relativi alla finestra di 24×24 pixel e i tag dei weakClassifiers (classificatori deboli).

A seconda del tipo di rilevamento, ci sono quasi 3.000 tag chiamati internalNodes a cui sono abbinati altrettanti tag rects e circa 6.000 tag leafValues. I numeri si possono riferire a misure e coordinate dei rettangoli e ai valori di soglia degli stadi di classificazione (stageThreshold).

Il Listato 1 riporta un estratto dal file haarcascade_frontalface_default.xml.

Consigliamo di copiare i suddetti classificatori XML dalla cartella /home/pi/opencv/data/haarcascades in una nuova cartella; noi lโ€™abbiamo chiamata face_eye_detect. Allโ€™interno di questa cartella mettete anche unโ€™immagine jpg.

Per il nostro esempio abbiamo usato lโ€™immagine dellโ€™autore, contenuta nel file โ€œpier.jpgโ€.

Attenzione! Prima di iniziare a lavorare con Python, ricordatevi di attivare il profilo per lโ€™ambiente virtuale โ€œcvโ€ e di aprire lโ€™idle di Python con i comandi seguenti dal terminale, come illustrato in Fig. 3:

source ~/.profile
workon cv
python -m idlelib.idle

Per i dettagli vi rimandiamo allโ€™articolo โ€œHome automation con OpenCV 4โ€ pubblicato nel fascicolo nยฐ233 di Elettronica In.
Analizzando il listato in Python, per prima cosa, importiamo le librerie necessarie:

import sys
import os
import numpy as np
import cv2 as cv

Quindi, creiamo lโ€™oggetto face_cascade con i classificatori ottenuti dallโ€™importazione del primo file XML per il rilevamento della faccia.

Allo stesso modo, creiamo lโ€™oggetto eye_cascade con i classificatori ottenuti dallโ€™importazione del secondo file XML per il rilevamento degli occhi.

Quindi, carichiamo lโ€™immagine jpg da analizzare e la trasformiamo in scala di grigi con la funzione cv.COLOR_BGR2GRAY.

Lโ€™oggetto img conterrร  le informazioni dellโ€™immagine e lโ€™oggetto gray quelle dellโ€™immagine trasformata in scala di grigi.
Procediamo quindi con i comandi:

face_cascade = cv.CascadeClassifier(โ€˜haarcascade_frontalface_default.xmlโ€™)
eye_cascade = cv.CascadeClassifier(โ€˜haarcascade_eye.xmlโ€™)
img = cv.imread(โ€˜pier.jpgโ€™)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

 

A questo punto possiamo cercare il volto nellโ€™immagine tramite la funzione face_cascade.detectMultiScale(gray, 1.3, 5).

Il ciclo for cerca un volto allโ€™interno dellโ€™oggetto faces passando le coordinate x e y e le dimensioni di larghezza e di altezza w e h della Feature.

Se viene trovato un volto, la sua posizione sarร  evidenziata con un rettangolo blu, tramite la funzione cv.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2).

Una volta che otteniamo la posizione del viso, possiamo creare una cosiddetta ROI (Region of Interest) per il viso e applicare il rilevamento degli occhi su questa ROI, dal momento che gli occhi sono sempre sul viso.

Con lo stesso procedimento, una volta rilevati gli occhi, questi vengono evidenziati con due rettangoli verdi:

faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]

eyes = eye_cascade.detectMultiScale(roi_gray)
for (ex,ey,ew,eh) in eyes:
cv.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

Infine, viene creata una finestra con lโ€™istruzione cv.imshow(โ€˜imgโ€™,img) per visualizzare il risultato. La finestra โ€œimgโ€ contenente il risultato รจ visibile nella Fig. 4.
Una volta chiusa la finestra, il programma viene terminato:

cv.imshow(โ€˜imgโ€™,img)
cv.waitKey(0)
cv.destroyAllWindows()

Listato 1

<opencv_storage>
<cascade type_id=โ€opencv-cascade-classifierโ€><stageType>BOOST</stageType>
<featureType>HAAR</featureType>
<height>24</height>
<width>24</width>
<stageParams>
<maxWeakCount>211</maxWeakCount></stageParams>
<featureParams>
<maxCatCount>0</maxCatCount></featureParams>
<stageNum>25</stageNum>
<stages>
<_>
<maxWeakCount>9</maxWeakCount>
<stageThreshold>-5.0425500869750977e+00</stageThreshold>
<weakClassifiers>
<_>
<internalNodes>
0 -1 0 -3.1511999666690826e-02</internalNodes>
<leafValues>
2.0875380039215088e+00 -2.2172100543975830e+00</leafValues></_>
<rects>
<_>
16 2 3 20 -1.</_>
<_>
17 2 1 20 3.</_></rects></_>
โ€ฆ
โ€ฆ
โ€ฆ

 

Fig. 3 I comandi da terminale per attivare lโ€™ambiente virtuale e aprire lโ€™idle di Python.

 

Fig. 4 La finestra con il rilevamento del volto e degli occhi.

Rilevamento del sorriso con OpenCV 4

Adesso passiamo ad una semplice serie di istruzioni per ottenere il rilevamento del sorriso, effettuato analizzando un breve file video.
A questo scopo, serviranno i due classificatori:

haarcascade_frontalface_default.xml
haarcascade_smile.xml

Dopo aver caricato le librerie necessarie, vengono creati gli oggetti face_cascade e smile_cascade come spiegato prima. La funzione cv2.VideoCapture permette di caricare il filmato. Il nostro video demo si chiama โ€˜pier_smile.mp4โ€™ ed รจ quello di un volto dapprima serio e poi sorridente. La risoluzione di cattura del video รจ di 640×480 e il fattore di scala (sF) รจ di 1.05.

import cv2
import numpy as np
import sys

face_cascade = cv2.CascadeClassifier(โ€œhaarcascade_frontalface_default.xmlโ€)
smile_cascade = cv2.CascadeClassifier(โ€œhaarcascade_smile.xmlโ€)

cap = cv2.VideoCapture(โ€˜pier_smile.mp4โ€™)
cap.set(3,640)
cap.set(4,480)
sF = 1.05

Il ciclo while analizza tutti i frame del video, trasformandoli in immagini a scala di grigi, esattamente come nellโ€™esempio precedente. Vi facciamo notare che adesso lโ€™oggetto img รจ un frame catturato di volta in volta dalla funzione cap.read().

while (cap.isOpened()):
ret, frame = cap.read()
img = frame
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

La funzione face_cascade.detectMultiScale cercherร  nel video (meglio, in ogni frame) il voltoโ€ฆ

faces = face_cascade.detectMultiScale(
gray,
scaleFactor= sF,
minNeighbors=8,
minSize=(55, 55),
flags=cv2.CASCADE_SCALE_IMAGE
)

…e, una volta trovato, creerร  una regione di interesse attraverso le righe di codice:

for (x, y, w, h) in faces:
roi_gray = gray[y:y+h, x:x+w]
roi_color = frame[y:y+h, x:x+w]

La funzione smile_cascade.detectMultiScale cercherร  un sorriso allโ€™interno del volto…

smile = smile_cascade.detectMultiScale(
roi_gray,
scaleFactor= 1.7,
minNeighbors=22,
minSize=(25, 25),
flags=cv2.CASCADE_SCALE_IMAGE
)

…e una volta trovato, disegnerร  un rettangolo intorno al sorriso, mentre nella finestra di terminale verrร  stampato โ€œTrovato un sorrisoโ€.

for (x, y, w, h) in smile:
print(โ€œTrovato un sorriso!โ€)
cv2.rectangle(roi_color, (x, y), (x+w, y+h), (255, 0, 0), 1)

Nella finestra โ€œSmile Detectorโ€ si potrร  vedere il risultato (Fig. 5). Se si preme il tasto ESC il programma viene terminato.

cv2.imshow(โ€˜Smile Detectorโ€™, frame)
c = cv2.waitKey(7) % 0x100
if c == 27:
break
cap.release()
cv2.destroyAllWindows()

Fig. 5 Rilevamento del volto in tempo reale utilizzando una webcam USB.

 

Riconoscimento facciale in tempo reale

Il terzo esperimento per il rilevamento facciale prevede lโ€™uso di una normalissima webcam USB.

Come al solito, allโ€™inizio dello script si importano le librerie necessarie e il classificatore haarcascade_frontalface_default.xml.

Con la funzione cv2.VideoCapture(0) vista prima รจ possibile catturare direttamente il video di una webcam USB passando il parametro 0.

import cv2
import sys
cascade_path = โ€œhaarcascade_frontalface_default.xmlโ€
face_cascade = cv2.CascadeClassifier(cascade_path)
video_capture = cv2.VideoCapture(0)

Il ciclo while controlla che sia collegata una webcam e quindi esegue la cattura frame by frame. Come al solito tutti i frame vengono convertiti in scala di grigio.

while True:
if not video_capture.isOpened():
print(โ€˜Unable to load camera.โ€™)
pass
ret, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

La funzione face_cascade.detectMultiScale ricerca un volto nello streaming video (meglio ancora, in ogni frame) attraverso le istruzioni:

faces = face_cascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30)
)

…e disegna un rettangolo intorno al volto, quando viene trovato.

Tenete presente che con il parametro minSize=(30,30) รจ possibile rilevare volti anche molto piccoli o distanti dalla telecamera.

Per esempio, nella Fig. 6 potete vedere come venga catturata addirittura la foto della patente che il soggetto sta esibendo di fronte alla telecamera!

Le istruzioni che eseguono quanto spiegato sono le seguenti:

for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)

Il risultato รจ visibile in una finestra chiamata โ€œVideoโ€, grazie alle istruzioni:

cv2.imshow(โ€˜Videoโ€™, frame)
if cv2.waitKey(1) & 0xFF == ord(โ€˜qโ€™):
break
cv2.imshow(โ€˜Videoโ€™, frame)
video_capture.release()
cv2.destroyAllWindows()

Premendo insieme i tasti CTRL+Q si termina il programma.

Notate che gli script Python haar_1.py, haar_2.py e haar3.py, i file XML, lโ€™immagine e il video demo cui abbiamo fatto riferimento sono disponibili allโ€™interno della cartella face_eye_detect. scaricabile dalla sezione download.

Fig. 6 Con il parametro inSize รจ possibile rilevare volti piccolissimi, anche da fotografie inquadrate dalla telecamera.

Download

Conclusioni

Bene, possiamo ritenere conclusa la trattazione. Termina qui, con questo progetto di riconoscimento facciale tramite Raspberry Pi, il nostro viaggio allโ€™interno della libreria OpenCV 4, anche se ci sarebbe ancora molto da dire e si potrebbero proporre vari altri esempi applicativi; questo non รจ escluso perchรฉ in futuro ci piacerebbe continuare a pubblicare le nostre sperimentazioni con OpenCV 4, quindi continuate a seguirci.

Se volete approfondire lโ€™utilizzo di Open CV4ย Futura Academy mette a disposizione un corso specifico.

Lascia un commento

Il tuo indirizzo email non sarร  pubblicato.

Menu