Surf AS3 を試してみました


画像から特徴点を抽出するアルゴリズム Surf を AS3 に移植したライブラリ
OpenSurf Source from C++ to AS3 というヤツを見つけたのでちょっとテストしてみました。

ちなみに Surf についてはこのスライド(http://www.slideshare.net/lawmn/siftsurf)などで説明されています。(他にもググればたくさん出てきます)

で、試してみた感想ですが…

C++ からの AS3 移植版なので、予想通りメチャクチャ遅いですw
まぁ参照元のサイトにも “It would be cool if someone could speed up this process ! Furthermore I have few doubts about my matrix conversions… (in FastHessian.as).” とあるくらいなので、「誰かこいつを高速化してくれよ!」という感じなのでしょうけど。

というわけで、デモはこちら。

Surf AS3 Test

画像をクリックするとデモ画面が開きます。
デモコンテンツの実行は Web Camera の映像が出てから画面をクリックしてください。

こんな感じで、意味が分からないままゴチャゴチャいじっていると多少動くようにはなったのですが、それでも重いですねー。

今回のデモのソースはこちらになります。
静止画用だったライブラリ付属のサンプルを、Webカメラからの動画対応に変更しただけですけど…

package
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.media.Camera;
	import flash.media.Video;
	
	import net.hires.debug.Stats;
	
	import surf.FastHessian;
	import surf.IPoint;
	import surf.IntegralImage;
	import surf.SurfDescriptor;
	
	
	[SWF( width = '640', height = '480', frameRate = '30', backgroundColor = '0' )]
	
	public class Main extends Sprite
	{
		[Embed( source = "./assets/bg.png" )]
		private static var imgClass:Class;
		public static var bg:Bitmap = new imgClass;
		
		private var _cam:Camera;
		private var _video:Video;
		
		private var _camImage:Bitmap;
		private var _camImageBuffer:BitmapData;
		
		// Cam
		private var _integral:IntegralImage;
		private var _ipts:Vector.<IPoint>;
		
		// Static
		private var _integralStatic:IntegralImage;
		private var _iptsStatic:Vector.<IPoint>;
		
		private var _afin:Number = 0.003;
		
		private var _circle:Sprite;
		private var _connectLiner:Sprite;
		
		private var _isStarted:Boolean;
		
		public function Main()
		{
			addChild( bg );
			setup();
			
			var stats:Stats = new Stats();
			stats.x = 640 - 70;
			addChild( stats );
		}
		
		
		// --------- Setup ------------------------------------------------ /
		private function setup():void
		{
			// Camera & Video
			_video = new Video( 320, 240 );
			_cam = Camera.getCamera();
			_cam.setMode( 320, 240, 30 );
			_video.attachCamera( _cam );
			
			// Image
			_camImage = new Bitmap();
			_camImageBuffer = new BitmapData( 320, 240, false, 0 );
			_camImage.bitmapData = _camImageBuffer;
			_camImage.x = 320;
			_camImage.y = 240;
			addChild( _camImage );
			
			_video.x = 320;
			_video.y = 240;
			addChild( _video );
			
			// Canvas
			_circle = new Sprite();
			_circle.x = 320;
			_circle.y = 240;
			addChild( _circle );
			
			_connectLiner = new Sprite()
			addChild( _connectLiner );
			
			stage.addEventListener( MouseEvent.CLICK, onStart );
		}
		
		
		private function onStart( e:MouseEvent ):void
		{
			stage.removeEventListener( MouseEvent.CLICK, onStart );
			addEventListener( Event.ENTER_FRAME, update );
			
			removeChild( _video );
		}

		
		// --------- Update ------------------------------------------------ /
		private function update( e:Event ):void
		{
			
			_camImageBuffer.lock();
			_camImageBuffer.draw( _video );
			_camImageBuffer.unlock();
			
			_ipts = new Vector.<IPoint>();
			
			//
			_integral = new IntegralImage( _camImage );
			var f:FastHessian = new FastHessian( _afin, 5, 3, _integral );
			_ipts = f.getIpoints();
			var surf:SurfDescriptor = new SurfDescriptor( _ipts, false, false, _integral );
			
			_circle.graphics.clear();
			
			for each ( var ip:IPoint in _ipts )
			{
				var S:int = ( 2.5 * ip.scale );
				var R:int = ( S * .5 );
				var C:uint;
				
				var AX:int = R * Math.cos( ip.orientation );
				var AY:int = R * Math.sin( ip.orientation );
				
				ip.laplacian > 0 ? C = 0x0000ff : C = 0xff0000;
				draw( _circle, ip.x, ip.y, S, R, C, AX, AY );
			}
			
			// SetStatic
			if( !_isStarted )
			{
				_isStarted = true;
				
				_iptsStatic = new Vector.<IPoint>();
				
				var image:Bitmap = new Bitmap();
				var buffer:BitmapData = new BitmapData( 320, 240, false, 0 );
				image.bitmapData = buffer;
				addChild( image );
				
				buffer.lock();
				buffer.draw( _video );
				buffer.unlock();
				
				_integralStatic = new IntegralImage( image );
				var ff:FastHessian = new FastHessian( _afin, 5, 3, _integralStatic );
				_iptsStatic = ff.getIpoints();
				var surf1:SurfDescriptor = new SurfDescriptor( _iptsStatic, false, false, _integralStatic );
				
				var circle:Sprite = new Sprite();
				addChild( circle );
				
				setChildIndex(_connectLiner, numChildren - 1);
				
				for each ( ip in _iptsStatic )
				{
					S = ( 2.5 * ip.scale );
					R = ( S * .5 );
					
					
					AX = R * Math.cos( ip.orientation );
					AY = R * Math.sin( ip.orientation );
					
					ip.laplacian > 0 ? C = 0x0000ff : C = 0xff0000;
					draw( circle, ip.x, ip.y, S, R, C, AX, AY );
				}

			}
			
			_connectLiner.graphics.clear();
			
			// compare !
			
			var dist:Number = 0;
			var d1:Number = 0;
			var d2:Number = 0;
			var match:IPoint;
			var matches:Vector.<IPoint> = new Vector.<IPoint>();
			
			for ( var i:int = 0; i < _iptsStatic.length; i++ )
			{
				d1 = d2 = Number.MAX_VALUE;
				
				for ( var j:int = 0; j < _ipts.length; j++ )
				{
					
					dist = soustract( _iptsStatic[ i ], _ipts[ j ]);
					
					
					if ( dist < d1 )
					{
						
						d2 = d1;
						d1 = dist;
						match = _ipts[ j ];
					}
					else if ( dist < d2 )
					{
						d2 = dist;
					}
				}
				
				
				if ( d1 / d2 < 0.65 )
				{
					match.x - _iptsStatic[ i ].x;
					match.y - _iptsStatic[ i ].y;
					matches.push( _iptsStatic[ i ]);
					matches.push( match );
					
					var a:Point = new Point( _iptsStatic[ i ].x, _iptsStatic[ i ].y );
					var b:Point = new Point( match.x, match.y );
					drawconnect( a, b );
				}
			}
		}
		
		
		
		// --------- Soustract ------------------------------------------------ /
		private function soustract( thi:IPoint, rhs:IPoint ):Number
		{
			
			var sum:Number = 0;
			
			for ( var i:int = 0; i < 64; ++i )
				sum += ( thi.descriptor[ i ] - rhs.descriptor[ i ]) * ( thi.descriptor[ i ] - rhs.descriptor[ i ]);
			
			return Math.sqrt( sum );
			
		}
	
		
		// --------- Draw ConnectLine ------------------------------------------------ /
		private function drawconnect( a:Point, b:Point ):void
		{
			
			_connectLiner.graphics.lineStyle( 1, 0xFFFF00 * Math.random() * 256 );
			_connectLiner.graphics.moveTo( a.x, a.y );
			_connectLiner.graphics.lineTo( b.x + _camImage.width, b.y + _camImage.height );
			
		}
		
		
		// --------- Draw Circle ------------------------------------------------ /
		private function draw( target:Sprite, X:int, Y:int, S:int, R:int, C:uint, AX:int, AY:int ):void
		{
			
			target.graphics.beginFill( C, .05 );
			target.graphics.lineStyle( .5, C );
			target.graphics.drawCircle( X, Y, S );
			target.graphics.endFill();
			
			target.graphics.lineStyle( 1, 0x00FF00 );
			target.graphics.moveTo( X, Y );
			target.graphics.lineTo( X + AX, Y + AY );
			
		}
		
	}
}

Surf AS3 を試してみました” に対して2件のコメントがあります。

    1. Yoshida@DigiFie より:

      Thank you for your interesting library!

コメントは受け付けていません。