Image cropping and face detection

Posted: June 13th, 2011 | Author: | Filed under: Python | 7 Comments »

The project I’m currently working on requires cropping of hundreds of portraits from the First World War archives at the Imperial War Museum.

Running a batch script on a directory of images is straight forward except my script is pretty dumb and tries to do a centre crop to create a square image. Unfortunately some of these images are not suitable for centre cropping:

Some of these portraits are quite long in height so a centre crop often results in the decapitation of the subject!

The logical thing to do here is to have your script first detect where the face is and then make a more intelligent crop to ensure the face remains in the new image. But surely face recognition requires super computers and several PhDs? Yes, it does. But we don’t really care who the subject is, we just need to know where the face is (or at least something that looks like a face). What we need is face detection, not recognition.

I was surprised to come across this little beauty: OpenCV, an open library for vision processing and luckily there’s a nice Python binding for it.

I tried out a sample from Robert Martin McGuire’s blog and was amazed at how simple and effective it was.

Robert’s script spits out two coordinates from the image that places a rectangle of where the face is. If your image has more than one person in it (or things that look like faces – more on that later) it will return two sets for each face.

Here’s the same image after running it through our face detection script:

Perfect! now we can adjust our cropping script to ensure that the face is within the bounds.

I tried this using really high resolution images and the script detected several faces in the image where there was only one. The problem is that if you have a lot of detail in your image like background artifacts and smudges there is likely to be some pattern that matches those of a face. For best results you may want to work with smaller images.

You can get this script from Robert’s site but here it is for all you lazy people. Make sure you’ve installed all necessary libraries. On Debian/Ubuntu you should be able to use this:

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

Test out the script like this:

$python thescript.py original.jpg output.jpg

If you get errors chances are it’s not finding the XML files. I had to copy these manually to get it to work. Note: this script doesn’t do any cropping, it just shows you where the face is and you will need to do the cropping yourself with some trial and error.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import os
import sys
 
from opencv.cv import *
from opencv.highgui import *
import Image, ImageDraw
 
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[2])
 
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/opencv/haarcascade/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)]" % (f.x, f.y, f.x + f.width, f.y + f.height))
            print_rectangle(x1,y1,x2,y2) #call to a python pil
 
def main():
    image = cvLoadImage(sys.argv[1]);
    detectObjects(image)
 
if __name__ == "__main__":
  main()
7 Comments »
  • http://www.designbull.co.uk/ designbull

    I wonder if it’s similar to the face recognition iPhoto on the Mac uses?

    • Anonymous

      I think they use far more sophisticate algorithms but the basic concept should be the same. The other difference is that those systems ‘learn’ as they process images.

  • Mjavidan18

    Hi dear giv

    there is another open-source library for image processing which is very
    useful and it is EMGU it also uses opencv dll and it was really useful
    for me in real-time human detection and even face feature extraction.

    mohammad javidan

    • Anonymous

      Thanks Mohammad, sorry about the super late reply. I’ll definitely look into this library.

  • Morgan

    Hey, buddy! 

    Thanks for sharing the information. Meanwhile, I have a small problem (Ihope)… When I run the program on a python shell, I get this error “…image = cvLoadImage(sys.argv[1]);
    NameError: global name ‘cvLoadImage’ is not defined”.

    What can I do to solve this? All help is appreciated.

    Thanks in advance!

    • Anonymous

      Hey Morgan,
      Sounds like the OpenCV module hasn’t been installed yet. If you’re on Debian/Ubuntu you should be able to use: sudo apt-get install python-opencv libcv-dev python-imaging ?

      You should also be able to use: sudo easy_install opencv

      Give that a try.

      G

  • Pingback: Detect face then autocrop pictures | question code