OSDN Git Service

Support NyARToolkit-2.5.1.
[nyartoolkit-and/nyartoolkit-and.git] / src / jp / nyatla / nyartoolkit / processor / SingleARMarkerProcesser.java
1 /* \r
2  * Capture Test NyARToolkitCSサンプルプログラム\r
3  * --------------------------------------------------------------------------------\r
4  * The NyARToolkit is Java edition ARToolKit class library.\r
5  * Copyright (C)2008-2009 Ryo Iizuka\r
6  *\r
7  * This program is free software: you can redistribute it and/or modify\r
8  * it under the terms of the GNU General Public License as published by\r
9  * the Free Software Foundation, either version 3 of the License, or\r
10  * (at your option) any later version.\r
11  * \r
12  * This program is distributed in the hope that it will be useful,\r
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15  * GNU General Public License for more details.\r
16  *\r
17  * You should have received a copy of the GNU General Public License\r
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
19  * \r
20  * For further information please contact.\r
21  *      http://nyatla.jp/nyatoolkit/\r
22  *      <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>\r
23  * \r
24  */\r
25 package jp.nyatla.nyartoolkit.processor;\r
26 \r
27 import jp.nyatla.nyartoolkit.NyARException;\r
28 import jp.nyatla.nyartoolkit.core.*;\r
29 import jp.nyatla.nyartoolkit.core.analyzer.raster.threshold.*;\r
30 import jp.nyatla.nyartoolkit.core.match.*;\r
31 import jp.nyatla.nyartoolkit.core.param.*;\r
32 import jp.nyatla.nyartoolkit.core.pickup.*;\r
33 import jp.nyatla.nyartoolkit.core.raster.*;\r
34 import jp.nyatla.nyartoolkit.core.raster.rgb.*;\r
35 import jp.nyatla.nyartoolkit.core.transmat.*;\r
36 import jp.nyatla.nyartoolkit.core.rasterfilter.rgb2bin.NyARRasterFilter_ARToolkitThreshold;\r
37 import jp.nyatla.nyartoolkit.core.types.*;\r
38 import jp.nyatla.nyartoolkit.core.squaredetect.*;\r
39 \r
40 /**\r
41  * このクラスは、同時に1個のマーカを処理することのできる、アプリケーションプロセッサです。\r
42  * マーカの出現・移動・消滅を、イベントで通知することができます。\r
43  * クラスには複数のマーカを登録できます。一つのマーカが見つかると、プロセッサは継続して同じマーカを\r
44  * 1つだけ認識し続け、見失うまでの間は他のマーカを認識しません。\r
45  * \r
46  * イベントは、 OnEnter→OnUpdate[n]→OnLeaveの順で発生します。\r
47  * マーカが見つかるとまずOnEnterが1度発生して、何番のマーカが発見されたかがわかります。\r
48  * 次にOnUpdateにより、現在の変換行列が連続して渡されます。最後にマーカを見失うと、OnLeave\r
49  * イベントが発生します。\r
50  * \r
51  */\r
52 public abstract class SingleARMarkerProcesser\r
53 {\r
54         /**\r
55          * detectMarkerのコールバック関数\r
56          */\r
57         private class DetectSquareCB implements NyARSquareContourDetector.IDetectMarkerCallback\r
58         {\r
59                 //公開プロパティ\r
60                 public final NyARSquare square=new NyARSquare();\r
61                 public double confidence=0.0;\r
62                 public int code_index=-1;               \r
63                 public double cf_threshold_new = 0.50;\r
64                 public double cf_threshold_exist = 0.30;\r
65                 \r
66                 //参照\r
67                 private INyARRgbRaster _ref_raster;\r
68                 //所有インスタンス\r
69                 private INyARColorPatt _inst_patt;\r
70                 private NyARMatchPattDeviationColorData _deviation_data;\r
71                 private NyARMatchPatt_Color_WITHOUT_PCA[] _match_patt;\r
72                 private final NyARMatchPattResult __detectMarkerLite_mr=new NyARMatchPattResult();\r
73                 private NyARCoord2Linear _coordline;\r
74                 \r
75                 public DetectSquareCB(NyARParam i_param)\r
76                 {\r
77                         this._match_patt=null;\r
78                         this._coordline=new NyARCoord2Linear(i_param.getScreenSize(),i_param.getDistortionFactor());\r
79                         return;\r
80                 }\r
81                 public void setNyARCodeTable(NyARCode[] i_ref_code,int i_code_resolution)\r
82                 {\r
83                         /*unmanagedで実装するときは、ここでリソース解放をすること。*/\r
84                         this._deviation_data=new NyARMatchPattDeviationColorData(i_code_resolution,i_code_resolution);\r
85                         this._inst_patt=new NyARColorPatt_Perspective_O2(i_code_resolution,i_code_resolution,4,25);\r
86                         this._match_patt = new NyARMatchPatt_Color_WITHOUT_PCA[i_ref_code.length];\r
87                         for(int i=0;i<i_ref_code.length;i++){\r
88                                 this._match_patt[i]=new NyARMatchPatt_Color_WITHOUT_PCA(i_ref_code[i]);\r
89                         }\r
90                 }\r
91                 private NyARIntPoint2d[] __tmp_vertex=NyARIntPoint2d.createArray(4);\r
92                 private int _target_id;\r
93                 /**\r
94                  * Initialize call back handler.\r
95                  */\r
96                 public void init(INyARRgbRaster i_raster,int i_target_id)\r
97                 {\r
98                         this._ref_raster=i_raster;\r
99                         this._target_id=i_target_id;\r
100                         this.code_index=-1;\r
101                         this.confidence=Double.MIN_VALUE;\r
102                 }\r
103 \r
104                 /**\r
105                  * 矩形が見付かるたびに呼び出されます。\r
106                  * 発見した矩形のパターンを検査して、方位を考慮した頂点データを確保します。\r
107                  */\r
108                 public void onSquareDetect(NyARSquareContourDetector i_sender,int[] i_coordx,int[] i_coordy,int i_coor_num,int[] i_vertex_index) throws NyARException\r
109                 {\r
110                         if (this._match_patt==null) {\r
111                                 return;\r
112                         }\r
113                         //輪郭座標から頂点リストに変換\r
114                         NyARIntPoint2d[] vertex=this.__tmp_vertex;\r
115                         vertex[0].x=i_coordx[i_vertex_index[0]];\r
116                         vertex[0].y=i_coordy[i_vertex_index[0]];\r
117                         vertex[1].x=i_coordx[i_vertex_index[1]];\r
118                         vertex[1].y=i_coordy[i_vertex_index[1]];\r
119                         vertex[2].x=i_coordx[i_vertex_index[2]];\r
120                         vertex[2].y=i_coordy[i_vertex_index[2]];\r
121                         vertex[3].x=i_coordx[i_vertex_index[3]];\r
122                         vertex[3].y=i_coordy[i_vertex_index[3]];\r
123                 \r
124                         //画像を取得\r
125                         if (!this._inst_patt.pickFromRaster(this._ref_raster,vertex)){\r
126                                 return;//取得失敗\r
127                         }\r
128                         //取得パターンをカラー差分データに変換して評価する。\r
129                         this._deviation_data.setRaster(this._inst_patt);\r
130 \r
131                         \r
132                         //code_index,dir,c1にデータを得る。\r
133                         final NyARMatchPattResult mr=this.__detectMarkerLite_mr;\r
134                         int lcode_index = 0;\r
135                         int dir = 0;\r
136                         double c1 = 0;\r
137                         for (int i = 0; i < this._match_patt.length; i++) {\r
138                                 this._match_patt[i].evaluate(this._deviation_data,mr);\r
139                                 double c2 = mr.confidence;\r
140                                 if (c1 < c2) {\r
141                                         lcode_index = i;\r
142                                         c1 = c2;\r
143                                         dir = mr.direction;\r
144                                 }\r
145                         }\r
146                         \r
147                         //認識処理\r
148                         if (this._target_id == -1) { // マーカ未認識\r
149                                 //現在は未認識\r
150                                 if (c1 < this.cf_threshold_new) {\r
151                                         return;\r
152                                 }\r
153                                 if (this.confidence > c1) {\r
154                                         // 一致度が低い。\r
155                                         return;\r
156                                 }\r
157                                 //認識しているマーカIDを保存\r
158                                 this.code_index=lcode_index;\r
159                         }else{\r
160                                 //現在はマーカ認識中                           \r
161                                 // 現在のマーカを認識したか?\r
162                                 if (lcode_index != this._target_id) {\r
163                                         // 認識中のマーカではないので無視\r
164                                         return;\r
165                                 }\r
166                                 //認識中の閾値より大きいか?\r
167                                 if (c1 < this.cf_threshold_exist) {\r
168                                         return;\r
169                                 }\r
170                                 //現在の候補よりも一致度は大きいか?\r
171                                 if (this.confidence>c1) {\r
172                                         return;\r
173                                 }\r
174                                 this.code_index=this._target_id;\r
175                         }\r
176                         //新しく認識、または継続認識中に更新があったときだけ、Square情報を更新する。\r
177                         //ココから先はこの条件でしか実行されない。\r
178                         \r
179                         //一致率の高い矩形があれば、方位を考慮して頂点情報を作成\r
180                         this.confidence=c1;\r
181                         NyARSquare sq=this.square;\r
182                         //directionを考慮して、squareを更新する。\r
183                         for(int i=0;i<4;i++){\r
184                                 int idx=(i+4 - dir) % 4;\r
185                                 this._coordline.coord2Line(i_vertex_index[idx],i_vertex_index[(idx+1)%4],i_coordx,i_coordy,i_coor_num,sq.line[i]);\r
186                         }\r
187                         for (int i = 0; i < 4; i++) {\r
188                                 //直線同士の交点計算\r
189                                 if(!NyARLinear.crossPos(sq.line[i],sq.line[(i + 3) % 4],sq.sqvertex[i])){\r
190                                         throw new NyARException();//ここのエラー復帰するならダブルバッファにすればOK\r
191                                 }\r
192                         }\r
193                 }\r
194         }       \r
195         /**オーナーが自由に使えるタグ変数です。\r
196          */\r
197         public Object tag;\r
198 \r
199         private int _lost_delay_count = 0;\r
200 \r
201         private int _lost_delay = 5;\r
202 \r
203         private NyARSquareContourDetector _square_detect;\r
204 \r
205         protected INyARTransMat _transmat;\r
206 \r
207         private NyARRectOffset _offset; \r
208         private int _threshold = 110;\r
209         // [AR]検出結果の保存用\r
210         private NyARBinRaster _bin_raster;\r
211 \r
212         private NyARRasterFilter_ARToolkitThreshold _tobin_filter;\r
213 \r
214         protected int _current_arcode_index = -1;\r
215 \r
216         private NyARRasterThresholdAnalyzer_SlidePTile _threshold_detect;\r
217         \r
218         protected SingleARMarkerProcesser()\r
219         {\r
220                 return;\r
221         }\r
222 \r
223         private boolean _initialized=false;\r
224 \r
225         protected void initInstance(NyARParam i_param,int i_raster_type) throws NyARException\r
226         {\r
227                 //初期化済?\r
228                 assert(this._initialized==false);\r
229                 \r
230                 NyARIntSize scr_size = i_param.getScreenSize();\r
231                 // 解析オブジェクトを作る\r
232                 this._square_detect = new NyARSquareContourDetector_Rle(i_param.getDistortionFactor(), scr_size);\r
233                 this._transmat = new NyARTransMat(i_param);\r
234                 this._tobin_filter=new NyARRasterFilter_ARToolkitThreshold(110,i_raster_type);\r
235 \r
236                 // 2値画像バッファを作る\r
237                 this._bin_raster = new NyARBinRaster(scr_size.w, scr_size.h);\r
238                 this._threshold_detect=new NyARRasterThresholdAnalyzer_SlidePTile(15,i_raster_type,4);\r
239                 this._initialized=true;\r
240                 //コールバックハンドラ\r
241                 this._detectmarker_cb=new DetectSquareCB(i_param);\r
242                 this._offset=new NyARRectOffset();\r
243                 return;\r
244         }\r
245 \r
246         /*自動・手動の設定が出来ないので、コメントアウト\r
247         public void setThreshold(int i_threshold)\r
248         {\r
249                 this._threshold = i_threshold;\r
250                 return;\r
251         }*/\r
252 \r
253         /**検出するマーカコードの配列を指定します。 検出状態でこの関数を実行すると、\r
254          * オブジェクト状態に強制リセットがかかります。\r
255          */\r
256         public void setARCodeTable(NyARCode[] i_ref_code_table, int i_code_resolution, double i_marker_width)\r
257         {\r
258                 if (this._current_arcode_index != -1) {\r
259                         // 強制リセット\r
260                         reset(true);\r
261                 }\r
262                 //検出するマーカセット、情報、検出器を作り直す。(1ピクセル4ポイントサンプリング,マーカのパターン領域は50%)\r
263                 this._detectmarker_cb.setNyARCodeTable(i_ref_code_table,i_code_resolution);\r
264                 this._offset.setSquare(i_marker_width);\r
265                 return;\r
266         }\r
267 \r
268         public void reset(boolean i_is_force)\r
269         {\r
270                 if (this._current_arcode_index != -1 && i_is_force == false) {\r
271                         // 強制書き換えでなければイベントコール\r
272                         this.onLeaveHandler();\r
273                 }\r
274                 // カレントマーカをリセット\r
275                 this._current_arcode_index = -1;\r
276                 return;\r
277         }\r
278         private DetectSquareCB _detectmarker_cb;\r
279         public void detectMarker(INyARRgbRaster i_raster) throws NyARException\r
280         {\r
281                 // サイズチェック\r
282                 assert(this._bin_raster.getSize().isEqualSize(i_raster.getSize().w, i_raster.getSize().h));\r
283 \r
284                 //BINイメージへの変換\r
285                 this._tobin_filter.setThreshold(this._threshold);\r
286                 this._tobin_filter.doFilter(i_raster, this._bin_raster);\r
287 \r
288                 // スクエアコードを探す\r
289                 this._detectmarker_cb.init(i_raster,this._current_arcode_index);\r
290                 this._square_detect.detectMarkerCB(this._bin_raster,this._detectmarker_cb);\r
291                 \r
292                 // 認識状態を更新\r
293                 final boolean is_id_found=updateStatus(this._detectmarker_cb.square,this._detectmarker_cb.code_index);\r
294                 //閾値フィードバック(detectExistMarkerにもあるよ)\r
295                 if(!is_id_found){\r
296                         //マーカがなければ、探索+DualPTailで基準輝度検索\r
297                         int th=this._threshold_detect.analyzeRaster(i_raster);\r
298                         this._threshold=(this._threshold+th)/2;\r
299                 }\r
300                 \r
301                 \r
302                 return;\r
303         }\r
304         /**\r
305          * \r
306          * @param i_new_detect_cf\r
307          * @param i_exist_detect_cf\r
308          */\r
309         public void setConfidenceThreshold(double i_new_cf,double i_exist_cf)\r
310         {\r
311                 this._detectmarker_cb.cf_threshold_exist=i_exist_cf;\r
312                 this._detectmarker_cb.cf_threshold_new=i_new_cf;\r
313         }\r
314 \r
315         private NyARTransMatResult __NyARSquare_result = new NyARTransMatResult();\r
316 \r
317         /**     オブジェクトのステータスを更新し、必要に応じてハンドル関数を駆動します。\r
318          *      戻り値は、「実際にマーカを発見する事ができたか」です。クラスの状態とは異なります。\r
319          */\r
320         private boolean updateStatus(NyARSquare i_square, int i_code_index)  throws NyARException\r
321         {\r
322                 NyARTransMatResult result = this.__NyARSquare_result;\r
323                 if (this._current_arcode_index < 0) {// 未認識中\r
324                         if (i_code_index < 0) {// 未認識から未認識の遷移\r
325                                 // なにもしないよーん。\r
326                                 return false;\r
327                         } else {// 未認識から認識の遷移\r
328                                 this._current_arcode_index = i_code_index;\r
329                                 // イベント生成\r
330                                 // OnEnter\r
331                                 this.onEnterHandler(i_code_index);\r
332                                 // 変換行列を作成\r
333                                 this._transmat.transMat(i_square, this._offset, result);\r
334                                 // OnUpdate\r
335                                 this.onUpdateHandler(i_square, result);\r
336                                 this._lost_delay_count = 0;\r
337                                 return true;\r
338                         }\r
339                 } else {// 認識中\r
340                         if (i_code_index < 0) {// 認識から未認識の遷移\r
341                                 this._lost_delay_count++;\r
342                                 if (this._lost_delay < this._lost_delay_count) {\r
343                                         // OnLeave\r
344                                         this._current_arcode_index = -1;\r
345                                         this.onLeaveHandler();\r
346                                 }\r
347                                 return false;\r
348                         } else if (i_code_index == this._current_arcode_index) {// 同じARCodeの再認識\r
349                                 // イベント生成\r
350                                 // 変換行列を作成\r
351                                 this._transmat.transMatContinue(i_square, this._offset, result);\r
352                                 // OnUpdate\r
353                                 this.onUpdateHandler(i_square, result);\r
354                                 this._lost_delay_count = 0;\r
355                                 return true;\r
356                         } else {// 異なるコードの認識→今はサポートしない。\r
357                                 throw new  NyARException();\r
358                         }\r
359                 }\r
360         }\r
361 \r
362         protected abstract void onEnterHandler(int i_code);\r
363 \r
364         protected abstract void onLeaveHandler();\r
365 \r
366         protected abstract void onUpdateHandler(NyARSquare i_square, NyARTransMatResult result);\r
367 }\r