Computer vision: OpenCV realtime face detection in Python

Per festeggiare degnamente l’arrivo del mio nuovo portatile in famiglia ho pensato di renderlo in grado di riconoscere volti umani da una sorgente video in tempo reale.

Video dell’applicazione realizzata

Segue il video dimostrativo dell’applicazione realizzata:

OpenCV (Open Source Computer Vision Library)

Era da tempo che desideravo utilizzare la libreria Open CV per tornare a fare qualche esperimento di Computer Vision e per esplorare le sue tanto decantate potenzialità.

OpenCV è una libreria rilasciata sotto licenza BSD dalla Intel per l’elaborazione realtime delle immagini e la Computer Vision.

Scritta in C e C++ è utilizzabile, tramite wrapper (sia ufficiali che non) in diversi linguaggi: Python, Ruby, Java, C# ed è stata portata sui principali sistemi operativi: GNU/Linux, FreeBSD, Mac OS X, Windows ma anche Android e iOS per lo sviluppo di applicazioni su dispositivi mobili.

Alcuni wrapper esportano solo un limitato sottoinsieme di funzionalità.

face-detection demo 009Mi sono reso conto che le potenzialità di tale libreria sono superiori alle mie più rosee aspettative: c’è tutto quello che può servire (e si può sognare) per realizzare applicazioni avanzate di Computer Vision ed elaborazione delle immagini.

Video di alcune interessanti applicazioni che è possibile realizzare

Sviluppare un’applicazione di ottima qualità per la face detection in realtime, problema normalmente complesso, diventa banale a tal punto che mi sono limitato a fare qualche ricerca su internet ed assemblare poche righe di codice Python trovate in alcuni blog.

Face Detection ed Haar-like features

L’algoritmo molto efficiente che viene utilizzato per la rilevazione dei volti, basato sulle Haar wavelet, è stato elaborato da Viola-Jones nell’ambito dell’object detection ed è stato pensato proprio per il problema della face detection in tempo reale.

Con OpenCV è possibile addestrare nuovi identificatori di oggetti tuttavia sono già presenti i seguenti classificatori (in formato xml):

haarcascade_eye_tree_eyeglasses.xml
haarcascade_eye.xml
haarcascade_frontalface_alt2.xml
haarcascade_frontalface_alt_tree.xml
haarcascade_frontalface_alt.xml
haarcascade_frontalface_default.xml
haarcascade_fullbody.xml
haarcascade_lefteye_2splits.xml
haarcascade_lowerbody.xml
haarcascade_mcs_eyepair_big.xml
haarcascade_mcs_eyepair_small.xml
haarcascade_mcs_lefteye.xml
haarcascade_mcs_mouth.xml
haarcascade_mcs_nose.xml
haarcascade_mcs_righteye.xml
haarcascade_mcs_upperbody.xml
haarcascade_profileface.xml
haarcascade_righteye_2splits.xml
haarcascade_upperbody.xml

Nelle mie prove, dopo aver individuato il volto, ho provato a rilevare anche gli occhi e la bocca ma in questo caso i risultati non mi hanno soddisfatto.

Sorgente Python

I miei esperimenti sono stati effettuati su una macchina GNU/Linux Ubuntu 11.04 con OpenCV 2.1.

E’ richiesto il pacchetto python-opencv, presente nei repository ufficiali e si assume che nel path dello script sia presente una directory haarcascades contenente i vari xml necessari per la detection.

Su Ubuntu 11.04 è possibile trovarli nella directory:

/usr/share/doc/opencv-doc/examples/haarcascades/haarcascades/

segue il codice sorgente utilizzato per la realizzazione del video:

#!/usr/bin/python

#----------------------------------------------------------------------------
# Face Detection Test (OpenCV)
#
# thanks to:
# http://japskua.wordpress.com/2010/08/04/detecting-eyes-with-python-opencv
#----------------------------------------------------------------------------

import cv
import time
import Image

def DetectFace(image, faceCascade):

    min_size = (20,20)
    image_scale = 2
    haar_scale = 1.1
    min_neighbors = 3
    haar_flags = 0

    # Allocate the temporary images
    grayscale = cv.CreateImage((image.width, image.height), 8, 1)
    smallImage = cv.CreateImage(
            (
                cv.Round(image.width / image_scale),
                cv.Round(image.height / image_scale)
            ), 8 ,1)

    # Convert color input image to grayscale
    cv.CvtColor(image, grayscale, cv.CV_BGR2GRAY)

    # Scale input image for faster processing
    cv.Resize(grayscale, smallImage, cv.CV_INTER_LINEAR)

    # Equalize the histogram
    cv.EqualizeHist(smallImage, smallImage)

    # Detect the faces
    faces = cv.HaarDetectObjects(
            smallImage, faceCascade, cv.CreateMemStorage(0),
            haar_scale, min_neighbors, haar_flags, min_size
        )

    # If faces are found
    if faces:
        for ((x, y, w, h), n) in faces:
            # the input to cv.HaarDetectObjects was resized, so scale the
            # bounding box of each face and convert it to two CvPoints
            pt1 = (int(x * image_scale), int(y * image_scale))
            pt2 = (int((x + w) * image_scale), int((y + h) * image_scale))
            cv.Rectangle(image, pt1, pt2, cv.RGB(255, 0, 0), 5, 8, 0)

    return image

#----------
# M A I N
#----------

capture = cv.CaptureFromCAM(0)
#capture = cv.CaptureFromFile("test.avi")

#faceCascade = cv.Load("haarcascades/haarcascade_frontalface_default.xml")
#faceCascade = cv.Load("haarcascades/haarcascade_frontalface_alt2.xml")
faceCascade = cv.Load("haarcascades/haarcascade_frontalface_alt.xml")
#faceCascade = cv.Load("haarcascades/haarcascade_frontalface_alt_tree.xml")

while (cv.WaitKey(15)==-1):
    img = cv.QueryFrame(capture)
    image = DetectFace(img, faceCascade)
    cv.ShowImage("face detection test", image)

cv.ReleaseCapture(capture)