In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

被写体の移動方向推定

被写体の移動方向推定
カメラの中心に写っているものが、どの方向に動いているかを推定。

直前のフレームの中心の3x3ピクセルを、
次のフレームの中心付近の3x3ピクセル達と比較して、
一番近いものを取り出すことによって、
移動方向を推定している。
カメラの画像そのままだと、情報量が多すぎてなんもできないので、
ちょっとぼかして、色数を落として(rgb各色4段階)いる。

ゆっくり動かすぶんには、なんかそれっぽくなったような。

パターンマッチングによるカメラの移動方向推定
http://wonderfl.net/code/3095974b264ca9ab00750977c426c30df0b2d201
みたいに(たぶん)洗練された方法じゃなくて、
まずは、一番最初に思いつく方法で極単純化して自分なりに実装してみた。
各種フィルターを使うような最適化も全然していない。

色数をもうちょっと増やしたり、
最適化して、そのぶんパターンマッチングに
CPU資源を割り振ったりしたら、
もっと精度上がるかな。
/**
 * Copyright umhr ( http://wonderfl.net/user/umhr )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/cI8w
 */

/*
被写体の移動方向推定
カメラの中心に写っているものが、どの方向に動いているかを推定。

直前のフレームの中心の3x3ピクセルを、
次のフレームの中心付近の3x3ピクセル達と比較して、
一番近いものを取り出すことによって、
移動方向を推定している。
カメラの画像そのままだと、情報量が多すぎてなんもできないので、
ちょっとぼかして、色数を落として(rgb各色4段階)いる。

ゆっくり動かすぶんには、なんかそれっぽくなったような。

パターンマッチングによるカメラの移動方向推定
http://wonderfl.net/code/3095974b264ca9ab00750977c426c30df0b2d201
みたいに(たぶん)洗練された方法じゃなくて、
まずは、一番最初に思いつく方法で極単純化して自分なりに実装してみた。
各種フィルターを使うような最適化も全然していない。

色数をもうちょっと増やしたり、
最適化して、そのぶんパターンマッチングに
CPU資源を割り振ったりしたら、
もっと精度上がるかな。

*/
package {
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.*;
	import flash.media.Camera;
	import flash.media.Video;
	import flash.utils.Timer;
	
	public class CameraEx extends Sprite {
		
		private var video:Video;
		private var btn:Sprite;
		private var _bitmapProcess:BitmapProcess;
		
		public function CameraEx() {
			
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			
			// camera
			var camera:Camera = Camera.getCamera();
			
			if (camera != null) {
				video = new Video(160, 120);
				video.attachCamera(camera);
				addChild(video);
			} else {
				trace("You need a camera.");
			}
			
			
			_bitmapProcess = new BitmapProcess();
			_bitmapProcess.x = 160;
			this.addChild(_bitmapProcess);
			
						// button
						btn = new Sprite();
						btn.buttonMode = true
						btn.graphics.beginFill(0x333333);
						btn.graphics.drawRect(0,0,100,30);
						btn.y = 120 + 10;            
						addChild(btn);
						btn.addEventListener(MouseEvent.MOUSE_UP, btnUp);
			
			var timer:Timer = new Timer(100,9999);
			timer.addEventListener(TimerEvent.TIMER,onTime);
			timer.start();
		}
		private function onTime(e:TimerEvent):void {
			_bitmapProcess.setBitmap(video);
		}
		
				private function btnUp(e:MouseEvent):void {
					_bitmapProcess.setBitmap(video);
				}
	}
}

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.filters.BitmapFilter;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
import flash.filters.ConvolutionFilter;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.media.Video;

class BitmapProcess extends Sprite{
	private var _bitmap0:Bitmap;
	private var _bitmap1:Bitmap;
	private var _bitmap2:Bitmap;
	private var _bitmap3:Bitmap;
	private var _bitmap4:Bitmap;
	private var _bitmap5:Bitmap;
	private var _bitmapData0:BitmapData;
	private var _bitmapData1:BitmapData;
	private var _bitmapData2:BitmapData;
	private var _tempBitmapData:BitmapData;
	private var _arrow:Sprite;
	public function BitmapProcess(){
		_bitmapData0 = new BitmapData(160,120,false,0x000000);
		_bitmap0 = new Bitmap(_bitmapData0);
		_bitmap0.scaleX = _bitmap0.scaleY = 2;
		this.addChild(_bitmap0);
		
		_bitmapData1 = new BitmapData(160,120,false,0x000000);
		_bitmap1 = new Bitmap(_bitmapData1);
		_bitmap1.scaleX = _bitmap1.scaleY = 2;
		_bitmap1.y = 240;
		this.addChild(_bitmap1);
		
		_bitmapData2 = new BitmapData(160,120,false,0x000000);
		_bitmap2 = new Bitmap(_bitmapData2);
		_bitmap2.scaleX = _bitmap2.scaleY = 2;
		_bitmap2.y = 500;
		//this.addChild(_bitmap2);
		
		_bitmap3 = new Bitmap(new BitmapData(160,120,false,0x000000));
		_bitmap3.scaleX = _bitmap3.scaleY = 2;
		_bitmap3.x = 330;
		//this.addChild(_bitmap3);
		
		_bitmap5 = new Bitmap(new BitmapData(160,120,false,0x000000));
		_bitmap5.scaleX = _bitmap5.scaleY = 2;
		_bitmap5.x = 330;
		_bitmap5.y = 500;
		//this.addChild(_bitmap5);
		
		_arrow = new Sprite();
		_arrow.graphics.beginFill(0xFF0000,0.5);
		_arrow.graphics.moveTo(8,8);
		_arrow.graphics.lineTo(8,8);
		_arrow.graphics.lineTo(8,1);
		_arrow.graphics.lineTo(16,1);
		_arrow.graphics.lineTo(16,-1);
		_arrow.graphics.lineTo(8,-1);
		_arrow.graphics.lineTo(8,-8);
		_arrow.graphics.lineTo(0,0);
		_arrow.graphics.endFill();
		_arrow.x = _bitmap1.x + _bitmap1.width/2;
		_arrow.y = _bitmap1.y + _bitmap1.height/2;
		_arrow.visible = false;
		this.addChild(_arrow);
		
		_tempBitmapData = new BitmapData(160,120,false,0x000000);
	}
	public function setBitmap(video:Video):void{
		_bitmap0.bitmapData = _bitmap2.bitmapData.clone();
		_tempBitmapData.draw(video);
		_bitmap2.bitmapData = _tempBitmapData.clone();
		_bitmap2.bitmapData.applyFilter(_bitmap2.bitmapData,_bitmap2.bitmapData.rect,new Point(0,0),new BlurFilter(2,2));
		_bitmap2.bitmapData = posterization(_bitmap2.bitmapData);
		_bitmap1.bitmapData.draw(video);
		
		_bitmap3.bitmapData = _bitmap0.bitmapData.clone();
		_bitmap5.bitmapData = _bitmap2.bitmapData.clone();
		
		var colors3:Array = [];
		colors3[0] = _bitmap3.bitmapData.getPixel(79,59);
		colors3[1] = _bitmap3.bitmapData.getPixel(80,59);
		colors3[2] = _bitmap3.bitmapData.getPixel(81,59);
		colors3[3] = _bitmap3.bitmapData.getPixel(79,60);
		colors3[4] = _bitmap3.bitmapData.getPixel(80,60);
		colors3[5] = _bitmap3.bitmapData.getPixel(81,60);
		colors3[6] = _bitmap3.bitmapData.getPixel(79,61);
		colors3[7] = _bitmap3.bitmapData.getPixel(80,61);
		colors3[8] = _bitmap3.bitmapData.getPixel(81,61);
		
		
		var colors5:Array = [9];
		var nears:Array = [];
		var focus:Array = [[0,0],[1,0],[0,1],[-1,0],[0,-1],[1,1],[-1,1],[-1,-1],[1,-1],
		[2,0],[0,2],[-2,0],[0,-2],[2,1],[1,2],[-1,2],[-2,1],[-2,-1],[-1,-2],[1,-2],[2,-1],[2,2],[-2,2],[-2,-2],[2,-2],
		[3,0],[0,3],[-3,0],[0,-3],[3,1],[3,2],[2,3],[1,3],[-1,3],[-2,3],[-3,2],[-3,1],[-3,-1],[-3,-2],
		[-2,-3],[-1,-3],[1,-3],[2,-3],[3,-2],[3,-1],[3,3],[-3,3],[-3,-3],[3,-3]];
		var score:int;
		for (var i:int = 0; i < focus.length; i++) {
				var tx:int = 79+focus[i][0];
				var ty:int = 59+focus[i][1];
				colors5[0] = _bitmap5.bitmapData.getPixel(tx,ty);
				colors5[1] = _bitmap5.bitmapData.getPixel(tx+1,ty);
				colors5[2] = _bitmap5.bitmapData.getPixel(tx+2,ty);
				colors5[3] = _bitmap5.bitmapData.getPixel(tx,ty+1);
				colors5[4] = _bitmap5.bitmapData.getPixel(tx+1,ty+1);
				colors5[5] = _bitmap5.bitmapData.getPixel(tx+2,ty+1);
				colors5[6] = _bitmap5.bitmapData.getPixel(tx,ty+2);
				colors5[7] = _bitmap5.bitmapData.getPixel(tx+1,ty+2);
				colors5[8] = _bitmap5.bitmapData.getPixel(tx+2,ty+2);
				score = nearArray(colors3,colors5);
				nears.push(score);
				if(score == 0){
					break;
				}
		}
		
		var nearPoz:int = nears.sort(Array.RETURNINDEXEDARRAY|Array.NUMERIC)[0];
//		_bitmap3.bitmapData.lock();
//		_bitmap3.bitmapData.setPixel(78,58,0xFF0000);
//		_bitmap3.bitmapData.setPixel(82,58,0xFF0000);
//		_bitmap3.bitmapData.setPixel(78,62,0xFF0000);
//		_bitmap3.bitmapData.setPixel(82,62,0xFF0000);
//		_bitmap3.bitmapData.unlock();
//		
//		_bitmap5.bitmapData.lock();
//		_bitmap5.bitmapData.setPixel(78,58,0xFF0000);
//		_bitmap5.bitmapData.setPixel(82,58,0xFF0000);
//		_bitmap5.bitmapData.setPixel(78,62,0xFF0000);
//		_bitmap5.bitmapData.setPixel(82,62,0xFF0000);
		if(nears[nearPoz] < 9 && nearPoz !=0){
//			_bitmap5.bitmapData.setPixel(focus[nearPoz][0]+79+1,focus[nearPoz][1]+59+1,0x0000FF);
			_arrow.visible = true;
			_arrow.rotation = Math.atan2(focus[nearPoz][1],focus[nearPoz][0])*180/Math.PI+180;
		}else{
			_arrow.visible = false;
		}
//		_bitmap5.bitmapData.unlock();
		
	}
	private function nearArray(a:Array,b:Array):int
	{
		var score:int = 0;
		for (var i:int = 0; i < 9; i++) {
			score += near(a[i],b[i]);
		}
		return score;
	}
	private function near(rgb1:uint,rgb2:uint):int
	{
		var r1:int = rgb1 >> 16 & 0xFF;
		var g1:int = rgb1 >> 8 & 0xFF;
		var b1:int = rgb1 & 0xFF;
		var r2:int = rgb2 >> 16 & 0xFF;
		var g2:int = rgb2 >> 8 & 0xFF;
		var b2:int = rgb2 & 0xFF;
		return Math.abs(r1-r2)/64+Math.abs(g1-g2)/64+Math.abs(b1-b2)/64;
	}
	
	private function outline(bd:BitmapData):BitmapData
	{
		var matrix:Array = [ -30, 30,  0,
			-30,  30, 0,
			-30, 30,  0];
		var filter:BitmapFilter = new ConvolutionFilter(3,3, matrix, 9);
		var filters:Array = [];
		bd.applyFilter(bd,bd.rect, new Point(0, 0), filter)
		return bd;
	}
	
	public function posterization(bitmapData:BitmapData):BitmapData{
		var n:int = bitmapData.height;
		var m:int = bitmapData.width;
		for (var i:int = 0; i < n; i++) {
			for (var j:int = 0; j < m; j++) {
				var rgb:uint = bitmapData.getPixel(j,i);
				var r:int = rgb >> 16 & 0xFF;
				var g:int = rgb >> 8 & 0xFF;
				var b:int = rgb & 0xFF;
				r = Math.floor(r/64)*64;
				g = Math.floor(g/64)*64;
				b = Math.floor(b/64)*64;
				bitmapData.setPixel(j,i,r*256*256+g*256+b);
			}
		}
		return bitmapData;
	}
	public function getGray(rgb:uint):int{
		var r:int = rgb >> 16 & 0xFF;
		var g:int = rgb >> 8 & 0xFF;
		var b:int = rgb & 0xFF;
		return (r+g+b)/3;
	}
}