Detecting blobs at the speed of light
While working on my eye tracking experiment I got to the point where I needed to execute a blob detection algorithm to determine relative positioning of the eyes. I found some really good blob detection algorithms but I didn't have enough time to try implementing them. Andrei R. Thomaz had ported an existing Processing library (based on subdivision), but it turned out to be too slow/complicated to fit for my needs.
Few days ago while looking for something else, I've found this genius object detection technique by japanese guy Kynd (developed from the original code by Kampei Baba). I decided to try it out for detecting blobs.
UPDATE: This blob detection method has also been discovered by Quasimondo and was shown (!) at Flash on the Beach 2007. It hasn't enough spread as Mario hadn't released the source.
You can test the result below, try it yourself. First, click the Flash area to activate, then click anywhere to add more blobs. You can also press space to toggle debug mode on/off.
I was totally amazed how fast (and exact) it performs! Believe or not but the main blob detection routine has only a few lines of code.
How does it work then?
It's really very simple – the secret lays in utilising the native floodFill Flash Player method in conjunction with getColorBoundsRect.
Here's how (after the jump).
Take a bitmapData in. Then use threshold method to convert it into 1-bit (black and white) bitmap (Kynd did it by superimposing slightly displaced images in DIFFERENCE blend mode and then removing noise with ConvolutionFilter and the threshold method, I left it out to gain processing speed - it's not really needed unless you want to isolate more complicated shapes).
Now, the magic happens just in a few steps.
-
Get the
rectanglecontaining all white pixels by usinggetColorBoundsRect(exit if it's empty). -
Examine the first column of pixels by sampling their values with
getPixel32. When white pixel is found, usefloodFillto mark the found shape with some third color. Then rungetColorBoundsRectagain but this time looking for that color. - If the derived rectangle fits the min/max size of the blob, store it's coordinates in the array.
-
Regardless of the previous result use
floodFillagain but this time with fourth colour, just to mark that shape as processed. - Repeat again until a number of blobs was found (or there's no more white pixels to examine).
I've modified Kynd's code a little bit, here's just the loop described above (you can grab the full class from his blog post).
while (i < maxBlobs)
{
// get the rectangle containing only white pixels
mainRect = r.getColorBoundsRect(0xffffffff, 0xffffffff);
// exit if the rectangle is empty
if (mainRect.isEmpty()) break;
// get the first column of the rectangle
var x:int = mainRect.x;
// examine pixel by pixel unless you find the first white pixel
for (var y:uint = mainRect.y; y < mainRect.y + mainRect.height; y++)
{
if (r.getPixel32(x, y) == 0xffffffff)
{
// fill it with some color
r.floodFill(x, y, FLOOD_FILL_COLOR);
// get the bounds of the filled area - this is the blob
blobRect = r.getColorBoundsRect(0xffffffff, FLOOD_FILL_COLOR);
// check if it meets the min and max width and height
if (blobRect.width > minWidth && blobRect.width < maxWidth && blobRect.height > minHeight && blobRect.height < maxHeight)
{
// if so, add the blob rectangle to the array
var blob:Object = {};
blob.rect = blobRect;
blobs.push(blob);
}
// mark blob as processed with some other color
r.floodFill(x, y, PROCESSED_COLOR);
}
}
// increase number of detected blobs
i++;
};
In my example the blobs meeting the size conditions are marked with green outline, the remaining ones are marked with red outline.
I am planning to build my own cardboard box touchscreen and try it out to capture finger movements. If you are interested in multitouch interfaces, make sure you check out Lux AS3 framework as well.
08:17 AM | posts | 14 Comments | Tags: as3, multitouchComments
- Eugene on June 1, 2009, at 10:02 AM
- kynd on June 1, 2009, at 06:34 PM
- Touch User Interface on June 6, 2009, at 11:28 AM
- Mario Klingemann on July 22, 2009, at 01:52 PM
- cipriano on September 10, 2009, at 12:50 AM
- Camila on October 13, 2009, at 04:22 PM
- Sammi on October 15, 2009, at 02:31 PM
- Og2t on October 16, 2009, at 05:33 PM
- Wayne on October 24, 2009, at 07:54 PM
- Marty on November 11, 2009, at 09:52 PM
- vladozver on October 22, 2010, at 02:10 AM
- Jimmy on October 28, 2010, at 04:51 PM
- Sérgio Silva on June 2, 2011, at 12:36 AM
- Mark on August 31, 2011, at 12:10 PM
Adding comments disabled for now.
