FLARToolKit

FLARToolKit version 2.x

Section 9 FLARToolKitにFilterを組込む

Adobe Pixel Bender Toolkitを使って作成したフィルターをFLARToolKitに組込みます。

開発環境は別のページで説明していますので、ここでは省略します。
今回使用しているのはFLARToolKit version 2.5.4をダウンロード、インポートしたバージョンを用いています。

pbjファイルを配置

保存したファイルを、resourcesフォルダ内に配置してください。

Adobe Flash Builder 4

サンプルの作成

次に、[ファイル]->[新規(N)]->[ActionScript クラス]で、新規にクラスを作成します。

Adobe Flash Builder 4

[FLARTK_Example_Single_SimpleCube_PV3D.as]ファイルの内容を、作成したクラス[FilterSample]にコピーします。
その後、下記の箇所を書き換えてください。

“FilterSample.as” を書き換えていきます。

まず、パッケージ。

*** 25,26 ****(編集前)
!    package examples
    {
--- 25,26 ----(編集後)
!    package
    {

ファイル名が変わるので、クラス名もそれに合わせて変更。

*** 58,60 ****(編集前)
!    
!    public class FLARTK_Example_Single_SimpleCube_PV3D extends Sprite
    {
--- 58,60 ----(編集後)
+    [SWF(width=640, height=480, backgroundColor=0x808080, frameRate=30)]
!    public class _FilterSample_ extends Sprite
    {

コンストラクタもクラス名もそれに合わせて変更。

*** 192,193 ****(編集前)
!        public function FLARTK_Example_Single_SimpleCube_PV3D()
        {
--- 192,193 ----(編集後)
!        public function _FilterSample_()
        {

ここまでで保存して[デフォルトのアプリケーション]に設定してから、実行出来ることを確認してください。

二値化映像を表示

二値化映像を画面の片隅に表示するようにします。

*** 442,443 ****(編集前)
            this.renderer.render();
        }
--- 442,447 ----(編集後)
            this.renderer.render();
+            
+            // 二値化映像の表示
+            var binRasterBitmap:Bitmap = new Bitmap(this.detector.thresholdedBitmapData);
+            this.addChild(binRasterBitmap);
        }

これを実行すると、二値化映像が表示されます。

Flash Player 10

フィルターの組込み

それでは本題のフィルター組込みです。
フィルターは[Embed]メタタグを使用してコンパイル時にSWFファイルに埋め込む方法を使用します。

必要なクラスをインポートします。

*** 31,32 ****(編集前)
    import flash.events.Event;
    import flash.media.Camera;
--- 31,35 ----(編集後)
    import flash.events.Event;
+   import flash.display.Shader;
+   import flash.filters.ShaderFilter;
+   import flash.geom.Point;
    import flash.media.Camera;

通常のサンプルは、背景描画と解析用に同じものを使用しているので、フィルターを当てると背景描画にも影響を与えてしまいます。 そのため、背景描画用にウェブカメラからの入力を確保するための変数を準備します。

*** 118,123 ****(編集前)
        /**
         * Webカメラからの入力をBitmapに確保する
         * @see flash.display.Bitmap
         */
        private var capture:Bitmap;

--- 118,124 ----(編集後)
        /**
         * Webカメラからの入力をBitmapに確保する
         * @see flash.display.Bitmap
         */
        private var capture:Bitmap;
+       private var background:Bitmap;

フィルターの変数を定義。Pointは、範囲指定の時に使用する。

*** 190,194 ****(編集前)
        protected var resultMat:FLARTransMatResult = new FLARTransMatResult();

        /**
         * Constructor
         * ここから初期化処理を呼び出して処理をスタート
--- 190,201 ----(編集後)
        protected var resultMat:FLARTransMatResult = new FLARTransMatResult();

+       /**
+        * カラーフィルター
+        */
+       private var extShaderFilter:ShaderFilter;
+        
+       private static const ZERO_POINT:Point = new Point();
+        
        /**
         * Constructor
         * ここから初期化処理を呼び出して処理をスタート

フィルターの初期化。
ここで[Embed]を使用して読み込み、初期化する。

*** 442,443 ****(編集前)
        private function initialization(e:Event): void
        {
            this.removeEventListener(Event.COMPLETE, initialization);

            // Setup camera
            this.webCamera = Camera.getCamera();
--- 442,447 ----(編集後)
        private function initialization(e:Event): void
        {
            this.removeEventListener(Event.COMPLETE, initialization);

+           [Embed(source="../resources/InvertBlueback.pbj", mimeType="application/octet-stream")]
+           var pbjData:Class;
+            
+           var inversionShader:Shader = new Shader(new pbjData());
+           this.extShaderFilter = new ShaderFilter(inversionShader);
+            
            // Setup camera
            this.webCamera = Camera.getCamera();

背景描画用のBitmapを確保。

*** 288,295 ****(編集前)
            this.webCamera.setMode( this.captureWidth, this.captureHeight, 30);
            this.video = new Video( this.captureWidth, this.captureHeight);
            this.video.attachCamera(this.webCamera);

            // setup ARToolkit
            this.capture = new Bitmap(new BitmapData(this.captureWidth, this.captureHeight, false, 0),
                PixelSnapping.AUTO,
                true);
--- 288,303 ----(編集後)
            this.webCamera.setMode( this.captureWidth, this.captureHeight, 30);
            this.video = new Video( this.captureWidth, this.captureHeight);
            this.video.attachCamera(this.webCamera);

+           // 背景描画
+           this.background = new Bitmap(new BitmapData(this.captureWidth, this.captureHeight, false, 0),
+                PixelSnapping.AUTO,
+                true);
+           this.background.width = this.canvasWidth;
+           this.background.height = this.canvasHeight;
+           this.addChild(this.background);
+            
            // setup ARToolkit
            this.capture = new Bitmap(new BitmapData(this.captureWidth, this.captureHeight, false, 0),
                PixelSnapping.AUTO,
                true);

背景描画用をaddChildしているので、解析用のはコメントアウトして描画しないようにしておく。

*** 311,312 ****(編集前)
            // キャプチャーしている内容を addChild
!            this.addChild(this.capture);
--- 311,312 ----(編集後)
            // キャプチャーしている内容を addChild
!            _//_this.addChild(this.capture);

最後に、detectorに与える Raster データにフィルターを適応して終了。

*** 443,451 ****(編集前)
        public function run(e:Event):void
        {
            this.capture.bitmapData.draw(this.video);

            // Marker detect
            var detected:Boolean = false;
            try {
                detected = this.detector.detectMarkerLite(this.raster, this._threshold) && this.detector.getConfidence() > 0.5;
            } catch (e:Error) {}
--- 443,456 ----(編集後)
        public function run(e:Event):void
        {
            this.capture.bitmapData.draw(this.video);
+           this.background.bitmapData.draw(this.video);

            // Marker detect
            var detected:Boolean = false;
            try {
+               // カラーフィルター適応
+               var _data:BitmapData = this.raster.getBuffer() as BitmapData;
+               _data.applyFilter(_data, _data.rect, ZERO_POINT, this.extShaderFilter);
+                
                detected = this.detector.detectMarkerLite(this.raster, this._threshold) && this.detector.getConfidence() > 0.5;
            } catch (e:Error) {}

編集が終わったら保存して実行してください。

Flash Player 10

まとめ

Detectorに与える this.raster を加工してしまえばそれに応じて解析してくれます。
今回は反転していますが、他にも、普通の白黒マーカーで、その周辺に余白を設けたくない場合や、暗い場所で使うことが想定されるならば、ガンマを変更するなど、幅広く応用ができます。

フィルターを作ることが手間になりますが、手間一つで応用できるので色々なフィルターを試してみては如何でしょうか?