眠れないからWebcamAsciify改良(悪)【エッジ検出】

WebcamAsciifyEdg.html ← この顔ムカツク
http://n00dle.web.fc2.com/webcamasciifyedg.html


前回の"WebcamAsciify.as"をスコープ中心に修正して、サブクラスを書いた。Webカメラの画像をエッジ検出してからアスキー文字に置き換えている。だいぶ被写体が認識し易くなった。反面、出現するアスキー文字が少なくなってアスキーアートの面白みがなくなっている。
エッジ検出した段階の画像は以下(を白黒反転させたもの)のようになっているわけだ。


AS3 Video Edge and Motion Detector

AS3 Video Edge and Motion Detect

http://www.laserpirate.com/as3edgeandmotion/

参考

  • AS3で画像処理入門(1) - flashrod

http://d.hatena.ne.jp/flashrod/20061015#1160910969
グレースケール化とエッジ検出はまんまここから。とりあえずコード読みながら仕組みを考えてみる。"ラプラシアン 2 を用いた2 次微分"??んががが…


ソースは以下

WebcamAsciifyEdg.as -> WebcamAsciify.as

WebcamAsciifyEdg.as

package {
	import flash.display.*;
	import flash.events.*;
	import flash.filters.*;
	import flash.geom.*;
	import flash.media.*;
	import flash.text.*;
	
	[SWF(backgroundColor = "0x000000", frameRate = "30")]
	public class WebcamAsciifyEdg extends WebcamAsciify
	{		
		public function WebcamAsciifyEdg()
		{	
		}
		 
		override public function entKey(event:KeyboardEvent):void
		{
			swit = swit; //スイッチ無効化
		}
		
		override public function tick(event:Event):void
		{
			
			textField.text = "";
			var output:String = "";
			
			bd = new BitmapData(picW, picH);
			bd.draw(video, matrix);
			
			bd = edge(bd).clone();
			
			pixels = new Array();
			
			for (var y:uint = 0; y < picH; y++) {
				var row:Array=new Array();
				for (var x:uint = 0; x < picW; x++) {
					var sampledColor:Number=bd.getPixel(x, y);
					row.push(sampledColor);
				}
				pixels.push(row);
			}
			
			for (var y:uint = 0; y < picH; y++) {
				for (var x:uint = 0; x < picW; x++) {
					var color:Number=pixels[y][x];
					var rgb:Object=makeRgb(color);
					var avg:Number=(rgb.r + rgb.g + rgb.b)/3;
					var s:String = getCharFromColor(avg);
					output += s + s + s + s;
				}
				output+="\n\n";
			}
			
			textField.appendText(output);
		}
		
		private function edge(bitmapData:BitmapData):BitmapData
		{
			var d:BitmapData = new BitmapData(bitmapData.width, bitmapData.height);
			var rec:Rectangle = new Rectangle(0, 0, bitmapData.width, bitmapData.height);
			var point:Point = new Point(0, 0);
			
			//グレースケール化
			d.applyFilter(bitmapData, rec, point,
			new ColorMatrixFilter([1/3, 1/3, 1/3, 0, 0,
						1/3, 1/3, 1/3, 0, 0,
						1/3, 1/3, 1/3, 0, 0,
						0, 0, 0, 255, 0]));
			//エッジ検出
			var l:Array = [-1, -1, -1,
					-1, +8, -1,
					-1, -1, -1];
			d.applyFilter(bitmapData, rec, point,new ConvolutionFilter(3, 3, l));
			
			return d;
		}
	}
}


WebcamAsciify.as

package {
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.media.*;
	import flash.text.*;
	
	[SWF(backgroundColor = "0x000000", frameRate = "30")]

	public class WebcamAsciify extends Sprite
	{
		public var video:Video;
		public var textField:TextField;
		public var textFormat:TextFormat;
		public var bd:BitmapData;
		public var picW:uint;
		public var picH:uint;
		public var matrix:Matrix;
		public var pixels:Array;
		public var asciiArray:Array;
		public var swit:Boolean;
		
		public static const
		videoWidth:int = 320,
		videoHeight:int = 240,
		pixelSize:Number =5;
		
		public function WebcamAsciify()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			
			swit = new Boolean (true);
			
			textFormat = new TextFormat();
			textFormat.size = 6;
			textFormat.color = 0x00ff00;
			textFormat.font = "Courier New"
			
			sampleChars(); //Ascii文字テーブル生成
			
			//Webカメラのビデオサイズを縮小して処理するための変数設定
			picW = videoWidth / pixelSize;
			picH = videoHeight / pixelSize;
			matrix = new Matrix();
			matrix.scale(1/pixelSize, 1/pixelSize);
			
			var camera : Camera = Camera.getCamera();
			video = new Video(videoWidth, videoHeight);
			video.attachCamera(camera);
						
			textField = new TextField();
			textField.autoSize = "left";
			textField.selectable = false;
			textField.defaultTextFormat = textFormat;
			textField.antiAliasType=AntiAliasType.ADVANCED;
			
			addChild(textField);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, entKey);
			addEventListener(Event.ENTER_FRAME, tick);
		}
		
		public function entKey(event:KeyboardEvent):void
		{
			swit = !(swit);
		}
		
		//メインループ
		public function tick(event:Event):void
		{
			textField.text = "";
			var output:String = "";
			
			bd = new BitmapData(picW, picH);
			bd.draw(video, matrix);
			
			pixels = new Array();
			
			for (var y:uint = 0; y < picH; y++) {
				var row:Array=new Array();
				for (var x:uint = 0; x < picW; x++) {
					var sampledColor:Number=bd.getPixel(x, y);
					row.push(sampledColor);
				}
				pixels.push(row);
			}
			
			for (var y:uint = 0; y < picH; y++) {
				for (var x:uint = 0; x < picW; x++) {
					var color:Number=pixels[y][x];
					var rgb:Object=makeRgb(color);
					var avg:Number=(rgb.r + rgb.g + rgb.b)/3;
					var s:String = getCharFromColor(avg);
					output += s + s + s + s;
				}
				output+="\n\n";
			}
			
			textField.appendText(output);
		}
		
		private function sampleChars():void 
		{
			asciiArray = new Array();
			var list:String = " .,;-~_+<>i!lI?/|)(1}{][rcvunxzjftLCJUYXZO0Qoahkbdpqwm*WMB8&%$#@";
			asciiArray = list.split("");
		}
		
		public function makeRgb(hex:Number):Object
		{
			var r:Number;
			var g:Number;
			var b:Number;
			r = (0xFF0000 & hex) >> 16;
			g = (0x00FF00 & hex) >> 8;
			b = (0x0000FF & hex);
			return {r:r,g:g,b:b};
		}
		
		public function getCharFromColor(arg:uint):String
		{
			var i:uint=0;
			var _char:String;
			
			//"A"か" "で表現
			if (swit == false) {
				if ( arg < Math.floor(256/3) ) {
					_char = "A";
				} else {
				_char = " ";
				}
			}
			
			//複数のAscii文字で表現
			if (swit == true) {
				for (var col:Number = 0; col < 256; col += Math.floor(256/asciiArray.length) ) {
					if (arg<=col) {
						_char = asciiArray[i];
					} else {
					i++;
					}
				}
			}
			return _char;
		}
	}
}