Facial Recognition via Python (non-OpenCV)

After working with the IR, I decided to cut the IR equipment out of the equation and was going to try my hand at facial recognition. This one does not use OpenCV or haarcascades. Instead, it uses a library I found through google called fdlib. It was written in C/C++, so using it with python shouldn’t be a problem. You can embed C/C++ in python via ctypes. You have already seen me use it in a previews post to set the cursor position in windows.

You can find fdlib at http://www.kyb.mpg.de/bs/people/kienzle/facedemo/facedemo.htm

The download also came with an example also written in C/C++

#include "windows.h"
#include "loadbmp.h" // from http://gpwiki.org/index.php/LoadBMPCpp
#include "fdlib.h"

void main(int argc, char *argv[])
{
 int i, n, x[256], y[256], size[256], w, h, threshold;
 BMPImg *bi;
 unsigned char *bgrdata, *graydata;

 if (argc==1)
 {
 printf("usage: fdtest bmpfilename [threshold]\n");
 exit(0);
 }

 bi = new BMPImg();
 printf("\nloading %s\n", argv[1]);
 bi->Load(argv[1]);
 w = bi->GetWidth();
 h = bi->GetHeight();
 printf("image is %dx%d pixels\n", w, h);
 bgrdata = bi->GetImg();
 graydata = new unsigned char[w*h];

 for (i=0; i
 {
 graydata[i] = (unsigned char) ((.11*bgrdata[3*i] + .59*bgrdata[3*i+1] + .3*bgrdata[3*i+2]));
 //if (i<10) printf("%d ", graydata[i]);
 }

 threshold = argc>2 ? atoi(argv[2]) : 0;
 printf("detecting with threshold = %d\n", threshold);
 fdlib_detectfaces(graydata, w, h, threshold);

 n = fdlib_getndetections();
 if (n==1)
 printf("%d face found\n", n);
 else
 printf("%d faces found\n", n);

 for (i=0; i
 {
 fdlib_getdetection(i, x+i, y+i, size+i);
 printf("x:%d y:%d size:%d\n", x[i], y[i], size[i]);
 }

 delete[] graydata;
 delete bi;
}

I noticed in the first “for loop” they convert a color image into a gray-scale image. We can cut that piece of code out since PIL has a method for that. im.convert(“L”)

My Version is a little beefed up though. I use a webcam to grab the images and display them with pygame. This way its in realtime instead of supplying an image as a command line argument. Below is a saved image from my version, I would have used print screen to grab it while viewing my webcam, but its hard to hold a picture + fn + prt sc

test photo for fdlib

The little blond one in the photograph is me at like 5 or so.

Note: This code is windows specific.

Requires:

  • PIL http://www.pythonware.com/products/pil/
  • fdlib http://www.kyb.mpg.de/bs/people/kienzle/facedemo/facedemo.htm
  • VideoCapture http://videocapture.sourceforge.net/
  • pygame http://pygame.org/news.html
  • psyco (optional) http://psyco.sourceforge.net/
from VideoCapture import Device
from ctypes import *
import Image, ImageDraw, os, time, pygame, sys
from pygame.locals import *
from psyco import full
full()

fd = cdll.LoadLibrary("fdlib.dll")

#assignments
cam = Device()
pygame.init()
screen = pygame.display.set_mode((640,480))
pygame.display.set_caption('Facial Recognition')
font = pygame.font.SysFont("Curier",26)

pixX = 0
pixY = 0
pixList = []

w = c_int(640)
h = c_int(480)
threshold = c_int(0)#raise this number for more accuracy

x = c_int * 256
y = c_int * 256
size = c_int * 256
x = x()
y = y()
size = size()

graydata = c_ubyte * (640*480)
graydata = graydata()
fps = 25.0
while 1:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: sys.exit()

    im = cam.getImage()
    draw = ImageDraw.Draw(im)
    img = im.convert("L") #convert to grayscale
    imd = list(img.getdata()) #graydata needed
    cnt = 0
    pixX = 0
    pixY = 0
    cnt = 0

    for pix in imd: #Convert python data types to ctypes
        graydata[cnt] = imd[cnt]
        cnt+=1

    fd.fdlib_detectfaces(byref(graydata), w, h, threshold)
    n = fd.fdlib_getndetections() #number of faces
    i = 0
    while i < n:
        fd.fdlib_getdetection(c_int(i), x, y, size)
        bBoxTres = size[0]/2
        draw.rectangle([(x[0]+bBoxTres,y[0]+bBoxTres),(x[0]-bBoxTres,y[0]-bBoxTres)], outline=224)
        #This is how I saved the image you see above. Cut this "if statement" out
        #if you don't want it saving an image every time it see's 5 faces
        if n >= 5:
            im.save("5.jpg")
        #This i += 1 is not part of the "if statement" above
        i += 1

    faceNumber = font.render('Number of Faces: '+str(n), True, (46,224,1))
    imn = pygame.image.frombuffer(im.tostring(), (640,480), "RGB")
    screen.blit(imn, (0,0))
    screen.blit(faceNumber,(0,0))
    pygame.display.flip()
    pygame.time.delay(int(1000 * 1.0/fps))