Python + OpenCV: FaceReplace

Cià, popoliamo un pò sto blog!

L’altro giorno “sfogliando” Hack A Day mi sono imbattuto in questo articolo. Quindi ho cominciato a documentarmi un pò sulla libreria OpenCV (che fortunatamente è disponibile anche per Python).

Girando di qua e di là e prendendo ispirazione soprattutto da questo post ho messo insieme (di fatto modificando un pò il codice del post linkato) uno scriptino in Python che acquisice l’immagine della webcam e rimpiazza la faccia (o le facce) con un’immagine che gli va passata come argomento. Questo è il risultato usando trollface.png:

Come vedete supporta anche più di una faccia alla volta. Un’altra cosa che si nota dal video è che purtroppo non sono ancora riuscito a capire come funziona la trasparenza, ci ho sbattuto la testa per tutta ieri notte e stanotte fino ad adesso ma niente; se passa qualche anima pia che ha idea di come fare lasci un commento, io ho provato maschere e mica maschere invano, se no se un giorno dovessi scoprirlo aggiornerò il post.

Quindi, appurato che per ora la trasparenza non va, è meglio usare immagini quadrate. Ergo, Creeper:

Lo script regge bene anche le mie agilissime finte e il face detection tiene anche il profilo a tre quarti, finchè non sparisce un occhio.

Ovviamente usandolo in real-time c’è un minimo di lag, direi intorno al mezzo secondo, ma io lo ritengo accettabile. Quando e se imparerò il C++ farò un confronto di prestazioni riscrivendolo in C++.

Veniamo al codice vero e proprio:

#!/usr/bin/python
#----------------------------------------------------------------------------
# Face Replacement Test (OpenCV)
#
# Mainly inspired (and copypasted) by this post by Luca Amore
# http://www.lucaamore.com/?p=638
# with some modifications to make it display an image
# instead of drawing a rectangle around the face
#
# Modified by rbino
# https://quelblogli.wordpress.com
#
#

import cv
import sys
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))
largh = pt2[0]-pt1[0]
lungh = pt2[1]-pt1[1]
roi = (pt1[0], pt1[1], largh, lungh)
cv.SetImageROI(image, roi)
cv.Resize(overlay, image)
cv.ResetImageROI(image)

return image

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

if len(sys.argv) != 2:
print "Argument: the image you want to swap your face with"
sys.exit(-1)

overlay = cv.LoadImage(sys.argv[1])

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

# I adapted the path to the one I've found on Debian Wheezy
# Uncomment the xml that you want to use

#faceCascade = cv.Load("/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml")
#faceCascade = cv.Load("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml")
faceCascade = cv.Load("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml")
#faceCascade = cv.Load("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt_tree.xml")

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

del(capture)
(Dite che è il caso che il codice lo alleghi a parte? Boh per ora faccio così, poi vedo).

Leggendo il codice noterete che commentando la riga che cattura dalla webcam e decommentando quella sotto si può far funzionare lo script anche con un video. Ho provato ad usarlo ma è molto lento, quindi ho lasciato il nome del file hardcodato nello script, se volete fare delle prove modificatelo. Comunque, copiate tutto l’ambaradam sopra, salvatelo in un bel facereplace.py, dategli i diritti di esecuzione e avviate con

./facereplace.py nomeimmagine

Vi servirà ovviamente la libreria OpenCV per Python, che se siete su una distro Linux Debian based (Ubuntu compresa) installate con un bel

sudo apt-get install python-opencv

se no date un’occhiata qui. Controllate anche che gli XML delle Haarcascades siano nel percorso segnato dopo faceCascade, altrimenti modificate il percorso in base alle vostre esigenze.

Bon, credo che sia tutto per questo primo post, almeno ho rotto il ghiaccio e gli altri due non hanno più l’ansia da prestazione 😀

Alla prossima!

Bino