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

ゼロ交差法によるエッジ検出

『画像処理プログラミング』という本と、
http://d.hatena.ne.jp/matsu4512/20090711/1247321353
を参考にゼロ交差法というエッジ検出をやってみました。
が、ぜんぜん速くならなかった…
Get Adobe Flash player
by utabi 20 Oct 2009
    Embed
/**
 * Copyright utabi ( http://wonderfl.net/user/utabi )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/fRJG
 */

// 『画像処理プログラミング』という本と、
//	http://d.hatena.ne.jp/matsu4512/20090711/1247321353
//	を参考にゼロ交差法というエッジ検出をやってみました。
//	が、ぜんぜん速くならなかった…

package
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BlendMode;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.filters.ConvolutionFilter;
	import flash.filters.ColorMatrixFilter;
    import flash.geom.ColorTransform;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.text.TextField;
	import net.hires.debug.*;
	
    [SWF(width = "465", height = "465", frameRate = "15",backgroundColor="0xffffff")]
   
   public class ZeroCrossing extends Sprite
    {
        private var camera:Camera;
        private var video:Video;
		private var videoWidth:int = 465;
		private var videoHeight:int = 232;
		
        private var now:BitmapData;
		private var bdGX:BitmapData, bdGY:BitmapData, bdGXY:BitmapData, bdGXX:BitmapData, bdGYY:BitmapData;
        private var bmd:BitmapData;
        private var rect:Rectangle;
        private var pt:Point;

		private var i:int;
		private var xp:int, yp:int;
		private var xx:int, yy:int;
		private var xo:int, yo:int;
		private var current:int, gray:uint;

		private var Lx:Number, Ly:Number, Lxy:Number, Lxx:Number, Lyy:Number;

		private var lap:Vector.<Number> = new Vector.<Number>();
		private var edge:Vector.<Number> = new Vector.<Number>();
		private var zeroCross:Vector.<uint> = new Vector.<uint>();
		
		private var msize:int;
		private var g:Object = new Object();
		
		private var noiseReduction:ConvolutionFilter;
		private var grayFilter:ColorMatrixFilter = new ColorMatrixFilter([
			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, 0, 0, 0, 255
		]);
		private var filterGX:ConvolutionFilter;
		private var filterGY:ConvolutionFilter;
		private var filterGXY:ConvolutionFilter;
		private var filterGXX:ConvolutionFilter;
		private var filterGYY:ConvolutionFilter;
		private var filterSet:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>(5);
		
        public function ZeroCrossing(){
            //super();
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            camera = Camera.getCamera();
            //カメラあり
            if(camera != null){
                setUpCamera();
            //カメラ無し
            }else{
                var txt:TextField = new TextField();
                txt.text ='カメラ無し';
                addChild(txt);
            }
            
            noiseReduction = new ConvolutionFilter(3, 3,[
                1,  2, 1,
                2,  4, 2,
                1,  2, 1
            ],52);
            bmd = new BitmapData(videoWidth,videoHeight,false);
            addChild(new Bitmap(bmd));
			
            now = new BitmapData(videoWidth,videoHeight,false);

			bdGX = new BitmapData(videoWidth,videoHeight,false);
			bdGY = new BitmapData(videoWidth,videoHeight,false);
			bdGXY = new BitmapData(videoWidth,videoHeight,false);
			bdGXX = new BitmapData(videoWidth,videoHeight,false);
			bdGYY = new BitmapData(videoWidth,videoHeight,false);
            rect = new Rectangle(0, 0, videoWidth, videoHeight);
            pt = new Point(0,0);
			
			msize = 5;
			g = setupGaussianFilters(.6,msize);
			filterGX = new ConvolutionFilter(msize,msize,g.gx,0,127);
			filterGY = new ConvolutionFilter(msize,msize,g.gy,0,127);
			filterGXY = new ConvolutionFilter(msize,msize,g.gxy,0,127);
			filterGXX = new ConvolutionFilter(msize,msize,g.gxx,0,127);
			filterGYY = new ConvolutionFilter(msize,msize,g.gyy,0,127);
			
			lap = new Vector.<Number>(rect.width*rect.height);
			edge = new Vector.<Number>(rect.width*rect.height);
			zeroCross = new Vector.<uint>(rect.width*rect.height);
			addChild(new Stats);
			addEventListener(Event.ENTER_FRAME,loop);
        }
        private function setUpCamera():void {
			
            camera.setMode(videoWidth, videoHeight, 15);
            video = new Video(videoWidth, videoHeight);
            video.attachCamera(camera);
            addChild(video);
        }
        
		private function loop(e:Event=null):void {
            now.draw(video);
			//now.applyFilter(now, rect, pt, noiseReduction);
			now.applyFilter(now, rect, pt, grayFilter);
			
			bdGX.applyFilter(now, rect, pt, filterGX);
			bdGY.applyFilter(now, rect, pt, filterGY);
			bdGXY.applyFilter(now, rect, pt, filterGXY);
			bdGXX.applyFilter(now, rect, pt, filterGXX);
			bdGYY.applyFilter(now, rect, pt, filterGYY);
			
			filterSet[0] = bdGX.getVector(rect);
			filterSet[1] = bdGY.getVector(rect);
			filterSet[2] = bdGXY.getVector(rect);
			filterSet[3] = bdGXX.getVector(rect);
			filterSet[4] = bdGYY.getVector(rect);
            
			bmd.setVector(rect,zero_cross(rect.width, rect.height, 0.025, filterSet));
            //bmd.draw(bdGXX);
        }
		private function zero_cross(w:Number, h:Number,th:Number,f:Vector.<Vector.<uint>>):Vector.<uint>{

			for(yp = 1; yp < h-1; yp++){
				for(xp = 1; xp < w-1; xp++){
					
					current = yp * w + xp;

					Lx = -0.5 + (( f[0][current] - 0xff000000) / 0x00ffffff);
					Ly = -0.5 + (( f[1][current]  - 0xff000000) / 0x00ffffff);
					Lxy = -0.5 + (( f[2][current]  - 0xff000000) / 0x00ffffff);
					Lxx = -0.5 + (( f[3][current]  - 0xff000000) / 0x00ffffff);
					Lyy = -0.5 + (( f[4][current]  - 0xff000000) / 0x00ffffff);

					//この値で+-が反転している部分を見つける
					lap[current] = ((Lx * Lx * Lxx) + (2.0 * Lxy * Lx * Ly) + (Ly * Ly * Lyy) );
					
					//エッジの強度
					edge[current] = Math.sqrt(Lx * Lx + Ly * Ly);
						
					if(edge[current] >= th && (lap[current] * lap[current-1] < 0.0 || lap[current] * lap[current-w] < 0.0)){
						
						zeroCross[current] = 0xff000000;

					} else {
						
						zeroCross[current] = 0xffffffff;
					
					}
				}
			}

			//trace(edge[current],lap[current] * lap[current-1], lap[current] * lap[current-w], 0xffffffff-0xff000000);
			return zeroCross;

	}
	//ガウス関数を微分したマスクを求める。
	private function setupGaussianFilters(scale:Number, matrix_size:int):Object{
    	var x0:int, y0:int;
    	var r0:Number, exponent:Number, id:int;
    	var Gx:Array = [], Gy:Array = [], Gxy:Array = [], Gxx:Array = [], Gyy:Array = [];
		var ret:Object = new Object;
	 
   		//フィルタの中心を求める
		x0 = y0 = matrix_size/2;
    
		for(var y:uint = 0; y < matrix_size; y++){
			for(var x:uint = 0; x < matrix_size; x++){
           
		   id = y*matrix_size+x;
		   
		   //中心からの距離を求める
            r0 = Number((y-y0)*(y-y0)+(x-x0)*(x-x0));
            
            //平滑化をするための2次元のガウス関数
            exponent = 1.0/(2.0*Math.PI*scale) * Math.exp(-r0/(2.0*scale));
            
            //中心からの距離に応じて重み付け
            Gx[id] = (-Number((x-x0))/scale) * exponent;
            Gy[id] = (-Number((y-y0))/scale) * exponent;
            Gxy[id] = (Number((y-y0)*(x-x0))/(scale*scale)) * exponent;
            Gxx[id] = (Number((x-x0)*(x-x0))/(scale*scale)-1.0/scale) * exponent;
            Gyy[id] = (Number((y-y0)*(y-y0))/(scale*scale)-1.0/scale) * exponent;
            
			}
		}
	
		ret = {gx:Gx, gy:Gy, gxy:Gxy, gxx:Gxx, gyy:Gyy};
		//trace(ret.gx);
		//trace(ret.gy);
		return ret
		}
    }
}