OSDN Git Service

[Backup]NyARToolkit for Java
[nyartoolkit-and/nyartoolkit-and.git] / src / jp / nyatla / nyartoolkit / processor / SingleARMarkerProcesser.java
1 /* \r
2  * Capture Test NyARToolkitCSサンプルプログラム\r
3  * --------------------------------------------------------------------------------\r
4  * Copyright (C)2008 R.Iizuka\r
5  *\r
6  * This program is free software; you can redistribute it and/or\r
7  * modify it under the terms of the GNU General Public License\r
8  * as published by the Free Software Foundation; either version 2\r
9  * of the License, or (at your option) any later version.\r
10  * \r
11  * This program is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  * \r
16  * You should have received a copy of the GNU General Public License\r
17  * along with this framework; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  * \r
20  * For further information please contact.\r
21  *      http://nyatla.jp/nyatoolkit/\r
22  *      <airmail(at)ebony.plala.or.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.match.*;\r
30 import jp.nyatla.nyartoolkit.core.param.*;\r
31 import jp.nyatla.nyartoolkit.core.pickup.*;\r
32 import jp.nyatla.nyartoolkit.core.raster.*;\r
33 import jp.nyatla.nyartoolkit.core.raster.rgb.*;\r
34 import jp.nyatla.nyartoolkit.core.transmat.*;\r
35 import jp.nyatla.nyartoolkit.core.rasterfilter.rgb2bin.*;\r
36 import jp.nyatla.nyartoolkit.core.types.*;\r
37 import jp.nyatla.nyartoolkit.core.squaredetect.*;\r
38 import jp.nyatla.nyartoolkit.core2.rasteranalyzer.threshold.NyARRasterThresholdAnalyzer_SlidePTile;\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         /**selectARCodeIndexFromListが値を返す時に使う変数型です。\r
55          */\r
56 \r
57         private class TResult_selectARCodeIndex\r
58         {\r
59                 public int direction;\r
60 \r
61                 public double confidence;\r
62 \r
63                 public int code_index;\r
64         }\r
65         /**オーナーが自由に使えるタグ変数です。\r
66          */\r
67         public Object tag;\r
68 \r
69         private int _lost_delay_count = 0;\r
70 \r
71         private int _lost_delay = 5;\r
72 \r
73         private INyARSquareDetector _square_detect;\r
74 \r
75         protected INyARTransMat _transmat;\r
76 \r
77         private double _marker_width;\r
78 \r
79         private NyARMatchPatt_Color_WITHOUT_PCA[] _match_patt;\r
80 \r
81         private NyARSquareStack _square_list = new NyARSquareStack(100);\r
82 \r
83         private INyARColorPatt _patt = null;\r
84 \r
85         private double _cf_threshold_new = 0.30;\r
86         private double _cf_threshold_exist = 0.15;\r
87         \r
88         private int _threshold = 110;\r
89         // [AR]検出結果の保存用\r
90         private NyARBinRaster _bin_raster;\r
91 \r
92         private NyARRasterFilter_ARToolkitThreshold _tobin_filter;\r
93 \r
94         protected int _current_arcode_index = -1;\r
95 \r
96         private NyARMatchPattDeviationColorData _deviation_data;\r
97         private NyARRasterThresholdAnalyzer_SlidePTile _threshold_detect;\r
98         \r
99         protected SingleARMarkerProcesser()\r
100         {\r
101                 return;\r
102         }\r
103 \r
104 \r
105         protected void initInstance(NyARParam i_param,int i_raster_type) throws NyARException\r
106         {\r
107                 NyARIntSize scr_size = i_param.getScreenSize();\r
108                 // 解析オブジェクトを作る\r
109                 this._square_detect = new NyARSquareDetector_Rle(i_param.getDistortionFactor(), scr_size);\r
110                 this._transmat = new NyARTransMat_NyARToolkit(i_param);\r
111                 this._tobin_filter=new NyARRasterFilter_ARToolkitThreshold(110,i_raster_type);\r
112 \r
113                 // 2値画像バッファを作る\r
114                 this._bin_raster = new NyARBinRaster(scr_size.w, scr_size.h);\r
115                 this._threshold_detect=new NyARRasterThresholdAnalyzer_SlidePTile(15,i_raster_type,4);\r
116                 return;\r
117         }\r
118 \r
119         /*自動・手動の設定が出来ないので、コメントアウト\r
120         public void setThreshold(int i_threshold)\r
121         {\r
122                 this._threshold = i_threshold;\r
123                 return;\r
124         }*/\r
125 \r
126         /**検出するマーカコードの配列を指定します。 検出状態でこの関数を実行すると、\r
127          * オブジェクト状態に強制リセットがかかります。\r
128          */\r
129         public void setARCodeTable(NyARCode[] i_ref_code_table, int i_code_resolution, double i_marker_width)\r
130         {\r
131                 if (this._current_arcode_index != -1) {\r
132                         // 強制リセット\r
133                         reset(true);\r
134                 }\r
135                 //検出するマーカセット、情報、検出器を作り直す。(1ピクセル4ポイントサンプリング,マーカのパターン領域は50%)\r
136                 this._patt = new NyARColorPatt_Perspective_O2(i_code_resolution, i_code_resolution,4,25);\r
137                 this._deviation_data=new NyARMatchPattDeviationColorData(i_code_resolution, i_code_resolution);\r
138                 this._marker_width = i_marker_width;\r
139 \r
140                 this._match_patt = new NyARMatchPatt_Color_WITHOUT_PCA[i_ref_code_table.length];\r
141                 for(int i=0;i<i_ref_code_table.length;i++){\r
142                         this._match_patt[i]=new NyARMatchPatt_Color_WITHOUT_PCA(i_ref_code_table[i]);\r
143                 }\r
144                 return;\r
145         }\r
146 \r
147         public void reset(boolean i_is_force)\r
148         {\r
149                 if (this._current_arcode_index != -1 && i_is_force == false) {\r
150                         // 強制書き換えでなければイベントコール\r
151                         this.onLeaveHandler();\r
152                 }\r
153                 // カレントマーカをリセット\r
154                 this._current_arcode_index = -1;\r
155                 return;\r
156         }\r
157 \r
158         public void detectMarker(INyARRgbRaster i_raster) throws NyARException\r
159         {\r
160                 // サイズチェック\r
161                 assert(this._bin_raster.getSize().isEqualSize(i_raster.getSize().w, i_raster.getSize().h));\r
162 \r
163                 // コードテーブルが無ければここで終わり\r
164                 if (this._match_patt== null) {\r
165                         return;\r
166                 }\r
167 \r
168                 // ラスタを(1/4の画像の)2値イメージに変換する.\r
169                 this._tobin_filter.setThreshold(this._threshold);\r
170                 this._tobin_filter.doFilter(i_raster, this._bin_raster);\r
171 \r
172                 NyARSquareStack square_stack = this._square_list;\r
173                 // スクエアコードを探す\r
174                 this._square_detect.detectMarker(this._bin_raster, square_stack);\r
175                 // 認識処理\r
176                 if (this._current_arcode_index == -1) { // マーカ未認識\r
177                         detectNewMarker(i_raster, square_stack);\r
178                 } else { // マーカ認識中\r
179                         detectExistMarker(i_raster, square_stack, this._current_arcode_index);\r
180                 }\r
181                 return;\r
182         }\r
183 \r
184         \r
185         private final NyARMatchPattResult __detectMarkerLite_mr=new NyARMatchPattResult();\r
186         \r
187         /**ARCodeのリストから、最も一致するコード番号を検索します。\r
188          */\r
189         private boolean selectARCodeIndexFromList(INyARRgbRaster i_raster, NyARSquare i_square, TResult_selectARCodeIndex o_result) throws NyARException\r
190         {\r
191                 // 現在コードテーブルはアクティブ?\r
192                 if (this._match_patt==null) {\r
193                         return false;\r
194                 }\r
195                 // 評価基準になるパターンをイメージから切り出す\r
196                 if (!this._patt.pickFromRaster(i_raster, i_square)) {\r
197                         return false;\r
198                 }\r
199                 //評価データを作成して、評価器にセット\r
200                 this._deviation_data.setRaster(this._patt);             \r
201                 final NyARMatchPattResult mr=this.__detectMarkerLite_mr;\r
202                 int code_index = 0;\r
203                 int dir = 0;\r
204                 double c1 = 0;\r
205                 // コードと比較する\r
206                 for (int i = 0; i < this._match_patt.length; i++) {\r
207                         this._match_patt[i].evaluate(this._deviation_data,mr);\r
208                         double c2 = mr.confidence;\r
209                         if (c1 < c2) {\r
210                                 code_index = i;\r
211                                 c1 = c2;\r
212                                 dir = mr.direction;\r
213                         }\r
214                 }\r
215                 o_result.code_index = code_index;\r
216                 o_result.direction = dir;\r
217                 o_result.confidence = c1;\r
218                 return true;\r
219         }\r
220 \r
221         private TResult_selectARCodeIndex __detect_X_Marker_detect_result = new TResult_selectARCodeIndex();\r
222 \r
223         /**新規マーカ検索 現在認識中のマーカがないものとして、最も認識しやすいマーカを1個認識します。\r
224          */\r
225         private void detectNewMarker(INyARRgbRaster i_raster, NyARSquareStack i_stack) throws NyARException\r
226         {\r
227                 int number_of_square = i_stack.getLength();\r
228                 double cf = 0;\r
229                 int dir = 0;\r
230                 int code_index = -1;\r
231                 int square_index = 0;\r
232                 TResult_selectARCodeIndex detect_result = this.__detect_X_Marker_detect_result;\r
233                 for (int i = 0; i < number_of_square; i++) {\r
234                         if (!selectARCodeIndexFromList(i_raster, (i_stack.getItem(i)), detect_result)) {\r
235                                 // 見つからない。\r
236                                 return;\r
237                         }\r
238                         if (detect_result.confidence < this._cf_threshold_new) {\r
239                                 continue;\r
240                         }\r
241                         if (detect_result.confidence < cf) {\r
242                                 // 一致度が低い。\r
243                                 continue;\r
244                         }\r
245                         cf = detect_result.confidence;\r
246                         code_index = detect_result.code_index;\r
247                         square_index = i;\r
248                         dir = detect_result.direction;\r
249                 }\r
250                 // 認識状態を更新\r
251                 final boolean is_id_found=updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
252                 //閾値フィードバック(detectExistMarkerにもあるよ)\r
253                 if(!is_id_found){\r
254                         //マーカがなければ、探索+DualPTailで基準輝度検索\r
255                         this._threshold_detect.analyzeRaster(i_raster);\r
256                         this._threshold=(this._threshold+this._threshold_detect.getThreshold())/2;\r
257                 }\r
258         }\r
259 \r
260         /**マーカの継続認識 現在認識中のマーカを優先して認識します。 \r
261          * (注)この機能はたぶん今後いろいろ発展するからNewと混ぜないこと。\r
262          */\r
263         private void detectExistMarker(INyARRgbRaster i_raster, NyARSquareStack i_stack, int i_current_id) throws NyARException\r
264         {\r
265                 int number_of_square = i_stack.getLength();\r
266                 double cf = 0;\r
267                 int dir = 0;\r
268                 int code_index = -1;\r
269                 int square_index = 0;\r
270                 TResult_selectARCodeIndex detect_result = this.__detect_X_Marker_detect_result;\r
271                 for (int i = 0; i < number_of_square; i++) {\r
272                         if (!selectARCodeIndexFromList(i_raster,i_stack.getItem(i), detect_result)) {\r
273                                 // 見つからない。\r
274                                 return;\r
275                         }\r
276                         // 現在のマーカを認識したか?\r
277                         if (detect_result.code_index != i_current_id) {\r
278                                 // 認識中のマーカではないので無視\r
279                                 continue;\r
280                         }\r
281                         if (detect_result.confidence < this._cf_threshold_exist) {\r
282                                 continue;\r
283                         }\r
284                         if (detect_result.confidence < cf) {\r
285                                 // 一致度が高い方を選ぶ\r
286                                 continue;\r
287                         }\r
288                         cf = detect_result.confidence;\r
289                         code_index = detect_result.code_index;\r
290                         dir = detect_result.direction;\r
291                         square_index = i;\r
292                 }\r
293                 // 認識状態を更新\r
294                 final boolean is_id_found=updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
295                 //閾値フィードバック(detectExistMarkerにもあるよ)\r
296                 if(!is_id_found){\r
297                         //マーカがなければ、探索+DualPTailで基準輝度検索\r
298                         this._threshold_detect.analyzeRaster(i_raster);\r
299                         this._threshold=(this._threshold+this._threshold_detect.getThreshold())/2;\r
300                 }\r
301                 \r
302         }\r
303 \r
304         private NyARTransMatResult __NyARSquare_result = new NyARTransMatResult();\r
305 \r
306         /**     オブジェクトのステータスを更新し、必要に応じてハンドル関数を駆動します。\r
307          *      戻り値は、「実際にマーカを発見する事ができたか」です。クラスの状態とは異なります。\r
308          */\r
309         private boolean updateStatus(NyARSquare i_square, int i_code_index, double i_cf, int i_dir)  throws NyARException\r
310         {\r
311                 NyARTransMatResult result = this.__NyARSquare_result;\r
312                 if (this._current_arcode_index < 0) {// 未認識中\r
313                         if (i_code_index < 0) {// 未認識から未認識の遷移\r
314                                 // なにもしないよーん。\r
315                                 return false;\r
316                         } else {// 未認識から認識の遷移\r
317                                 this._current_arcode_index = i_code_index;\r
318                                 // イベント生成\r
319                                 // OnEnter\r
320                                 this.onEnterHandler(i_code_index);\r
321                                 // 変換行列を作成\r
322                                 this._transmat.transMat(i_square, i_dir, this._marker_width, result);\r
323                                 // OnUpdate\r
324                                 this.onUpdateHandler(i_square, result);\r
325                                 this._lost_delay_count = 0;\r
326                                 return true;\r
327                         }\r
328                 } else {// 認識中\r
329                         if (i_code_index < 0) {// 認識から未認識の遷移\r
330                                 this._lost_delay_count++;\r
331                                 if (this._lost_delay < this._lost_delay_count) {\r
332                                         // OnLeave\r
333                                         this._current_arcode_index = -1;\r
334                                         this.onLeaveHandler();\r
335                                 }\r
336                                 return false;\r
337                         } else if (i_code_index == this._current_arcode_index) {// 同じARCodeの再認識\r
338                                 // イベント生成\r
339                                 // 変換行列を作成\r
340                                 this._transmat.transMat(i_square, i_dir, this._marker_width, result);\r
341                                 // OnUpdate\r
342                                 this.onUpdateHandler(i_square, result);\r
343                                 this._lost_delay_count = 0;\r
344                                 return true;\r
345                         } else {// 異なるコードの認識→今はサポートしない。\r
346                                 throw new  NyARException();\r
347                         }\r
348                 }\r
349         }\r
350 \r
351         protected abstract void onEnterHandler(int i_code);\r
352 \r
353         protected abstract void onLeaveHandler();\r
354 \r
355         protected abstract void onUpdateHandler(NyARSquare i_square, NyARTransMatResult result);\r
356 }\r