Tag: python

Fun with Python, OpenCV and face detection

I had some fun with Gary Bishop’s OpenCV Python wrapper this morning. I wanted to try out OpenCV for detecting faces using a web cam. This could be used for instance to see if someone is sitting behind his desk or not. I used Gary’s Python wrapper since I didn’t want to code in C++.

I didn’t know where to start, so I searched for existing OpenCV face detection examples. I found a blog post by Nirav Patel explaining how to use OpenCV’s official Python bindings to perform face detection. Nirav will be working on a webcam module for Pygame for the Google Summer of Code.

I managed to rewrite Nirav’s example to get it working with CVtypes:

Here’s the code. Although it’s just a quick and dirty hack, it might be useful to others. It requires CVtypes and OpenCV, and was tested on Ubuntu Hardy with a Logitech QuickCam Communicate Deluxe webcam. You will need Nirav’s Haar cascade file as well.

import sys
from CVtypes import cv
 
def detect(image):
    image_size = cv.GetSize(image)
 
    # create grayscale version
    grayscale = cv.CreateImage(image_size, 8, 1)
    cv.CvtColor(image, grayscale, cv.BGR2GRAY)
 
    # create storage
    storage = cv.CreateMemStorage(0)
    cv.ClearMemStorage(storage)
 
    # equalize histogram
    cv.EqualizeHist(grayscale, grayscale)
 
    # detect objects
    cascade = cv.LoadHaarClassifierCascade('haarcascade_frontalface_alt.xml', cv.Size(1,1))
    faces = cv.HaarDetectObjects(grayscale, cascade, storage, 1.2, 2, cv.HAAR_DO_CANNY_PRUNING, cv.Size(50, 50))
 
    if faces:
        print 'face detected!'
        for i in faces:
            cv.Rectangle(image, cv.Point( int(i.x), int(i.y)),
                         cv.Point(int(i.x + i.width), int(i.y + i.height)),
                         cv.RGB(0, 255, 0), 3, 8, 0)
 
if __name__ == "__main__":
    print "OpenCV version: %s (%d, %d, %d)" % (cv.VERSION,
                                               cv.MAJOR_VERSION,
                                               cv.MINOR_VERSION,
                                               cv.SUBMINOR_VERSION)
 
    print "Press ESC to exit ..."
 
    # create windows
    cv.NamedWindow('Camera', cv.WINDOW_AUTOSIZE)
 
    # create capture device
    device = 0 # assume we want first device
    capture = cv.CreateCameraCapture(0)
    cv.SetCaptureProperty(capture, cv.CAP_PROP_FRAME_WIDTH, 640)
    cv.SetCaptureProperty(capture, cv.CAP_PROP_FRAME_HEIGHT, 480)    
 
    # check if capture device is OK
    if not capture:
        print "Error opening capture device"
        sys.exit(1)
 
    while 1:
        # do forever
 
        # capture the current frame
        frame = cv.QueryFrame(capture)
        if frame is None:
            break
 
        # mirror
        cv.Flip(frame, None, 1)
 
        # face detection
        detect(frame)
 
        # display webcam image
        cv.ShowImage('Camera', frame)
 
        # handle events
        k = cv.WaitKey(10)
 
        if k == 0x1b: # ESC
            print 'ESC pressed. Exiting ...'
            break

A known problem is that pressing the escape key doesn’t quit the program. Might be something wrong in my use of the cv.WaitKey function. Meanwhile you can just use Ctrl+C. All in all, the face detection works pretty well. It doesn’t recognize multiple faces yet, but that might be due to the training data. It would be interesting to experiment with OpenCV’s support for eye tracking in the future.

Update: the script does recognize multiple faces in a frame. Yesterday when Alex stood at my desk, it recognized his face as well. I think it didn’t work before because I used cv.Size(100, 100) for the last parameter of cv.HaarDetectObjects instead of cv.Size(50, 50). This parameter indicates the minimum face size (in pixels). When people were standing around my desk, they were usually farther away from the camera. Their face was then probably smaller than 100×100 pixels.

Just a quick note on ctypes. I remember when I created PydgetRFID that I tried to use libphidgets’ SWIG-generated Python bindings, but couldn’t get them to work properly. I had read about ctypes, and decided to use it for creating my own wrapper around libphidgets. Within a few hours I had a working prototype. When you’re struggling with SWIG-generated Python bindings, or have some C library without bindings that you would like to use, give ctypes a try. Gary Bishop wrote about a couple of interesting ctypes tricks to make the process easier.

Announcing PydgetRFID

I just released version 0.1 of PydgetRFID, the Python interface to the Phidgets Inc. RFID kit I blogged about earlier. It’s free software (licensed under the GPL). It wraps libphidgets with ctypes to talk to the hardware.

The software is now more polished and additionally provides a D-Bus service that allows other applications (written in any language with D-Bus bindings) to use the hardware. Currently this means you can connect to the hardware from Python, Ruby, .NET, C, C++, Perl and Pascal!

This DBUS service allows to start and stop reading, and emits a signal whenever a different tag (including the nil value) is read. I modified the original PyGTK GUI to use this daemon for communicating with the hardware. Furthermore, I improved the HAL support so that plugging the device in and out is detected. Unfortunately, the daemon cannot yet handle this though. That’s for a next release

Here is the GUI (which you probably remember from the last post). Nil values are now colored red:

PydgetRFID: GUI

And this a screenshot showing the communication between the daemon and the GUI logged with dbus-monitor:

PydgetRFID: using the the daemon and GUI

More information can be found at the PydgetRFID homepage.

PyGTK GUI for the PhidgetRFID reader

I had some fun writing a Python wrapper around libphidgets for an RFID reader we had lying around here. To do so, I used ctypes (apparantly the Python bindings for libphidgets were broken). To check for a connected RFID reader, I interfaced with hal through dbus. Afterwards I created a simple GUI for the device with PyGTK.

Here is the result:

PyGTK GUI for RFID reader

I experienced some weird permissions problems though. The device could only be opened with root privileges. Takis helped me step through libphidgets to see if there was a bug in it. In the end, we solved it by changing the /etc/udev/rules.d/permissions.rules file (in my case it was called 40-permissions.rules). I’m not sure if there are any security problems with this though.

I changed these lines:

# USB devices (usbfs replacement)
SUBSYSTEM=="usb_device", MODE="0664"

to:

# USB devices (usbfs replacement)
SUBSYSTEM=="usb_device", GROUP="plugdev", MODE="0664"

I will probably put the code online when I have some spare time (and after I cleaned it up a bit).