Face Detection in Static Images with Python

One of the things I’ve been longing to do with my mobile photo-sharing site Camura is to offer image annotations, like objects and faces.  Over the last couple of years I have been increasingly frustrated by the appearance of face tagging on services like Facebook, and the recent addition of face recognition to iPhoto has brought this frustration to the surface once again.  I don’t even want to do something as complex as face recognition - I just want to find faces in an image.

Googling for things like “open source face detector” doesn’t come up with much.  The landscape seems to be comprised of mostly expensive for-pay libraries written for Windows, abandoned research projects, and lots of research papers full of equations – but no code that I could get to run.

To make a long post short, it turns out that Intel’s OpenCV computer vision library comes with a face detector example that should work out of the box.  Better yet, there are now some decent Python bindings for OpenCV that come pre-packaged with OpenCV for Ubuntu and Debian.  You can install them with: $ sudo apt-get install python-opencv

Now, it seems that most OpenCV face detector examples are meant to be run “live”, usually taking the image from a webcam and highlighting faces with a red box in real-time.  However, I have a large database of static images that I want to consider individually, and I simply want to save the face coordinates for later use, rather than altering the picture.

So, with a bit more Googling, I found a Python script that I could chop up and use for this purpose, and here is what I came up with:

An example run of the script looks something like this:

$ python face_detect.py marty_mcguire.jpg
[(50,36) -> (115,101)]

You can overlay that rectangle on an output image with ImageMagick’s “convert”:

$ convert marty_mcguire.jpg -stroke red -fill none -draw "rectangle 50,36 115,101" output.jpg

And the output might look something like this:

My face, it has been detected.

Pretty fun stuff!



Comments

Henrik on said:

Thx, was looking for this!

Dom on said:

Thanks for this example!

FYI, /usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml is contained in libcv-dev so you actually need to install that too for the code to run

i.e.,

$ sudo apt-get install python-opencv libcv-dev

Dom on said:

p.s. tested and working with the ISO standard CV http://en.wikipedia.org/wik... test image :-)

Anony M. on said:

Thank you very much indeed, sir.

ryanhaigh on said:

Thanks for this information it was very useful to me. I did however have a problem when using this in a larger program and I thought others might find it useful. It seems that "if faces:" will still be true even if no faces are found in the image. Using "if faces.total > 0:" worked perfectly.

Thanks Again,
ryanhaigh

marius on said:

Hi, I get an error when running this script:

$ ./face_detect.py lena.jpg
terminate called after throwing an instance of 'int'
Aborted
$ _

The same happens when running this from the python shell. When copy-pasting single lines, the error appears at "faces = cvHaarDetectObjects(...)". The shell is also killed. I don't even have a guess on where to start looking here. Any ideas on what goes wrong?

Robert McGuire on said:

Marius - have you tried ryanhaigh's suggestion of changing the "if faces:" line to "if faces.total > 0:"?

Alexander F. on said:

Hi! Anyone an idea how this works on windows? i get the "ImportError: No module named opencv.cv" Error using python 26 and opencv 2.1. copying the files from "C:\OpenCV2.1\Python2.6\Lib\site-packages" to "C:\Python26\Lib\site-packages" as said everywhere on the internet doesn't seem to work. best regards, alex

Guenter Bachelier on said:

I have just installed OpenCV 2.1 on Ubuntu with
http://gijs.pythonic.nl/blo...
and tried this code but I get a
ImportError: No module named opencv.cv

Alexander F on said:

Hi! I have the thingy running on windows but maybe this can help you:
•Add /bin to your PATH environment variable
•Create an environment variable PYTHONPATH and set it to /Python2.6/Lib/site-packages

adapt it to your versions/directories/operating systems needs.

John on said:

Nice stuff! Exactly what I wanted. Thanks.

Rob G. Healey on said:

This is an awesome piece of code and work! I am running Fedora Rawhide/ 15, and this runs perfectly!

Thank you so much for creating this code, and example to use...

wasuaje on said:

Hi there, great code, but i can't find /usr/share/opencv/haarcascades/haarcascade_frontal/face_default.xml on ubuntu 10.10 can you help me?

wasuaje on said:

Sorry found the solution myself here

https://bugs.launchpad.net/...

wasuaje on said:

Hello there, i prefer to do the image changes (draw the rectangles) right in python so i paste my code all python based:

#!/usr/bin/python

# face_detect.py

# Face Detection using OpenCV. Based on sample code from:
# http://python.pastebin.com/...

# Usage: python face_detect.py

import sys, os
from opencv.cv import *
from opencv.highgui import *
import Image, ImageDraw

def detectObjects(image):
"""Converts an image to grayscale and prints the locations of any
faces found"""
grayscale = cvCreateImage(cvSize(image.width, image.height), 8, 1)
cvCvtColor(image, grayscale, CV_BGR2GRAY)

storage = cvCreateMemStorage(0)
cvClearMemStorage(storage)
cvEqualizeHist(grayscale, grayscale)
cascade = cvLoadHaarClassifierCascade('/usr/share/doc/opencv-doc/examples/haarcascades/haarcascades/haarcascade_frontalface_alt.xml',cvSize(1,1))
faces = cvHaarDetectObjects(grayscale, cascade, storage, 1.2, 2,CV_HAAR_DO_CANNY_PRUNING, cvSize(50,50))

if faces.total > 0:
for f in faces:
x1,y1,x2,y2=f.x,f.y,f.x+f.width,f.y+f.height
print("[(%d,%d) -> (%d,%d)]" % (x1,y1,x2,y2))
print_rectangle(x1,y1,x2,y2) #call to a python pil

def print_rectangle(x1,y1,x2,y2):#function to modify the img
im = Image.open(sys.argv[1])
draw = ImageDraw.Draw(im)
draw.rectangle([x1,y1,x2,y2])
im.save(sys.argv[1])

def main():
image = cvLoadImage(sys.argv[1]);
detectObjects(image)

if __name__ == "__main__":
main()

marius on said:

Hi Robert, very late reply... :) I was just playing with stuff again and found the exact same website as last year.

I'm using Ubuntu 10.10 with everything installed from repository. Still get the same error, even with ryanhaigh’s change. The script never gets to that line, so that doesn't surprise me.

Cheers!

AnandOka on said:

Hi Marius,
you need to make sure that in:
cascade = cvLoadHaarClassifierCascade(
'path/to/haarcascade_frontalface_default.xml',
cvSize(1,1))
the path of the file is correct. Otherwise the returned value is a None which causes the abort.

In my ubuntu 11.04, the file is in
/usr/share/doc/opencv-doc/examples/haarcascades/haarcascades/haarcascade_frontalface_default.xml.gz
I just copied it to my working directory and extracted it there.
The code worked after that.

matias on said:

I've started this project about an year ago and uploaded to github when didn't had time to work on it, I guess it might be interesting to somebody.

It's python, of course, and uses opencv too.

https://github.com/omab/faces

Leigh on said:

1. install
# apt-get install python-opencv libcv-dev opencv-doc

2. extract
# cd /usr/share/doc/opencv-doc/examples/haarcascades/haarcascades/
# cp *.gz ..
# gunzip *.gz

3. Run (this changes your images and renames the old ones)

#!/usr/bin/python

# face_detect.py

# Face Detection using OpenCV. Based on sample code from:
# http://python.pastebin.com/...

# Usage: python face_detect.py

import sys,os
from opencv.cv import *
from opencv.highgui import *

CLASSIFIER='/usr/share/doc/opencv-doc/examples/haarcascades/haarcascade_frontalface_default.xml'

def detectObjects(fn, image):
"""Converts an image to grayscale and prints the locations of any
faces found"""
grayscale = cvCreateImage(cvSize(image.width, image.height), 8, 1)
cvCvtColor(image, grayscale, CV_BGR2GRAY)

storage = cvCreateMemStorage(0)
cvClearMemStorage(storage)
cvEqualizeHist(grayscale, grayscale)
cascade = cvLoadHaarClassifierCascade(CLASSIFIER, cvSize(1,1))
faces = cvHaarDetectObjects(grayscale, cascade, storage, 1.2, 2,
CV_HAAR_DO_CANNY_PRUNING, cvSize(50,50))

if faces:
for f in faces:
newfn = fn + ".output.jpg"
os.system("convert %s -stroke red -fill none -draw 'rectangle %d,%d %d,%d' %s" % (fn, f.x, f.y, f.x+f.width, f.y+f.height, newfn))
os.system("mv %s %s.orig" % (fn, fn))
os.system("mv %s %s" % (newfn, fn))

def main():
image = cvLoadImage(sys.argv[1]);
detectObjects(sys.argv[1], image)

if __name__ == "__main__":
main()

Toby Skinner on said:

If you are using Python(X,Y) with Open CV 2 then you'll need to make a few tweaks. I couldn't find the Haar classifier data in the standard install so I needed to download OpenCV, extract it and the data folder can be found in there (no need to actually build or install OpenCV).

My version that works, I'm not a Python dev so I'm sure there are optimisations etc:

import sys, os
import cv2.cv as cv

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

grayscale = cv.CreateImage((image.width, image.height), 8, 1)
cv.CvtColor(image, grayscale, cv.CV_BGR2GRAY)

storage = cv.CreateMemStorage(0)
cv.EqualizeHist(grayscale, grayscale)
cascade = cv.Load('')
faces = cv.HaarDetectObjects(grayscale, cascade, storage, 1.2, 2, cv.CV_HAAR_DO_CANNY_PRUNING, (50,50))

if faces:
for f in faces:
print(f)

Note I'm not sure where the ClearMemStorage function has gone and whether del does the same thing or not, someone better at Python might be able to help.

Also the data structures returned are slightly different, each 'face' is a tuple containing a rect and an int.

Hope that helps someone.

hemanth on said:

I've got the error message

terminate called after throwing an instance of 'int'
Aborted

Any one could help me.?

emijrp on said:

I downloaded this file and replaced the path to this file in the code http://tutorial-haartrainin... Also, I installed opencv-doc. I voila, it works.

Reidel Martin-Raul on said:

Hello i was wondering if you could help me out a bit with a problem... i would like to make a facial recognition software for my laptop and i dont really now were to start from please it would mean a lot to me u could send me a message on raolboss@yahoo.com