役に立たない動体検知時計
動体検知のアルゴリズムを採り入れてみた時計です。
カメラに映った人の動きに反応して時計を表示します。
表示された時計は、人の動作に合わせて向きが変化したり
大きさが変化したりします。というか、するはずです。
たぶん、すると思います。まちょっと覚悟はしておけ。
カメラの前を右へ左へと通り過ぎてみたりして、時計が
反応してくれることを期待しながら試してみて下さい。
/**
* Copyright mousepancyo ( http://wonderfl.net/user/mousepancyo )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/4rGk
*/
// forked from Event's Human Clock
/*
動体検知のアルゴリズムを採り入れてみた時計です。
カメラに映った人の動きに反応して時計を表示します。
表示された時計は、人の動作に合わせて向きが変化したり
大きさが変化したりします。というか、するはずです。
たぶん、すると思います。まちょっと覚悟はしておけ。
カメラの前を右へ左へと通り過ぎてみたりして、時計が
反応してくれることを期待しながら試してみて下さい。
*/
package {
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Point;
import fl.motion.easing.*;
import com.flashdynamix.motion.*;
[SWF(width=465, height=465, backgroundColor=0xFFFFFF, frameRate=30)]
public class HumanClock extends Sprite {
private var _timer:Timer
private var _container:Sprite
private var _sec:int;
private var _motions:MotionDetection;
private var _hPanelList:Vector.<TimePanel> = new Vector.<TimePanel>()
private var _hXList:Vector.<Number> = new Vector.<Number>();
private var _hYList:Vector.<Number> = new Vector.<Number>();
private var _hZList:Vector.<Number> = new Vector.<Number>();
private var _hSizeList:Vector.<Number> = new Vector.<Number>();
private var _mPanelList:Vector.<TimePanel> = new Vector.<TimePanel>()
private var _mXList:Vector.<Number> = new Vector.<Number>();
private var _mYList:Vector.<Number> = new Vector.<Number>();
private var _mZList:Vector.<Number> = new Vector.<Number>();
private var _mSizeList:Vector.<Number> = new Vector.<Number>();
private var _sPanelList:Vector.<TimePanel> = new Vector.<TimePanel>()
private var _sXList:Vector.<Number> = new Vector.<Number>();
private var _sYList:Vector.<Number> = new Vector.<Number>();
private var _sZList:Vector.<Number> = new Vector.<Number>();
private var _sSizeList:Vector.<Number> = new Vector.<Number>();
private var _offsetH:int = -100
private var _offsetM:int = 0
private var _offsetS:int = 100
private var _oldx:Number = 0
private var _oldy:Number = 0
private var _oldSize:Number = 1
private var _motionX_flg:String
private var _motionY_flg:String
private var _motionSize_flg:String
private var _motionCount:int = 30
private var _tween:TweensyGroup;
private const _rad: Number = 250;
private const _grovalZ: Number = 150;
private const _centerZ: Number = 380;
public function HumanClock() {
initView()
}
private function initView():void {
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
//
_motions = new MotionDetection(stage.stageWidth, stage.stageHeight)
addChild(_motions)
//
_container = new Sprite();
_container.x = this.stage.stageWidth/2;
_container.y = this.stage.stageHeight/2;
addChild(_container);
_container.visible = false
//
createClock(_hPanelList, _hXList, _hYList, _hZList, _hSizeList, 24, _offsetH)
createClock(_mPanelList, _mXList, _mYList, _mZList, _mSizeList, 60, _offsetM)
createClock(_sPanelList, _sXList, _sYList, _sZList, _sSizeList, 60, _offsetS)
//
clockStart()
//
_motions.addEventListener(MotionDetection.CAM_DEACTIVE, camDeactive)
}
private function clockStart():void{
_timer = new Timer(50);
_timer.addEventListener(TimerEvent.TIMER, onTimer);
_timer.start();
}
private function onTimer(e:TimerEvent):void {
var time:Date = new Date;
var hour:int = time.getHours();
var min:int = time.getMinutes();
var sec:int = time.getSeconds();
var nx:Number = 0
var ny:Number = 0
var ns:Number = 0
//
if(_motions.getPosition().length != 0 && _motionX_flg == "" && _motionY_flg == ""){
//_container.visible = true
if(_tween == null) showObj(_container, 1.5)
//
for(var i:int=0; i<_motions.getPosition().length; i++){
nx += _motions.getPosition()[i].x
ny += _motions.getPosition()[i].y
ns += _motions.getPosition()[i].width * _motions.getPosition()[i].height
}
if(nx/_motions.getPosition().length < _oldx){
_motionX_flg = "left"
}else{
_motionX_flg = "right"
}
if(ny/_motions.getPosition().length < _oldy){
_motionY_flg = "top"
}else{
_motionY_flg = "bottom"
}
if(ns/_motions.getPosition().length < _oldSize){
_motionSize_flg = "small"
}else{
_motionSize_flg = "large"
}
addEventListener(Event.ENTER_FRAME, movedClock)
_oldx = nx/_motions.getPosition().length
_oldy = ny/_motions.getPosition().length
_oldSize = ns/_motions.getPosition().length
}else{
_motionX_flg = ""
_motionY_flg = ""
}
//
updateView(hour, min, sec);
}
private function updateView(h:int, m:int, s:int):void {
updateClock(_hPanelList, _hXList, _hYList, _hZList, _hSizeList, 24, h)
updateClock(_mPanelList, _mXList, _mYList, _mZList, _mSizeList, 60, m)
updateClock(_sPanelList, _sXList, _sYList, _sZList, _sSizeList, 60, s)
}
//created clock init view
private function createClock(panelList:Vector.<TimePanel>, xList:Vector.<Number>, yList:Vector.<Number>, zList:Vector.<Number>, sizeList:Vector.<Number>, count:int, offset:int):void{
for(var i:Number = 0; i < count; i++){
panelList.push(new TimePanel());
if(i < 10){
panelList[panelList.length-1].tx.text = "0"+i.toString();
}else {
panelList[panelList.length-1].tx.text = i.toString();
}
_container.addChild(panelList[panelList.length-1]);
xList.push(offset);
yList.push(0);
zList.push(0);
sizeList.push(1);
}
}
//update clock view
private function updateClock(panelList:Vector.<TimePanel>, xList:Vector.<Number>, yList:Vector.<Number>, zList:Vector.<Number>, sizeList:Vector.<Number>, count:int, time:int):void{
for(var i:Number = 0; i < count; i++){
var angle:Number = (time/count * Math.PI * 2 - i/count * Math.PI * 2);
var py:Number = _rad*Math.sin(angle);
var pz:Number = _centerZ - _rad*Math.cos(angle);
yList[i] += (py - yList[i])/4;
zList[i] += (pz - zList[i])/4;
if(i == time){
sizeList[i] += (4 - sizeList[i])/4;
}else{
sizeList[i] += (1 - sizeList[i])/4;
}
panelList[i].x = xList[i] * _grovalZ/zList[i];
panelList[i].y = yList[i] * _grovalZ/zList[i];
panelList[i].scaleX = sizeList[i] * _grovalZ/zList[i];
panelList[i].scaleY = sizeList[i] * _grovalZ/zList[i];
}
}
//moved clock view
private function movedClock(e:Event):void{
var i:int
_motionCount--
if(_motionCount > 0){
if(_motionX_flg == "right"){
for(i=0; i<_hXList.length; i++){
_hXList[i] -=15
}
for(i=0; i<_mXList.length; i++){
_mXList[i] -=15
_sXList[i] -=15
}
}else if(_motionX_flg == "left"){
for(i=0; i<_hXList.length; i++){
_hXList[i] +=15
}
for(i=0; i<_mXList.length; i++){
_mXList[i] +=15
_sXList[i] +=15
}
}
if(_motionY_flg == "top"){
_container.rotationX += 2
}else if(_motionY_flg == "bottom"){
_container.rotationX -= 2
}
if(_motionY_flg == "large"){
_container.scaleX += 0.1
_container.scaleY += 0.1
}else if(_motionY_flg == "small"){
_container.scaleX -= 0.1
_container.scaleY -= 0.1
}
}else{
removeEventListener(Event.ENTER_FRAME, movedClock)
_motionX_flg = ""
_motionY_flg = ""
_motionCount = 30
}
}
private function camDeactive(e:Event):void{
if(_tween == null) hideObj(_container, 1.5)
removeEventListener(Event.ENTER_FRAME, movedClock)
}
private function initClock():void{
for(var i:int=0; i<_hXList.length; i++){
_hXList[i] = -100
}
for(i=0; i<_mXList.length; i++){
_mXList[i] = 0
_sXList[i] = 100
}
_container.rotationX = 0
_container.scaleX = 1
_container.scaleY = 1
}
//tween
public function tween(sp:Sprite, time:Number, xPos:Number, yPos:Number=0, delay:Number=0):void{
_tween = new TweensyGroup();
_tween.to(sp, {x:xPos, y:yPos}, time, Linear.easeInOut, delay);
_tween.onComplete = memoryClear;
function memoryClear():void{
_tween.dispose();
_tween = null;
}
}
private function showObj(sp:Sprite, time:Number, delay:Number=0):void{
_tween = new TweensyGroup();
sp.visible = true
_tween.to(sp, {alpha:1}, time, null, delay);
//
_tween.onComplete = memoryClear;
function memoryClear():void{
_tween.dispose();
_tween = null;
}
}
private function hideObj(sp:Sprite, time:Number, delay:Number=0):void{
_tween = new TweensyGroup();
_tween.to(sp, {alpha:0}, time, null, delay);
_tween.onComplete = memoryClear;
function memoryClear():void{
initClock()
sp.visible = false
_tween.dispose();
_tween = null;
}
}
}
}
// class TimePanel
import flash.display.Sprite;
import flash.display.Shape;
import flash.text.TextField;
import flash.text.TextFormat;
class TimePanel extends Sprite{
private var _tx:TextField = new TextField()
private var _fmt:TextFormat = new TextFormat("_typewriter", 18, 0xFFFFFF, true, false, false, null, null, "center", null, null, null, 2)
public function TimePanel(){
var size:int = 30
var shape:Shape = new Shape()
shape.graphics.beginFill(0, 0)
shape.graphics.drawRect(-size/2, -size/2, size, size)
shape.graphics.endFill()
//
_tx.defaultTextFormat = _fmt
_tx.selectable = false
_tx.width = size
_tx.height = size
_tx.x = -size/2
_tx.y = -size/3
//
addChild(shape)
addChild(_tx)
}
public function get tx():TextField{
return _tx;
}
}
// class MotionDetection
// 動体検知のアルゴリズム参考:http://faces.bascule.co.jp/motiondetection/
import flash.display.Sprite;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.display.Shape;
import flash.events.Event;
import flash.events.ActivityEvent;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.geom.Matrix;
import flash.filters.ConvolutionFilter;
import flash.media.Camera;
import flash.media.Video;
class MotionDetection extends Sprite {
private var _w:int
private var _h:int
//
private var _camera:Camera;
private var _video:Video;
private var _bmd:BitmapData;
private var _bm:Bitmap;
//
private var _currentBmd:BitmapData;
private var _beforeBmd:BitmapData;
private var _rect:Rectangle;
private var _mRect:Rectangle;
private var _pt:Point;
//
private var _threshold:uint = 0xFF555555;
private var _noiseReduction:ConvolutionFilter;
private var _noize_min_pix:uint = 0;
private var _inflateVar:uint = 10
private var _rects:Array = new Array();
//
public static const CAM_ACTIVE:String = "cam_active"
public static const CAM_DEACTIVE:String = "cam_deactive"
public function MotionDetection(w:int, h:int):void {
_w = w
_h = h
init();
}
private function init():void {
_camera = Camera.getCamera();
_camera.setMode(_w, _h, 15);
if (_camera != null) {
setupCamera();
_camera.addEventListener(ActivityEvent.ACTIVITY, CamActivityHandler);
}
_bmd = new BitmapData(_w, _h ,false, 0xffffff);
_bm = new Bitmap(_bmd);
var dObj:DisplayObject = addChild(_bm);
dObj.x = _w;
//
_currentBmd = new BitmapData(_w, _h);
_beforeBmd = new BitmapData(_w, _h);
_rect = new Rectangle(0, 0, _w, _h);
_pt = new Point(0,0);
//
_noiseReduction = new ConvolutionFilter();
_noiseReduction.matrixX = 3;
_noiseReduction.matrixY = 3;
_noiseReduction.matrix = [
1, 1, 1,
1, 0, 1,
1, 1, 1
];
_noiseReduction.bias = -0x100 * _noize_min_pix;
}
private function setupCamera():void {
_video = new Video(_w, _h);
_video.attachCamera(_camera);
_video.scaleX = -1;
_video.x = _w;
addChild(_video);
}
private function CamActivityHandler(e:ActivityEvent):void {
if (_camera.activityLevel > 30) {
dispatchEvent(new Event(MotionDetection.CAM_ACTIVE))
addEventListener(Event.ENTER_FRAME, update);
} else {
dispatchEvent(new Event(MotionDetection.CAM_DEACTIVE))
removeEventListener(Event.ENTER_FRAME, update);
}
}
private function update(e:Event):void {
make2tone();
rectForBlock();
}
private function make2tone():void {
_currentBmd.fillRect(_rect, 0xFFFFFFFF);
_currentBmd.draw(_video);
_currentBmd.draw(_beforeBmd, new Matrix(), new ColorTransform(), BlendMode.DIFFERENCE);
//
_currentBmd.threshold(_currentBmd, _rect, _pt, "<", _threshold, 0xFF000000);
_currentBmd.threshold(_currentBmd, _rect, _pt, "!=", 0xFF000000, 0xFFFFFFFF);
//
var _bm_noise:BitmapData = _currentBmd.clone();
_bm_noise.applyFilter(_bm_noise, _rect, _pt, _noiseReduction);
_currentBmd.threshold(_bm_noise, _rect, _pt, "==", 0xff000000, 0xff000000, 0xFF);
//
_beforeBmd.draw(_video);
//
_bmd.draw(_currentBmd);
_mRect = _bmd.getColorBoundsRect(0xffffff,0xffffff,true);
}
private function rectForBlock():void {
_rects = new Array();
while (true) {
var wbr:Rectangle = _bmd.getColorBoundsRect(0xFFFFFF,0xFFFFFF);
if (wbr.isEmpty()) {
break;
}
var x:Number = wbr.x;
for (var y:Number = wbr.y + wbr.height - 1; y >= wbr.y; --y) {
if (_bmd.getPixel(x,y) == 0xFFFFFF) {
_bmd.floodFill(x, y, 0xFF00FF);
var br:Rectangle = _bmd.getColorBoundsRect(0xFFFFFF,0xFF00FF);
br.inflate(_inflateVar,_inflateVar);
_bmd.fillRect(br,0x0000FF);
_rects.push(br);
break;
}
}
}
for (var idx:uint=0; idx<_rects.length; idx++) {
var idx_rec:Rectangle = _rects[idx];
for (var i:uint=idx+1; i<_rects.length; i++) {
var tgt_rec:Rectangle = _rects[i];
if (idx_rec != tgt_rec && idx_rec.intersects(tgt_rec)) {
_rects.push(idx_rec.union(tgt_rec));
_rects.splice(Number(i), 1);
_rects.splice(Number(idx), 1);
idx--;
break;
}
}
}
}
public function getPosition():Vector.<Rectangle> {
var rtList:Vector.<Rectangle> = new Vector.<Rectangle>()
if (_rects.length >= 1) {
for (var n:uint=0; n<_rects.length; n++) {
rtList.push(_rects[n])
}
}
return rtList
}
}