Saturday, January 14, 2006

motion capture in python

You know those suits with the ping-pong balls attached to it? The kind they use in motion capture? I thought it would be really cool if I could build my own. Then I'd be able to film my kickboxing and analyze it afterwards.

The current state-of-the-art seems to be tracking a magnetic field with the sensors on the suit. Unfortunately I don't have the resources to do that. So I'm going with the older way: visually tracking the markers.

I capture frames using my cheap webcam and the VideoCapture Python library. Others have used it for simple motion detection but not motion tracking. I decided to track the motion of red objects. Why red? Well, it's one of the least common colours in my office and is usually concentrated to a small area (bottle caps, mugs, books).

To get my hands on the red pixels I can't simply extract the R from RGB images. If a colour has a red component it could also be white, yellow, magenta... So you take the R and subtract the G and B. Ignoring values below zero you now have a gauge for the "redness" of a pixel.

(Extra points: Correct me if I'm wrong, but I believe "R minus G minus B" will give you a "redness" plane that intersects the xy chromaticity diagram (see sRGB color space) as a line running from blue to green along the edge of the sRGB gamut. The triangular plane segment within the gamut reaches it's "peak" at the maximum red representable by sRGB.)

This is a simple way to find the maximum red point on the image. I drew a crosshair over that point for clarity. With the series of images captured by the webcam I constructed an animated gif. So the system tracks a red object. Cool.

However, what I want to do is track more than one red object. I did this by forming clusters of red dots above certain intensity.

How do you form clusters? Well I used the K-means algorithm, conveniently included with SciPy. Et viola! It seems to do a pretty good job of it.

Not bad for a days work. Only 150 lines of Python. Of course it is at this point that my fear is confirmed: My webcam doesn't seem up to the task of tracking the speed of my movements. So before I jump around with a bunch of red markers on my body, I'll need a better camera.

Edit: You can download a rough version of the code here: Parts are commented out so you don't need a webcam. You will need Python, SciPy and PIL however. I hope this works...

Another Edit: Here's an alternative I wrote ( that uses numarray, Pycluster and PIL instead. I'm starting to dislike SciPy. If there are enough requests I think I'll have to do another write-up.