Non ci sono prodotti a carrello.
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).
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.
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></_> โฆ โฆ โฆ
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()
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.
Download
Codice per Riconoscimento Facciale
1 file(s) 17.58 MB
Per il download di questo file รจ necessario essere registrati al sito
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.