動体検知 + 肌色認識 2
/**
* Copyright alpicola ( http://wonderfl.net/user/alpicola )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/fSCb
*/
package {
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.BlendMode;
import flash.events.Event;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.filters.ColorMatrixFilter;
import flash.filters.ConvolutionFilter;
import flash.media.Camera;
import flash.media.Video;
[SWF(width="465", height="465", backgroundColor="#ffffff", frameRate="24")]
public class MotionDetection extends Sprite {
private var camera:Camera;
private var video:Video;
private var now:BitmapData;
private var prev:BitmapData;
private var rec:Rectangle;
private var pt:Point;
private var noiseReduction:ConvolutionFilter;
private var grayScale:ColorMatrixFilter;
private var skin:ColorMatrixFilter;
private var s:Sprite;
private var objects:Vector.<MotionObject> = new Vector.<MotionObject>();
public function MotionDetection() {
stage.align = "TL";
stage.scaleMode = "noScale";
camera = Camera.getCamera();
if (camera == null) return;
camera.setMode(465, 465, 24);
video = new Video(camera.width, camera.height);
video.attachCamera(camera);
addChild(video);
s = new Sprite();
addChild(s);
now = new BitmapData(camera.width, camera.height, false);
prev = new BitmapData(camera.width, camera.height, false);
rec = new Rectangle(0, 0, camera.width, camera.height);
pt = new Point();
noiseReduction = new ConvolutionFilter(3, 3);
noiseReduction.bias = -(0x1000 + 0x100 * 6);
noiseReduction.matrix = [
1, 1, 1,
1, 16, 1,
1, 1, 1
];
grayScale = new ColorMatrixFilter([
0.3, 0.59, 0.11, 0, 0,
0.3, 0.59, 0.11, 0, 0,
0.3, 0.59, 0.11, 0, 0,
0, 0, 0, 1, 0
]);
skin = new ColorMatrixFilter([
0, 0, 0, 0, 0,
-0.43, -0.85, 1.28, 0, 198.4,
1.28, -1.07, -0.21, 0, 108.8,
0, 0, 0, 1, 0
]);
addEventListener(Event.ENTER_FRAME, update);
}
private function update(e:Event):void {
var rect:Rectangle;
var rects:Vector.<Rectangle> = getRects();
var candidates:Vector.<MotionObject> = new Vector.<MotionObject>();
var intersects:Vector.<MotionObject>;
var object:MotionObject;
var n:int = objects.length;
for (var i:int = 0, length:int = rects.length; i < length; i++) {
rect = rects[i];
if (rect.width * rect.height > video.width * video.height * 0.7) continue;
intersects = new Vector.<MotionObject>();
for (var j:int = 0; j < n; j++) {
object = objects[j];
if (object.rect.intersects(rect)) intersects.push(object);
}
var len:int = intersects.length;
switch (len) {
case 0:
if (rect.width * rect.height > video.width * video.height * 0.02) {
candidates.push(new MotionObject(rect));
}
break;
case 1:
intersects[0].move(rect);
break;
default:
var result:MotionObject;
var intersection:Rectangle;
var size:int;
var max:int = 0;
while (len--) {
object = intersects[len];
intersection = rect.intersection(object.rect);
size = intersection.width * intersection.height;
if (size > max) {
result = object;
max = size;
}
}
result.move(rect);
}
}
while (n--) {
object = objects[n];
object.update();
if (object.dead) objects.splice(n, 1);
}
n = candidates.length;
while (n--) {
objects.push(candidates[n]);
}
draw();
}
private function getRects():Vector.<Rectangle> {
now.draw(video);
var copy:BitmapData = now.clone();
now.draw(prev, new Matrix(), new ColorTransform(), BlendMode.DIFFERENCE);
prev = copy.clone();
copy.applyFilter(now, rec, pt, skin);
now.applyFilter(now, rec, pt, grayScale);
now.threshold(now, rec, pt, ">", 0xff111111, 0xffffffff);
//now.threshold(now, rec, pt, "!=", 0xffffffff, 0xff000000);
now.threshold(copy, rec, pt, "!=", 0x008080, 0xff000000, 0x00c0c0);
now.applyFilter(now, rec, pt, noiseReduction);
var rects:Vector.<Rectangle> = new Vector.<Rectangle>();
var rect:Rectangle;
var bound:Rectangle = now.getColorBoundsRect(0xffffff, 0xffffff);
var line:BitmapData = new BitmapData(rec.width, 1, false);
var lineBound:Rectangle = new Rectangle(0, 0, rec.width, 1);
while (!bound.isEmpty()) {
lineBound.y = bound.y;
line.copyPixels(now, lineBound, pt);
bound = line.getColorBoundsRect(0xffffff, 0xffffff);
now.floodFill(bound.x, lineBound.y, 0xff00ff);
rect = now.getColorBoundsRect(0xffffff, 0xff00ff);
rect.inflate(4, 4);
now.fillRect(rect, 0x0000ff);
rects.push(rect);
bound = now.getColorBoundsRect(0xffffff, 0xffffff);
}
/*var length:int = rects.length;
for (var i:int = 0; i < length; i++) {
var rect1:Rectangle = rects[i];
for (var j:int = i + 1; j < length; j++) {
var rect2:Rectangle = rects[j];
if (rect1.intersects(rect2)) {
rects[j] = rect1.union(rect2);
rects.splice(i, 1);
i--;
length--;
break;
}
}
}*/
var m:int, n:int = rects.length;
var rect1:Rectangle, rect2:Rectangle;
while (n-- > 1) {
rect1 = rects[n];
m = n;
while (m--) {
rect2 = rects[m];
if (!rect1.intersects(rect2)) continue;
rects[m] = rect1.union(rect2);
rects.splice(n, 1);
break;
}
}
return rects;
}
private function draw():void {
s.graphics.clear();
s.graphics.lineStyle(0, 0x00c0c0);
var rect:Rectangle;
for (var i:int = 0, length:int = objects.length; i < length; i++) {
if (!objects[i].time) continue;
rect = objects[i].rect;
s.graphics.beginFill(0x00c0c0, 0.4);
s.graphics.drawRect(rect.x, rect.y, rect.width, rect.height);
s.graphics.endFill();
}
}
}
}
import flash.geom.Rectangle;
class MotionObject {
public var time:int = 0;
public var dead:Boolean = false;
public var rect:Rectangle;
private var rects:Vector.<Rectangle> = new Vector.<Rectangle>();
private var count:int = 5;
function MotionObject(rect:Rectangle) {
this.rect = rect;
}
public function move(rect:Rectangle):void {
rects.push(rect);
}
public function update():void {
time++;
var len:int = rects.length;
switch (len) {
case 0:
count--;
if (!count) dead = true;
break;
case 1:
count = 5;
rect = rects[0];
break;
default:
count = 5;
rect = rects[0];
while (--len) {
rect = rect.union(rects[len]);
}
}
if (rect.width > 8) rect.inflate(-4, 0);
if (rect.height > 8) rect.inflate(0, -4);
rects = new Vector.<Rectangle>();
}
}