- Find the edge of the objects by superimposing slightly displaced images in DIFFERENCE mode and then remove noise with ConvolutionFilter and the threshold method.
- Separate the edges into blocks using the getColorBoundsRect method.
- Draw lines around the edges in each of blocks(Voila!)
The most important part of the code is again based on
Baba Kanpei's motion tracking example. I used this technique to create the videos in
the next post.
Sample code
Not very organized yet and for demonstration purposes only.
Only works well with a photo with a rather simple background.
package {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.filters.*;
public class Detector {
private var s:BitmapData;
private var r:BitmapData;
private var blocks:Array;
public function Detector() {
}
public function proccess(s:BitmapData):Array {
var r1:BitmapData,r2:BitmapData,r3:BitmapData,r4:BitmapData;
r1 = getDiffImage(s);
r2 = getBlocks(r1);
r3 = drawBlobs(s);
return [r1,r2,r3];
}
public function getDiffImage(s:BitmapData):BitmapData {
var r:BitmapData = new BitmapData(s.width,s.height);
var r2:BitmapData = new BitmapData(s.width,s.height);
var rect:Rectangle = new Rectangle(0,0,s.width,s.height);
var pt:Point = new Point(0,0);
r.draw(s);
r2.draw(s);
var mtx = new Matrix();
mtx.translate(2,0);
r.draw(s, mtx, new ColorTransform(), BlendMode.DIFFERENCE);
mtx.translate(-2,2);
r2.draw(s, mtx, new ColorTransform(), BlendMode.DIFFERENCE);
r.copyPixels(r, new Rectangle(2,0,2,s.height), pt);
r2.copyPixels(r2, new Rectangle(0,2,s.width,2), pt);
r.draw(r2, new Matrix(), new ColorTransform(), BlendMode.ADD);
var filter:ConvolutionFilter = new ConvolutionFilter(3,3,
[0.1,0.1,0.1,
0.1,0.1,0.1,
0.1,0.1,0.1]);
r.applyFilter(r,rect,pt,filter);
r.threshold(r, rect, pt, "<", 0xff111111, 0xff000000);
r.threshold(r, rect, pt, "!=", 0xff000000, 0xffffffff);
return r;
}
public function getBlocks(s:BitmapData):BitmapData {
blocks = new Array();
var i:uint=0;
var o:Object;
var size:uint;
var r:BitmapData=new BitmapData(s.width,s.height);
r.draw(s);
var sp:Sprite = new Sprite();
var g:Graphics=sp.graphics;
var rect1:Rectangle,rect2:Rectangle;
while (true) {
i++;
if (i>1000) {
break;
}
rect1=r.getColorBoundsRect(0xffffffff,0xffffffff);
if (rect1.isEmpty()) {
break;
}
var x=rect1.x;
for (var y:uint = rect1.y; y < rect1.y + rect1.height; y++) {
if (r.getPixel32(x,y)==0xffffffff) {
r.floodFill(x, y, 0xffff00ff);
rect2=r.getColorBoundsRect(0xffffffff,0xffff00ff);
size=rect2.width*rect2.height;
if (size>300) {
o = new Object();
o.size=size;
o.rect=rect2;
o.bmpd=new BitmapData(o.rect.width,o.rect.height);
o.bmpd.copyPixels(r, o.rect, new Point(0,0));
blocks.push(o);
}
r.floodFill(x, y, 0xff00ffff);
}
}
}
for (i = 0; i<blocks.length; i ++) {
g.lineStyle(0,0x00FF00);
g.drawRect(blocks[i].rect.x, blocks[i].rect.y, blocks[i].rect.width, blocks[i].rect.height);
}
r.draw(sp);
return r;
}
public function drawBlobs(s:BitmapData):BitmapData {
var sp:Sprite = new Sprite();
var g = sp.graphics;
var r:BitmapData=new BitmapData(s.width,s.height);
r.draw(s);
var pts:Array;
var b:Object;
var mid1:Point,mid2:Point;
var x:int,y:int,i:uint,j:uint;
for (i = 0; i < blocks.length; i++) {
pts = [];
b = blocks[i];
for (y = 0; y < b.rect.height; y += 5) {
for (x = 0; x < b.rect.width; x += 1) {
if (b.bmpd.getPixel(x,y)==0xff00ff) {
pts.push(new Point(x,y));
break;
}
}
}
for (y = b.rect.height -1; y >= 0; y -=5) {
for (x = b.rect.width - 1; x >=0; x -= 1) {
if (b.bmpd.getPixel(x,y)==0xff00ff) {
pts.push(new Point(x,y));
break;
}
}
}
g.beginFill(0xFF0000,0.2);
g.lineStyle(0,0xFF0000);
for (j = 0; j < pts.length; j ++) {
if (j==0) {
mid1 = Point.interpolate(pts[j], pts[(j + 1) % pts.length], 0.5);
g.moveTo(b.rect.x + mid1.x, b.rect.y + mid1.y);
}
mid2 = Point.interpolate(pts[(j + 2) % pts.length], pts[(j + 1) % pts.length], 0.5);
g.curveTo(b.rect.x + pts[(j + 1) % pts.length].x, b.rect.y + pts[(j + 1) % pts.length].y, b.rect.x + mid2.x, b.rect.y + mid2.y);
}
g.endFill();
}
r.draw(sp);
return r;
}
}
}
Leave a comment