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

似而非キャニーエッジ

似而非キャニーエッジ Fake canny edge
解説:http://aquioux.blog48.fc2.com/blog-entry-693.html
@author YOSHIDA, Akio (Aquioux)
/**
 * Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/7GCV
 */

package {
	import com.bit101.components.Label;
	import com.bit101.components.Slider;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.ColorTransform;
	/**
	 * 似而非キャニーエッジ Fake canny edge
	 * 解説:http://aquioux.blog48.fc2.com/blog-entry-693.html
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#000000")]
	
	public class Main extends Sprite {
		
		private var smoothing:EffectorSmoothing;
		private var binarization:EffectorBinarization;

		private var sliderBinarization:Slider;
		private var labelBinarization:Label;
		private var prevThreshold:Number;
		
		private var sliderSmoothing:Slider;
		private var labelSmoothing:Label;
		private var prevSmooth:Number;
		
		public function Main() {
			Wonderfl.capture_delay(20);

			// エフェクタ連鎖
			var chain:ChainEffectors = new ChainEffectors();
			smoothing    = new EffectorSmoothing();
			binarization = new EffectorBinarization();
			chain.addEffector(smoothing);
			chain.addEffector(binarization);
			chain.addEffector(new EffectorEdge());
		
			// 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 1
			var min:uint = 0;
			var max:uint = 255;
			sliderBinarization = new Slider(Slider.HORIZONTAL, this, 0, 0, sliderBinarizationHandler);
			sliderBinarization.width = 200;
			sliderBinarization.setSliderParams(min, max, uint(max / 2));
			labelBinarization = new Label(this, sliderBinarization.width + 3, sliderBinarization.y - 3);
			labelBinarization.transform.colorTransform = new ColorTransform(0, 0, 0, 1, 255);
			sliderBinarizationHandler(null);
			
			// Controller 2
			min = 0;
			max = 16;
			sliderSmoothing	= new Slider(Slider.HORIZONTAL, this, 0, sliderBinarization.height + 5, sliderSmoothingHandler);
			sliderSmoothing.width = 200;
			sliderSmoothing.setSliderParams(min, max, 2);
			labelSmoothing = new Label(this, sliderSmoothing.width + 3, sliderSmoothing.y - 3);
			labelSmoothing.transform.colorTransform = new ColorTransform(0, 0, 0, 1, 255);
			sliderSmoothingHandler(null);
			
			// 開始
			model.chain = chain;
			model.start();
		}
		
		private function sliderBinarizationHandler(event:Event):void{
			var value:uint = (event) ? event.target.value : sliderBinarization.value;
			labelBinarization.text = "Threaold : " + String(value);
			
			if (prevThreshold != value) {
				binarization.threshold = value;
				prevThreshold = value;
			}
		}
		private function sliderSmoothingHandler(event:Event):void{
			var value:uint = (event) ? event.target.value : sliderSmoothing.value;
			labelSmoothing.text = "Smooth strength : " + String(value);
			
			if (prevSmooth != value) {
				smoothing.strength = value;
				prevSmooth = value;
			}
		}
	}
}


	import flash.display.BitmapData;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.Matrix;
	import flash.media.Camera;
	import flash.media.Video;
	/**
	 * Web Camera の映像にエフェクトをかける(MVC の Model)
	 * エフェクトロジックは effector クラスとして外部で定義する
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class Model extends EventDispatcher {
		// --------------------------------------------------
		// View へ渡すデータ(プロパティ)
		// --------------------------------------------------
		/**
		 * 加工済みのカメラ画像
		 */
		public function get data():BitmapData { return _data; }
		private var _data:BitmapData;
		
		// --------------------------------------------------
		// 外部から受け取るデータ(プロパティ)
		// --------------------------------------------------
		/**
		 * エフェクタ連鎖
		 */
		public function set chain(value:ChainEffectors):void {
			_chain = value;
		}
		private var _chain:ChainEffectors;
		
		// --------------------------------------------------
		// 外部との通信をおこなうメソッド
		// --------------------------------------------------
		/**
		 * 対 View 用メソッド
		 * このメソッドの終了時にイベントを発行するので、View との通信手段となる
		 * @private
		 */
		private function update():void {
			_data.draw(video, matrix);
			_data = _chain.applyEffect(_data);
			dispatchEvent(new Event(Event.CHANGE));
		}
		
		// --------------------------------------------------
		// その他のメソッド
		// --------------------------------------------------
		/**
		 * コンストラクタ
		 * コンストラクタの引数はステージとする。各種データはアクセサーによって取り込むものとする
		 * @param	stage	ステージ
		 */
		private var stage:Stage;

		// カメラが表示するサイズ
		private var cameraWidth:uint;
		private var cameraHeight:uint;
		// カメラ
		private var camera:Camera;
		private var video:Video;
		private var matrix:Matrix;
		public function Model(stage:Stage, cw:Number = 0, ch:Number = 0) {
			this.stage = stage;
			this.cameraWidth  = (cw == 0) ? stage.stageWidth  : cw;
			this.cameraHeight = (ch == 0) ? stage.stageHeight : ch;
			
			_data = new BitmapData(cameraWidth, cameraHeight, false);
			matrix = new Matrix( -1, 0, 0, 1, cameraWidth, 0);
			
			// カメラ
			camera = Camera.getCamera();
			if (camera) {
				// camera のセットアップ
				camera.setMode(cameraWidth, cameraHeight, stage.frameRate);
				// video のセットアップ
				video = new Video(cameraWidth, cameraHeight);
				video.attachCamera(camera);
			} else {
				throw new Error("カメラがありません。");
			}
		}
		
		/**
		 * 処理開始
		 * Event.ENTER_FRAME を使う場合、このメソッドを設定する。
		 * Controller から通知されるイベントだけで処理する場合、このメソッドは不要。
		 */
		public function start():void {
			stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
		/**
		 * イベントハンドラ
		 * @private
		 */
		private function enterFrameHandler(event:Event):void {
			update();
		}
	}


	import flash.display.Bitmap;
	import flash.events.Event;
	/**
	 * Web Camera のスクリーン(MVC の View)
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class View extends Bitmap {
		/**
		 * コンストラクタ
		 * @param	model	Model
		 */
		private var model:Model;
		public function View(model:Model) {
			this.model = model;
			this.model.addEventListener(Event.CHANGE, changeHandler);
		}
		
		/**
		 * Model との通信手段
		 * @param	event	発生したイベント
		 */
		private function changeHandler(event:Event):void {
			// Model からデータを受け取り、視覚化
			this.bitmapData = model.data;
		}
	}


	import flash.display.BitmapData;
	/**
	 * エフェクタ連鎖
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class ChainEffectors {
		private var effectors:Array = [];
	
		/**
		 * コンストラクタ
		 * @param	model	Model
		 */
		public function ChainEffectors() {
		}
		
		/**
		 * エフェクタの追加
		 * @param	effector	エフェクタ
		 */
		public function addEffector(effector:AbstractEffector):void {
			effectors.push(effector);
		}
		
		/**
		 * エフェクタの適用
		 * @param	value	エフェクタをかける BitmapData
		 */
		public function applyEffect(value:BitmapData):BitmapData {
			var n:uint = effectors.length;
			for(var i:int=0; i < n; i++){
				var effector:AbstractEffector = effectors[i];
				value = effector.applyEffect(value);
			}
			return value;
		}
	}


	import flash.display.BitmapData;
	import flash.geom.Point;
	/**
	 * BitmapData エフェクト用抽象クラス
	 * @author YOSHIDA, Akio
	 */
	class AbstractEffector {
		/*
		 * BitmapData.applyFilter で destPoint として使用する Point オブジェクト
		 */
		protected const ZERO_POINT:Point = new Point(0, 0);
		
		/*
		 * コンストラクタ
		 */
		public function AbstractEffector() {}
		
		/*
		 * 効果の適用
		 * @param	value	効果をかける BitmapData
		 */
		public function applyEffect(value:BitmapData):BitmapData {
			return effect(value);
		}
		
		/*
		 * 効果内容、具体的なコードはサブクラスで定義する
		 * @param	value	効果をかける BitmapData
		 */
		protected function effect(value:BitmapData):BitmapData {
			return value;
		}
	}


	import flash.display.BitmapData;
	import flash.geom.Rectangle;
	/**
	 * 二値化
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class EffectorBinarization extends AbstractEffector {
		public function set threshold(value:int):void {
			if (value < 0)   value = 0;
			if (value > 255) value = 255;
			_threshold = value;
		}
		private var _threshold:int = 127;	// 閾値:0 ~ 255
		
		private var cloneBitmapData:BitmapData;	// 一時処理用 BitmapData
		private var rect:Rectangle;
		
		/*
		 * 二値化実行
		 * @param	value	効果をかける BitmapData
		 */
		override protected function effect(value:BitmapData):BitmapData {
			if (cloneBitmapData) cloneBitmapData.dispose();
			cloneBitmapData = new BitmapData(value.width, value.height);
			cloneBitmapData = value.clone();
			rect = cloneBitmapData.rect;
			value.fillRect(rect, 0xFF000000);
			value.threshold(cloneBitmapData, rect, ZERO_POINT, ">", _threshold, 0xFFFFFFFF, 0x000000FF, false);
			return value;
		}
	}


	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.filters.ConvolutionFilter;
	import flash.geom.Rectangle;
	/**
	 * エッジ検出(ラプラシアン・オペレータ)
	 * 参考: 「OpenGL+GLSLによる画像処理プログラミング」 工学社 酒井幸市 P107 「5.1.2 エッジ検出フィルタ」
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class EffectorEdge extends AbstractEffector {
		// ConvolutionFilter のマトリクス(ラプラシアン)
		private var laplacian:Array = [
			0,  1, 0,
			1, -4, 1,
			0,  1, 0
		];

		/*
		 * エッジ検出実行
		 * @param	value	効果をかける BitmapData
		 */
		override protected function effect(value:BitmapData):BitmapData {
			value.applyFilter(value, value.rect, ZERO_POINT, new ConvolutionFilter(3, 3, laplacian));
			return value;
		}
	}


	import flash.display.BitmapData;
	import flash.filters.ColorMatrixFilter;
	/**
	 * ColorMatrixFilter による BitmapData のグレイスケール化(NTSC 系加重平均による)
	 * 参考:Foundation ActionScript 3.0 Image Effects(P106)
	 * 		http://www.amazon.co.jp/gp/product/1430218711?ie=UTF8&tag=laxcomplex-22
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class EffectorGrayScale extends AbstractEffector {
		// ColorMatrixFilter 用マトリクス
		private const GRAYSCALE_MATRIX:Array = [
			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.3375, 0.66375, 0.12375, 0, 0,		// 0.33*1.125, 0.59*1.125, 0.11*1.125
			0.3375, 0.66375, 0.12375, 0, 0,
			0.3375, 0.66375, 0.12375, 0, 0,
			*/
			0,   0,    0,    1, 0
		];
		// ColorMatrixFilter
		private const GRAYSCALE_FILTER:ColorMatrixFilter = new ColorMatrixFilter(GRAYSCALE_MATRIX);
		
		/*
		 * グレイスケール実行
		 * @param	value	効果をかける BitmapData
		 */
		override protected function effect(value:BitmapData):BitmapData {
			value.applyFilter(value, value.rect, ZERO_POINT, GRAYSCALE_FILTER);
			return value;
		}
	}


	import flash.display.BitmapData;
	import flash.filters.BitmapFilterQuality;
	import flash.filters.BlurFilter;
	/**
	 * BlurFilter による平滑化
	 * @author YOSHIDA, Akio (Aquioux)
	 */
	class EffectorSmoothing extends AbstractEffector {
		/*
		 * ぼかしの量
		 * @param	value	数値
		 */
		public function set strength(value:Number):void {
			blurFilter.blurX = blurFilter.blurY = value;
		}
		/*
		 * ぼかしの質
		 * @param	value	数値
		 */
		public function set quality(value:int):void {
			blurFilter.quality = value;
		}
		// ブラーフィルタ
		private var blurFilter:BlurFilter;


		public function EffectorSmoothing() {
			blurFilter = new BlurFilter(2, 2, BitmapFilterQuality.MEDIUM);
		}
		
		/*
		 * 平滑化実行
		 * @param	value	効果をかける BitmapData
		 */
		override protected function effect(value:BitmapData):BitmapData {
			value.applyFilter(value, value.rect, ZERO_POINT, blurFilter);
			return value;
		}
	}