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

[WebCam] NeonMan

[WebCam] NeonMan
@author Aquioux(Yoshida, Akio)
/**
 * Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/1ywN
 */

package {
	import flash.display.Sprite;
	import net.hires.debug.Stats;
	[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#FFFFFF")]
	/**
	 * [WebCam] NeonMan
	 * @author Aquioux(Yoshida, Akio)
	 */
	public class Main extends Sprite {
		
		public function Main():void {
			Wonderfl.capture_delay(20);

			// model
			try {
				var model:Model = new Model(stage);
			} catch (err:Error) {
				trace(err.message);
				return;
			}
			
			// view
			var view:View = new View(model);
			addChild(view);
			
			// controller
			var controller:Controller = new Controller(model);
			addChild(controller);
			
			//addChild(new Stats());
		}
	}
}


	import flash.display.BitmapData;
	import flash.display.Stage;
	import flash.events.ActivityEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.media.Camera;
	import flash.media.Video;
	/**
	 * Model
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class Model extends EventDispatcher {
		// ---------- パブリックプロパティ ----------
		//
		// View へ渡すデータ
		public function get data():BitmapData { return _data; }
		private var _data:BitmapData;

		
		// ---------- ローカルプロパティ ----------
		//
		private var stage_:Stage;
		private var cameraWidth_:uint;
		private var cameraHeight_:uint;
		private var camera_:Camera;
		private var video_:Video;
		private var matrix_:Matrix;

		// 各エフェクタ
		private var smooth_:Smooth;
		private var posterize_:Posterize;
		private var effector_:Effector;
		
		private const STRENGTH_MAX:uint = 16;
		private var ratio:uint;
		

		// ---------- パブリックメソッド ----------
		//
		/**
		 * コンストラクタ
		 * @param	stage	ステージ
		 * @param	cw		カメラ幅(省略時はステージ幅)
		 * @param	ch		カメラ高(省略時はステージ高)
		 */
		public function Model(stage:Stage, cw:uint = 0, ch:uint = 0) {
			// 引数の処理
			stage_ = stage;
			var w:uint = stage_.stageWidth;
			var h:uint = stage_.stageHeight;
			cameraWidth_  = (cw == 0) ? w : cw;
			cameraHeight_ = (ch == 0) ? h : ch;

			// View へ渡すデータの生成
			_data = new BitmapData(w, h, true, 0x00000000);
			
			// 鏡像になるよう、Matrix で左右反転
			var tx:uint = (w - cameraWidth_)  / 2 + cameraWidth_;
			var ty:uint = (h - cameraHeight_) / 2;
			matrix_ = new Matrix( -1, 0, 0, 1, tx, ty);
			
			// カメラ準備
			camera_ = Camera.getCamera();
			if (camera_) {
				// camera のセットアップ
				camera_.setMode(cameraWidth_, cameraHeight_, stage_.frameRate);
				// video のセットアップ
				video_ = new Video(cameraWidth_, cameraHeight_);
				video_.attachCamera(camera_);
				// カメラがアクティブになるまで待つ
				camera_.addEventListener(ActivityEvent.ACTIVITY, activeHandler);
			} else {
				throw new Error("カメラがありません。");
			}
			
			ratio = w / (STRENGTH_MAX - 1);

			// エフェクタ
			smooth_ = new Smooth();
			smooth_.strength = 16;
			posterize_ = new Posterize();
			posterize_.degree = 2;
			effector_ = new Effector();
		}
		
		/**
		 * isNegative_ の切り替え
		 * Controller とのインターフェース
		 */
		public function notifyFromController(value:Number):void {
			var strength:uint = value / ratio + 2;
			smooth_.strength = strength;
		}
		
		
		// ---------- ローカルメソッド ----------
		//
		// ACTIVITY イベントハンドラ
		private function activeHandler(e:ActivityEvent):void {
			camera_.removeEventListener(ActivityEvent.ACTIVITY, arguments.callee);
			stage_.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
		// ENTER_FRAME イベントハンドラ
		private function enterFrameHandler(event:Event):void {
			_data.draw(video_, matrix_);
			
			smooth_.applyEffect(_data);		// 平滑化
			posterize_.applyEffect(_data);
			effector_.applyEffect(_data);

			dispatchEvent(new Event(Event.CHANGE));
		}
	}


	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	/**
	 * View
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class View extends Bitmap {
		// ---------- パブリックプロパティ ----------
		//
		// Model の参照
		public function set model(value:Model):void { _model = value; }
		private var _model:Model;
		
		
		// ---------- パブリックメソッド ----------
		//
		/**
		 * コンストラクタ
		 * @param	model	Model
		 */
		public function View(model:Model) {
			_model = model;
			_model.addEventListener(Event.CHANGE, changeHandler);
		}
		

		// ---------- ローカルメソッド ----------
		//
		// Model から Event.CHANGE が発行されたときの処理
		private function changeHandler(e:Event):void {
			bitmapData = _model.data;
		}
	}


	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	/**
	 * Controller
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class Controller extends Sprite {
		// ---------- パブリックプロパティ ----------
		//
		// Model の参照
		public function set model(value:Model):void { _model = value; }
		private var _model:Model;
		

		// ---------- パブリックメソッド ----------
		//
		/**
		 * コンストラクタ
		 * @param	model	Model
		 */
		public function Controller(model:Model) {
			_model = model;
			addEventListener(Event.ADDED_TO_STAGE, addToStageHandler);
		}
		

		// ---------- ローカルメソッド ----------
		//
		// イベントハンドラ
		// 自分がステージに登録されたとき
		private function addToStageHandler(e:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, arguments.callee);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
		}
		
		// イベントハンドラ
		private function moveHandler(e:MouseEvent):void {
			_model.notifyFromController(mouseX);
		}
	}




	import flash.display.BitmapData;
	/**
	 * BitmapDataEffector 用 interface
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	interface IEffector {
		function applyEffect(value:BitmapData):BitmapData;
	}


	import flash.geom.Point;
	/**
	 * bitmapDataEffector パッケージ内のクラスで共通に使う定数など
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class EffectorUtils {
		// ---------- パブリックプロパティ ----------
		//
		// BitmapData が備える各種メソッドの destPoint 用
		static public const ZERO_POINT:Point = new Point(0, 0);

		
		// ---------- パブリックメソッド ----------
		//
		// 一つのチャンネルにおける濃度の平均値を求める(引数のヒストグラムで調整する)
		static public function getAverageOfBrightness1(hist:Vector.<Number>):uint {
			var sum:uint = 0;
			var numOfPixel:uint = 0;
			for (var i:int = 0; i < 256; i++) {
				sum        += i * hist[i];
				numOfPixel += hist[i];
			}
			return sum / numOfPixel >> 0;
		}
		// RGB チャンネルにおける濃度の各平均値を求める
		static public function getAverageOfBrightness3(hist:Vector.<Vector.<Number>>):Vector.<uint> {
			var rSum:uint = 0;
			var gSum:uint = 0;
			var bSum:uint = 0;
			var numOfPixel:uint = 0;
			for (var i:int = 0; i < 256; i++) {
				rSum += i * hist[0][i];
				gSum += i * hist[1][i];
				bSum += i * hist[2][i];
				numOfPixel += hist[0];
			}
			return Vector.<uint>([rSum / numOfPixel >> 0, gSum / numOfPixel >> 0, bSum / numOfPixel >> 0]);
		}
		
		// 一つのチャンネルにおける濃度の平均値を求める(引数のヒストグラムで調整する)
		static public function getSumOfBrightness1(hist:Vector.<Number>):uint {
			var sum:uint = 0;
			for (var i:int = 0; i < 256; i++) {
				sum += i * hist[i];
			}
			return sum;
		}
		// RGB チャンネルにおける濃度の各平均値を求める
		static public function getSumOfBrightness3(hist:Vector.<Vector.<Number>>):Vector.<uint> {
			var rSum:uint = 0;
			var gSum:uint = 0;
			var bSum:uint = 0;
			for (var i:int = 0; i < 256; i++) {
				rSum += i * hist[0][i];
				gSum += i * hist[1][i];
				bSum += i * hist[2][i];
			}
			return Vector.<uint>([rSum, gSum, bSum]);
		}
	}


	import flash.display.BitmapData;
	import flash.display.BitmapDataChannel;
	import flash.filters.ConvolutionFilter;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	/**
	 * 今回のメインエフェクタ
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class Effector implements IEffector {
		// ---------- ローカルプロパティ ----------
		//
		private var bufferBmd_:BitmapData;
		private var rBmd_:BitmapData;
		private var gBmd_:BitmapData;
		private var bBmd_:BitmapData;
		
		private var rect_:Rectangle;
		
		private var edge_:Edge2 = new Edge2();
		
		private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
		

		
		// ---------- パブリックメソッド ----------
		//
		/*
		 * 効果適用
		 * @param	value	効果対象 BitmapData
		 */
		public function applyEffect(value:BitmapData):BitmapData {
			if (!rBmd_) {
				rBmd_ = new BitmapData(value.width, value.height, false, 0x000000);
				gBmd_ = rBmd_.clone();
				bBmd_ = rBmd_.clone();
				rect_ = value.rect;
			}
			
			rBmd_.copyChannel(value, rect_, ZERO_POINT, BitmapDataChannel.RED, BitmapDataChannel.RED);
			gBmd_.copyChannel(value, rect_, ZERO_POINT, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
			bBmd_.copyChannel(value, rect_, ZERO_POINT, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
			
			edge_.applyEffect(rBmd_);
			edge_.applyEffect(gBmd_);
			edge_.applyEffect(bBmd_);

			value.fillRect(value.rect, 0xFF000000);
			
			value.copyChannel(rBmd_, rBmd_.rect, ZERO_POINT, BitmapDataChannel.RED, BitmapDataChannel.RED);
			value.copyChannel(gBmd_, gBmd_.rect, ZERO_POINT, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
			value.copyChannel(bBmd_, bBmd_.rect, ZERO_POINT, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
			
			return value;
		}
	}


	import flash.display.BitmapData;
	import flash.filters.BitmapFilterQuality;
	import flash.filters.BlurFilter;
	import flash.geom.Point;
	/**
	 * BlurFilter による平滑化
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class Smooth implements IEffector {
		// ---------- パブリックプロパティ ----------
		//
		/*
		 * ぼかしの強さ
		 * @param	value	数値
		 */
		public function set strength(value:Number):void {
			filter_.blurX = filter_.blurY = value;
		}
		/*
		 * ぼかしの質
		 * @param	value	数値
		 */
		public function set quality(value:int):void {
			filter_.quality = value;
		}


		// ---------- ローカルプロパティ ----------
		//
		private var filter_:BlurFilter;		// ブラーフィルタ
		private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;


		// ---------- パブリックメソッド ----------
		//
		/*
		 * コンストラクタ
		 */
		public function Smooth() {
			filter_ = new BlurFilter(2, 2, BitmapFilterQuality.MEDIUM);
		}
		
		/*
		 * 効果適用
		 * @param	value	効果対象 BitmapData
		 */
		public function applyEffect(value:BitmapData):BitmapData {
			value.applyFilter(value, value.rect, ZERO_POINT, filter_);
			return value;
		}
	}


	import flash.display.BitmapData;
	import flash.geom.Point;
	/**
	 * paletteMap による BitmapData の減色
	 * 参考:「実践画像処理入門」 培風館 内村圭一・上瀧剛 P16 「2.5 濃度値の量子化による減色処理」
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class Posterize implements IEffector {
		// ---------- パブリックプロパティ ----------
		//
		/*
		 * 減色の段階
		 * @param	value	段階
		 */
		public function set degree(value:uint):void {
			// value の有効範囲は 2 ~ 256
			if (value <   2) value =   2;
			if (value > 256) value = 256;

			for (var i:int = 0; i < 256; i++) {
				var val:uint = uint(i / (256 / value)) * 255 / (value - 1);
				rArray_[i] = val << 16;
				gArray_[i] = val <<  8;
				bArray_[i] = val;
			}
		}


		// ---------- ローカルプロパティ ----------
		//
		// paletteMap の引数となる各 Channel 用の Array
		private var rArray_:Array = [];
		private var gArray_:Array = [];
		private var bArray_:Array = [];

		private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;

		
		// ---------- パブリックメソッド ----------
		//
		/*
		 * コンストラクタ
		 */
		public function Posterize() {
			degree = 8;	// degree のデフォルト
		}
		
		/*
		 * 効果適用
		 * @param	value	効果対象 BitmapData
		 */
		public function applyEffect(value:BitmapData):BitmapData {
			value.paletteMap(value, value.rect, ZERO_POINT, rArray_, gArray_, bArray_);
			return value;
		}
	}


	import flash.display.BitmapData;
	import flash.filters.ConvolutionFilter;
	import flash.geom.Point;
	/**
	 * ConvolutionFilter によるエッジ検出 2次微分
	 * 「OpenGL+GLSLによる画像処理プログラミング」 工学社 酒井幸市 P104 「5.1 差分フィルタ」
	 * 「C言語で学ぶ実践画像処理」 オーム社 井上誠喜・他 P47 「4.7 ラプラシアンとゼロ交差により輪郭線を求める」
	 * http://msdn.microsoft.com/ja-jp/academic/cc998604.aspx
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class Edge2 implements IEffector {
		// ---------- ローカルプロパティ ----------
		//
		private const MATRIX:Array = [
			-1, -1, -1,
			-1,  8, -1,
			-1, -1, -1
		];
		private const FILTER:ConvolutionFilter = new ConvolutionFilter(3, 3, MATRIX);

		private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;

		
		// ---------- パブリックメソッド ----------
		//
		/*
		 * 効果適用
		 * @param	value	効果対象 BitmapData
		 */
		public function applyEffect(value:BitmapData):BitmapData {
			value.applyFilter(value, value.rect, ZERO_POINT, FILTER);
			return value;
		}
	}