OSDN Git Service

[update]nyartoolkit
[nyartoolkit-and/nyartoolkit-and.git] / trunk / src / jp / nyatla / nyartoolkit / processor / SingleARMarkerProcesser.java
index d39344e..19fb191 100644 (file)
@@ -1,39 +1,41 @@
 /* \r
  * Capture Test NyARToolkitCSサンプルプログラム\r
  * --------------------------------------------------------------------------------\r
- * Copyright (C)2008 R.Iizuka\r
+ * The NyARToolkit is Java edition ARToolKit class library.\r
+ * Copyright (C)2008-2009 Ryo Iizuka\r
  *\r
- * This program is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License\r
- * as published by the Free Software Foundation; either version 2\r
- * of the License, or (at your option) any later version.\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
  * \r
  * This program is distributed in the hope that it will be useful,\r
  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
  * GNU General Public License for more details.\r
- * \r
+ *\r
  * You should have received a copy of the GNU General Public License\r
- * along with this framework; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
  * \r
  * For further information please contact.\r
  *     http://nyatla.jp/nyatoolkit/\r
- *     <airmail(at)ebony.plala.or.jp>\r
+ *     <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>\r
  * \r
  */\r
 package jp.nyatla.nyartoolkit.processor;\r
 \r
 import jp.nyatla.nyartoolkit.NyARException;\r
 import jp.nyatla.nyartoolkit.core.*;\r
+import jp.nyatla.nyartoolkit.core.analyzer.raster.threshold.*;\r
 import jp.nyatla.nyartoolkit.core.match.*;\r
 import jp.nyatla.nyartoolkit.core.param.*;\r
 import jp.nyatla.nyartoolkit.core.pickup.*;\r
 import jp.nyatla.nyartoolkit.core.raster.*;\r
 import jp.nyatla.nyartoolkit.core.raster.rgb.*;\r
 import jp.nyatla.nyartoolkit.core.transmat.*;\r
-import jp.nyatla.nyartoolkit.core.rasterfilter.rgb2bin.*;\r
+import jp.nyatla.nyartoolkit.core.rasterfilter.rgb2bin.NyARRasterFilter_ARToolkitThreshold;\r
 import jp.nyatla.nyartoolkit.core.types.*;\r
+import jp.nyatla.nyartoolkit.core.squaredetect.*;\r
 \r
 /**\r
  * このクラスは、同時に1個のマーカを処理することのできる、アプリケーションプロセッサです。\r
@@ -49,17 +51,144 @@ import jp.nyatla.nyartoolkit.core.types.*;
  */\r
 public abstract class SingleARMarkerProcesser\r
 {\r
-       /**selectARCodeIndexFromListが値を返す時に使う変数型です。\r
+       /**\r
+        * detectMarkerのコールバック関数\r
         */\r
-\r
-       private class TResult_selectARCodeIndex\r
+       private class DetectSquareCB implements NyARSquareContourDetector.IDetectMarkerCallback\r
        {\r
-               public int direction;\r
-\r
-               public double confidence;\r
+               //公開プロパティ\r
+               public final NyARSquare square=new NyARSquare();\r
+               public double confidence=0.0;\r
+               public int code_index=-1;               \r
+               public double cf_threshold_new = 0.50;\r
+               public double cf_threshold_exist = 0.30;\r
+               \r
+               //参照\r
+               private INyARRgbRaster _ref_raster;\r
+               //所有インスタンス\r
+               private INyARColorPatt _inst_patt;\r
+               private NyARMatchPattDeviationColorData _deviation_data;\r
+               private NyARMatchPatt_Color_WITHOUT_PCA[] _match_patt;\r
+               private final NyARMatchPattResult __detectMarkerLite_mr=new NyARMatchPattResult();\r
+               private NyARCoord2Linear _coordline;\r
+               \r
+               public DetectSquareCB(NyARParam i_param)\r
+               {\r
+                       this._match_patt=null;\r
+                       this._coordline=new NyARCoord2Linear(i_param.getScreenSize(),i_param.getDistortionFactor());\r
+                       return;\r
+               }\r
+               public void setNyARCodeTable(NyARCode[] i_ref_code,int i_code_resolution)\r
+               {\r
+                       /*unmanagedで実装するときは、ここでリソース解放をすること。*/\r
+                       this._deviation_data=new NyARMatchPattDeviationColorData(i_code_resolution,i_code_resolution);\r
+                       this._inst_patt=new NyARColorPatt_Perspective_O2(i_code_resolution,i_code_resolution,4,25);\r
+                       this._match_patt = new NyARMatchPatt_Color_WITHOUT_PCA[i_ref_code.length];\r
+                       for(int i=0;i<i_ref_code.length;i++){\r
+                               this._match_patt[i]=new NyARMatchPatt_Color_WITHOUT_PCA(i_ref_code[i]);\r
+                       }\r
+               }\r
+               private NyARIntPoint2d[] __tmp_vertex=NyARIntPoint2d.createArray(4);\r
+               /**\r
+                * Initialize call back handler.\r
+                */\r
+               public void init(INyARRgbRaster i_raster)\r
+               {\r
+                       this._ref_raster=i_raster;\r
+                       this.code_index=-1;\r
+                       this.confidence=Double.MIN_NORMAL;\r
+               }\r
 \r
-               public int code_index;\r
-       }\r
+               /**\r
+                * 矩形が見付かるたびに呼び出されます。\r
+                * 発見した矩形のパターンを検査して、方位を考慮した頂点データを確保します。\r
+                */\r
+               public void onSquareDetect(NyARSquareContourDetector i_sender,int[] i_coordx,int[] i_coordy,int i_coor_num,int[] i_vertex_index) throws NyARException\r
+               {\r
+                       if (this._match_patt==null) {\r
+                               return;\r
+                       }\r
+                       //輪郭座標から頂点リストに変換\r
+                       NyARIntPoint2d[] vertex=this.__tmp_vertex;\r
+                       vertex[0].x=i_coordx[i_vertex_index[0]];\r
+                       vertex[0].y=i_coordy[i_vertex_index[0]];\r
+                       vertex[1].x=i_coordx[i_vertex_index[1]];\r
+                       vertex[1].y=i_coordy[i_vertex_index[1]];\r
+                       vertex[2].x=i_coordx[i_vertex_index[2]];\r
+                       vertex[2].y=i_coordy[i_vertex_index[2]];\r
+                       vertex[3].x=i_coordx[i_vertex_index[3]];\r
+                       vertex[3].y=i_coordy[i_vertex_index[3]];\r
+               \r
+                       //画像を取得\r
+                       if (!this._inst_patt.pickFromRaster(this._ref_raster,vertex)){\r
+                               return;//取得失敗\r
+                       }\r
+                       //取得パターンをカラー差分データに変換して評価する。\r
+                       this._deviation_data.setRaster(this._inst_patt);\r
+\r
+                       \r
+                       //code_index,dir,c1にデータを得る。\r
+                       final NyARMatchPattResult mr=this.__detectMarkerLite_mr;\r
+                       int lcode_index = 0;\r
+                       int dir = 0;\r
+                       double c1 = 0;\r
+                       for (int i = 0; i < this._match_patt.length; i++) {\r
+                               this._match_patt[i].evaluate(this._deviation_data,mr);\r
+                               double c2 = mr.confidence;\r
+                               if (c1 < c2) {\r
+                                       lcode_index = i;\r
+                                       c1 = c2;\r
+                                       dir = mr.direction;\r
+                               }\r
+                       }\r
+                       \r
+                       //認識処理\r
+                       if (this.code_index == -1) { // マーカ未認識\r
+                               //現在は未認識\r
+                               if (c1 < this.cf_threshold_new) {\r
+                                       return;\r
+                               }\r
+                               if (this.confidence > c1) {\r
+                                       // 一致度が低い。\r
+                                       return;\r
+                               }\r
+                               //認識しているマーカIDを保存\r
+                               this.code_index=lcode_index;\r
+                       }else{\r
+                               //現在はマーカ認識中                           \r
+                               // 現在のマーカを認識したか?\r
+                               if (lcode_index != this.code_index) {\r
+                                       // 認識中のマーカではないので無視\r
+                                       return;\r
+                               }\r
+                               //認識中の閾値より大きいか?\r
+                               if (c1 < this.cf_threshold_exist) {\r
+                                       return;\r
+                               }\r
+                               //現在の候補よりも一致度は大きいか?\r
+                               if (this.confidence>c1) {\r
+                                       return;\r
+                               }\r
+                       }\r
+                       //新しく認識、または継続認識中に更新があったときだけ、Square情報を更新する。\r
+                       //ココから先はこの条件でしか実行されない。\r
+                       \r
+                       //一致率の高い矩形があれば、方位を考慮して頂点情報を作成\r
+                       this.confidence=c1;\r
+                       NyARSquare sq=this.square;\r
+                       //directionを考慮して、squareを更新する。\r
+                       for(int i=0;i<4;i++){\r
+                               int idx=(i+4 - dir) % 4;\r
+                               this._coordline.coord2Line(i_vertex_index[idx],i_vertex_index[(idx+1)%4],i_coordx,i_coordy,i_coor_num,sq.line[i]);\r
+                       }\r
+                       for (int i = 0; i < 4; i++) {\r
+                               //直線同士の交点計算\r
+                               if(!NyARLinear.crossPos(sq.line[i],sq.line[(i + 3) % 4],sq.sqvertex[i])){\r
+                                       throw new NyARException();//ここのエラー復帰するならダブルバッファにすればOK\r
+                               }\r
+                       }\r
+               }\r
+       }       \r
        /**オーナーが自由に使えるタグ変数です。\r
         */\r
        public Object tag;\r
@@ -68,22 +197,11 @@ public abstract class SingleARMarkerProcesser
 \r
        private int _lost_delay = 5;\r
 \r
-       private NyARSquareDetector _square_detect;\r
-\r
-       protected NyARTransMat _transmat;\r
-\r
-       private double _marker_width;\r
-\r
-       private NyARMatchPatt_Color_WITHOUT_PCA[] _match_patt;\r
+       private NyARSquareContourDetector _square_detect;\r
 \r
-       private NyARSquareStack _square_list = new NyARSquareStack(100);\r
+       protected INyARTransMat _transmat;\r
 \r
-       private NyARColorPatt_O3 _patt = null;\r
-\r
-       private double _cf_threshold_new = 0.30;\r
-\r
-       private double _cf_threshold_exist = 0.15;\r
-       \r
+       private NyARRectOffset _offset; \r
        private int _threshold = 110;\r
        // [AR]検出結果の保存用\r
        private NyARBinRaster _bin_raster;\r
@@ -92,27 +210,42 @@ public abstract class SingleARMarkerProcesser
 \r
        protected int _current_arcode_index = -1;\r
 \r
-       private NyARMatchPattDeviationColorData _deviation_data;\r
+       private NyARRasterThresholdAnalyzer_SlidePTile _threshold_detect;\r
+       \r
+       protected SingleARMarkerProcesser()\r
+       {\r
+               return;\r
+       }\r
 \r
+       private boolean _initialized=false;\r
 \r
-       public SingleARMarkerProcesser(NyARParam i_param,int i_raster_type) throws NyARException\r
+       protected void initInstance(NyARParam i_param,int i_raster_type) throws NyARException\r
        {\r
+               //初期化済?\r
+               assert(this._initialized==false);\r
+               \r
                NyARIntSize scr_size = i_param.getScreenSize();\r
                // 解析オブジェクトを作る\r
-               this._square_detect = new NyARSquareDetector(i_param.getDistortionFactor(), scr_size);\r
+               this._square_detect = new NyARSquareContourDetector_Rle(i_param.getDistortionFactor(), scr_size);\r
                this._transmat = new NyARTransMat(i_param);\r
                this._tobin_filter=new NyARRasterFilter_ARToolkitThreshold(110,i_raster_type);\r
 \r
                // 2値画像バッファを作る\r
                this._bin_raster = new NyARBinRaster(scr_size.w, scr_size.h);\r
+               this._threshold_detect=new NyARRasterThresholdAnalyzer_SlidePTile(15,i_raster_type,4);\r
+               this._initialized=true;\r
+               //コールバックハンドラ\r
+               this._detectmarker_cb=new DetectSquareCB(i_param);\r
+               this._offset=new NyARRectOffset();\r
                return;\r
        }\r
 \r
+       /*自動・手動の設定が出来ないので、コメントアウト\r
        public void setThreshold(int i_threshold)\r
        {\r
                this._threshold = i_threshold;\r
                return;\r
-       }\r
+       }*/\r
 \r
        /**検出するマーカコードの配列を指定します。 検出状態でこの関数を実行すると、\r
         * オブジェクト状態に強制リセットがかかります。\r
@@ -123,15 +256,9 @@ public abstract class SingleARMarkerProcesser
                        // 強制リセット\r
                        reset(true);\r
                }\r
-               // 検出するマーカセット、情報、検出器を作り直す。\r
-               this._patt = new NyARColorPatt_O3(i_code_resolution, i_code_resolution);\r
-               this._deviation_data=new NyARMatchPattDeviationColorData(i_code_resolution, i_code_resolution);\r
-               this._marker_width = i_marker_width;\r
-\r
-               this._match_patt = new NyARMatchPatt_Color_WITHOUT_PCA[i_ref_code_table.length];\r
-               for(int i=0;i<i_ref_code_table.length;i++){\r
-                       this._match_patt[i]=new NyARMatchPatt_Color_WITHOUT_PCA(i_ref_code_table[i]);\r
-               }\r
+               //検出するマーカセット、情報、検出器を作り直す。(1ピクセル4ポイントサンプリング,マーカのパターン領域は50%)\r
+               this._detectmarker_cb.setNyARCodeTable(i_ref_code_table,i_code_resolution);\r
+               this._offset.setSquare(i_marker_width);\r
                return;\r
        }\r
 \r
@@ -145,160 +272,66 @@ public abstract class SingleARMarkerProcesser
                this._current_arcode_index = -1;\r
                return;\r
        }\r
-\r
+       private DetectSquareCB _detectmarker_cb;\r
        public void detectMarker(INyARRgbRaster i_raster) throws NyARException\r
        {\r
                // サイズチェック\r
                assert(this._bin_raster.getSize().isEqualSize(i_raster.getSize().w, i_raster.getSize().h));\r
 \r
-               // コードテーブルが無ければここで終わり\r
-               if (this._match_patt== null) {\r
-                       return;\r
-               }\r
-\r
-               // ラスタを(1/4の画像の)2値イメージに変換する.\r
+               //BINイメージへの変換\r
                this._tobin_filter.setThreshold(this._threshold);\r
                this._tobin_filter.doFilter(i_raster, this._bin_raster);\r
 \r
-               NyARSquareStack square_stack = this._square_list;\r
                // スクエアコードを探す\r
-               this._square_detect.detectMarker(this._bin_raster, square_stack);\r
-               // 認識処理\r
-               if (this._current_arcode_index == -1) { // マーカ未認識\r
-                       detectNewMarker(i_raster, square_stack);\r
-               } else { // マーカ認識中\r
-                       detectExistMarker(i_raster, square_stack, this._current_arcode_index);\r
+               this._detectmarker_cb.init(i_raster);\r
+               this._square_detect.detectMarkerCB(this._bin_raster,this._detectmarker_cb);\r
+               \r
+               // 認識状態を更新\r
+               final boolean is_id_found=updateStatus(this._detectmarker_cb.square,this._detectmarker_cb.code_index);\r
+               //閾値フィードバック(detectExistMarkerにもあるよ)\r
+               if(!is_id_found){\r
+                       //マーカがなければ、探索+DualPTailで基準輝度検索\r
+                       int th=this._threshold_detect.analyzeRaster(i_raster);\r
+                       this._threshold=(this._threshold+th)/2;\r
                }\r
+               \r
+               \r
                return;\r
        }\r
-\r
-       \r
-       private final NyARMatchPattResult __detectMarkerLite_mr=new NyARMatchPattResult();\r
-       \r
-       /**ARCodeのリストから、最も一致するコード番号を検索します。\r
-        */\r
-       private boolean selectARCodeIndexFromList(INyARRgbRaster i_raster, NyARSquare i_square, TResult_selectARCodeIndex o_result) throws NyARException\r
-       {\r
-               // 現在コードテーブルはアクティブ?\r
-               if (this._match_patt==null) {\r
-                       return false;\r
-               }\r
-               // 評価基準になるパターンをイメージから切り出す\r
-               if (!this._patt.pickFromRaster(i_raster, i_square)) {\r
-                       return false;\r
-               }\r
-               //評価データを作成して、評価器にセット\r
-               this._deviation_data.setRaster(this._patt);             \r
-               final NyARMatchPattResult mr=this.__detectMarkerLite_mr;\r
-               int code_index = 0;\r
-               int dir = 0;\r
-               double c1 = 0;\r
-               // コードと比較する\r
-               for (int i = 0; i < this._match_patt.length; i++) {\r
-                       this._match_patt[i].evaluate(this._deviation_data,mr);\r
-                       double c2 = mr.confidence;\r
-                       if (c1 < c2) {\r
-                               code_index = i;\r
-                               c1 = c2;\r
-                               dir = mr.direction;\r
-                       }\r
-               }\r
-               o_result.code_index = code_index;\r
-               o_result.direction = dir;\r
-               o_result.confidence = c1;\r
-               return true;\r
-       }\r
-\r
-       private TResult_selectARCodeIndex __detect_X_Marker_detect_result = new TResult_selectARCodeIndex();\r
-\r
-       /**新規マーカ検索 現在認識中のマーカがないものとして、最も認識しやすいマーカを1個認識します。\r
-        */\r
-       private void detectNewMarker(INyARRgbRaster i_raster, NyARSquareStack i_stack) throws NyARException\r
-       {\r
-               int number_of_square = i_stack.getLength();\r
-               double cf = 0;\r
-               int dir = 0;\r
-               int code_index = -1;\r
-               int square_index = 0;\r
-               TResult_selectARCodeIndex detect_result = this.__detect_X_Marker_detect_result;\r
-               for (int i = 0; i < number_of_square; i++) {\r
-                       if (!selectARCodeIndexFromList(i_raster, (i_stack.getItem(i)), detect_result)) {\r
-                               // 見つからない。\r
-                               return;\r
-                       }\r
-                       if (detect_result.confidence < this._cf_threshold_new) {\r
-                               continue;\r
-                       }\r
-                       if (detect_result.confidence < cf) {\r
-                               // 一致度が低い。\r
-                               continue;\r
-                       }\r
-                       cf = detect_result.confidence;\r
-                       code_index = detect_result.code_index;\r
-                       square_index = i;\r
-                       dir = detect_result.direction;\r
-               }\r
-               // 認識状態を更新\r
-               updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
-       }\r
-\r
-       /**マーカの継続認識 現在認識中のマーカを優先して認識します。 \r
-        * (注)この機能はたぶん今後いろいろ発展するからNewと混ぜないこと。\r
+       /**\r
+        * \r
+        * @param i_new_detect_cf\r
+        * @param i_exist_detect_cf\r
         */\r
-       private void detectExistMarker(INyARRgbRaster i_raster, NyARSquareStack i_stack, int i_current_id) throws NyARException\r
+       public void setConfidenceThreshold(double i_new_cf,double i_exist_cf)\r
        {\r
-               int number_of_square = i_stack.getLength();\r
-               double cf = 0;\r
-               int dir = 0;\r
-               int code_index = -1;\r
-               int square_index = 0;\r
-               TResult_selectARCodeIndex detect_result = this.__detect_X_Marker_detect_result;\r
-               for (int i = 0; i < number_of_square; i++) {\r
-                       if (!selectARCodeIndexFromList(i_raster,i_stack.getItem(i), detect_result)) {\r
-                               // 見つからない。\r
-                               return;\r
-                       }\r
-                       // 現在のマーカを認識したか?\r
-                       if (detect_result.code_index != i_current_id) {\r
-                               // 認識中のマーカではないので無視\r
-                               continue;\r
-                       }\r
-                       if (detect_result.confidence < this._cf_threshold_exist) {\r
-                               continue;\r
-                       }\r
-                       if (detect_result.confidence < cf) {\r
-                               // 一致度が高い方を選ぶ\r
-                               continue;\r
-                       }\r
-                       cf = detect_result.confidence;\r
-                       code_index = detect_result.code_index;\r
-                       dir = detect_result.direction;\r
-                       square_index = i;\r
-               }\r
-               // 認識状態を更新\r
-               updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
+               this._detectmarker_cb.cf_threshold_exist=i_exist_cf;\r
+               this._detectmarker_cb.cf_threshold_new=i_new_cf;\r
        }\r
 \r
        private NyARTransMatResult __NyARSquare_result = new NyARTransMatResult();\r
 \r
-       /**オブジェクトのステータスを更新し、必要に応じてハンドル関数を駆動します。\r
+       /**     オブジェクトのステータスを更新し、必要に応じてハンドル関数を駆動します。\r
+        *      戻り値は、「実際にマーカを発見する事ができたか」です。クラスの状態とは異なります。\r
         */\r
-       private void updateStatus(NyARSquare i_square, int i_code_index, double i_cf, int i_dir)  throws NyARException\r
+       private boolean updateStatus(NyARSquare i_square, int i_code_index)  throws NyARException\r
        {\r
                NyARTransMatResult result = this.__NyARSquare_result;\r
                if (this._current_arcode_index < 0) {// 未認識中\r
                        if (i_code_index < 0) {// 未認識から未認識の遷移\r
                                // なにもしないよーん。\r
+                               return false;\r
                        } else {// 未認識から認識の遷移\r
                                this._current_arcode_index = i_code_index;\r
                                // イベント生成\r
                                // OnEnter\r
                                this.onEnterHandler(i_code_index);\r
                                // 変換行列を作成\r
-                               this._transmat.transMat(i_square, i_dir, this._marker_width, result);\r
+                               this._transmat.transMat(i_square, this._offset, result);\r
                                // OnUpdate\r
                                this.onUpdateHandler(i_square, result);\r
                                this._lost_delay_count = 0;\r
+                               return true;\r
                        }\r
                } else {// 認識中\r
                        if (i_code_index < 0) {// 認識から未認識の遷移\r
@@ -308,18 +341,19 @@ public abstract class SingleARMarkerProcesser
                                        this._current_arcode_index = -1;\r
                                        this.onLeaveHandler();\r
                                }\r
+                               return false;\r
                        } else if (i_code_index == this._current_arcode_index) {// 同じARCodeの再認識\r
                                // イベント生成\r
                                // 変換行列を作成\r
-                               this._transmat.transMat(i_square, i_dir, this._marker_width, result);\r
+                               this._transmat.transMatContinue(i_square, this._offset, result);\r
                                // OnUpdate\r
                                this.onUpdateHandler(i_square, result);\r
                                this._lost_delay_count = 0;\r
+                               return true;\r
                        } else {// 異なるコードの認識→今はサポートしない。\r
                                throw new  NyARException();\r
                        }\r
                }\r
-               return;\r
        }\r
 \r
        protected abstract void onEnterHandler(int i_code);\r