OSDN Git Service

[backup]NyARToolkit for Java
[nyartoolkit-and/nyartoolkit-and.git] / sample / sandbox / jp / nyatla / nyartoolkit / sandbox / x2 / SingleARMarkerProcesser_X2.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.sandbox.x2;\r
26 \r
27 import jp.nyatla.nyartoolkit.NyARException;\r
28 import jp.nyatla.nyartoolkit.core.*;\r
29 import jp.nyatla.nyartoolkit.core.analyzer.threshold.NyARRasterThresholdAnalyzerBuilder_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.gs2bin.*;\r
37 import jp.nyatla.nyartoolkit.core.rasterfilter.rgb2bin.NyARRasterFilterBuilder_RgbToBin;\r
38 import jp.nyatla.nyartoolkit.core.rasterfilter.rgb2bin.NyARRasterFilter_ARToolkitThreshold;\r
39 import jp.nyatla.nyartoolkit.core.types.*;\r
40 import jp.nyatla.nyartoolkit.core.squaredetect.*;\r
41 \r
42 /**\r
43  * このクラスは、同時に1個のマーカを処理することのできる、アプリケーションプロセッサです。\r
44  * マーカの出現・移動・消滅を、イベントで通知することができます。\r
45  * クラスには複数のマーカを登録できます。一つのマーカが見つかると、プロセッサは継続して同じマーカを\r
46  * 1つだけ認識し続け、見失うまでの間は他のマーカを認識しません。\r
47  * \r
48  * イベントは、 OnEnter→OnUpdate[n]→OnLeaveの順で発生します。\r
49  * マーカが見つかるとまずOnEnterが1度発生して、何番のマーカが発見されたかがわかります。\r
50  * 次にOnUpdateにより、現在の変換行列が連続して渡されます。最後にマーカを見失うと、OnLeave\r
51  * イベントが発生します。\r
52  * \r
53  */\r
54 public abstract class SingleARMarkerProcesser_X2\r
55 {\r
56         /**selectARCodeIndexFromListが値を返す時に使う変数型です。\r
57          */\r
58 \r
59         private class TResult_selectARCodeIndex\r
60         {\r
61                 public int direction;\r
62 \r
63                 public double confidence;\r
64 \r
65                 public int code_index;\r
66         }\r
67         /**オーナーが自由に使えるタグ変数です。\r
68          */\r
69         public Object tag;\r
70 \r
71         private int _lost_delay_count = 0;\r
72 \r
73         private int _lost_delay = 5;\r
74 \r
75         private INyARSquareContourDetector _square_detect;\r
76 \r
77         //<X2 patch>\r
78         protected NyARTransMat_X2 _transmat;\r
79         //</X2 patch>\r
80         private double _marker_width;\r
81 \r
82         private NyARMatchPatt_Color_WITHOUT_PCA[] _match_patt;\r
83 \r
84         private NyARSquareStack _square_list = new NyARSquareStack(100);\r
85 \r
86         private INyARColorPatt _patt = null;\r
87 \r
88         private double _cf_threshold_new = 0.30;\r
89         private double _cf_threshold_exist = 0.15;\r
90         \r
91         private int _threshold = 110;\r
92         // [AR]検出結果の保存用\r
93         private NyARBinRaster _bin_raster;\r
94 \r
95         private NyARRasterFilter_ARToolkitThreshold _tobin_filter;\r
96 \r
97         protected int _current_arcode_index = -1;\r
98 \r
99         private NyARMatchPattDeviationColorData _deviation_data;\r
100         private NyARRasterThresholdAnalyzerBuilder_Threshold _threshold_detect;\r
101         \r
102         protected SingleARMarkerProcesser_X2()\r
103         {\r
104                 return;\r
105         }\r
106 \r
107 \r
108         protected void initInstance(NyARParam i_param,int i_raster_type) throws NyARException\r
109         {\r
110                 NyARIntSize scr_size = i_param.getScreenSize();\r
111                 // 解析オブジェクトを作る\r
112 //<X2 patch>\r
113                 this._square_detect = new NyARSquareDetector_X2(i_param.getDistortionFactor(), scr_size);\r
114                 this._transmat = new NyARTransMat_X2(i_param);\r
115 //</X2 patch>\r
116 \r
117                 this._tobin_filter=new NyARRasterFilter_ARToolkitThreshold(110,i_raster_type);\r
118 \r
119                 // 2値画像バッファを作る\r
120                 this._bin_raster = new NyARBinRaster(scr_size.w, scr_size.h);\r
121                 this._threshold_detect=new NyARRasterThresholdAnalyzerBuilder_Threshold(15,i_raster_type,4);\r
122                 return;\r
123         }\r
124 \r
125         /**検出するマーカコードの配列を指定します。 検出状態でこの関数を実行すると、\r
126          * オブジェクト状態に強制リセットがかかります。\r
127          */\r
128         public void setARCodeTable(NyARCode[] i_ref_code_table, int i_code_resolution, double i_marker_width)\r
129         {\r
130                 if (this._current_arcode_index != -1) {\r
131                         // 強制リセット\r
132                         reset(true);\r
133                 }\r
134                 //検出するマーカセット、情報、検出器を作り直す。(1ピクセル4ポイントサンプリング,マーカのパターン領域は50%)\r
135                 this._patt = new NyARColorPatt_Perspective_O2(i_code_resolution, i_code_resolution,4,25);\r
136                 this._deviation_data=new NyARMatchPattDeviationColorData(i_code_resolution, i_code_resolution);\r
137                 this._marker_width = i_marker_width;\r
138 \r
139                 this._match_patt = new NyARMatchPatt_Color_WITHOUT_PCA[i_ref_code_table.length];\r
140                 for(int i=0;i<i_ref_code_table.length;i++){\r
141                         this._match_patt[i]=new NyARMatchPatt_Color_WITHOUT_PCA(i_ref_code_table[i]);\r
142                 }\r
143                 return;\r
144         }\r
145 \r
146         public void reset(boolean i_is_force)\r
147         {\r
148                 if (this._current_arcode_index != -1 && i_is_force == false) {\r
149                         // 強制書き換えでなければイベントコール\r
150                         this.onLeaveHandler();\r
151                 }\r
152                 // カレントマーカをリセット\r
153                 this._current_arcode_index = -1;\r
154                 return;\r
155         }\r
156 \r
157         public void detectMarker(INyARRgbRaster i_raster) throws NyARException\r
158         {\r
159                 // サイズチェック\r
160                 assert(this._bin_raster.getSize().isEqualSize(i_raster.getSize().w, i_raster.getSize().h));\r
161 \r
162                 // コードテーブルが無ければここで終わり\r
163                 if (this._match_patt== null) {\r
164                         return;\r
165                 }\r
166 \r
167                 // ラスタを(1/4の画像の)2値イメージに変換する.\r
168                 this._tobin_filter.setThreshold(this._threshold);\r
169                 this._tobin_filter.doFilter(i_raster, this._bin_raster);\r
170 \r
171                 NyARSquareStack square_stack = this._square_list;\r
172                 // スクエアコードを探す\r
173                 this._square_detect.detectMarkerCB(this._bin_raster, square_stack);\r
174                 // 認識処理\r
175                 if (this._current_arcode_index == -1) { // マーカ未認識\r
176                         detectNewMarker(i_raster, square_stack);\r
177                 } else { // マーカ認識中\r
178                         detectExistMarker(i_raster, square_stack, this._current_arcode_index);\r
179                 }\r
180                 return;\r
181         }\r
182 \r
183         \r
184         private final NyARMatchPattResult __detectMarkerLite_mr=new NyARMatchPattResult();\r
185         \r
186         /**ARCodeのリストから、最も一致するコード番号を検索します。\r
187          */\r
188         private boolean selectARCodeIndexFromList(INyARRgbRaster i_raster, NyARSquare i_square, TResult_selectARCodeIndex o_result) throws NyARException\r
189         {\r
190                 // 現在コードテーブルはアクティブ?\r
191                 if (this._match_patt==null) {\r
192                         return false;\r
193                 }\r
194                 // 評価基準になるパターンをイメージから切り出す\r
195                 if (!this._patt.pickFromRaster(i_raster, i_square.imvertex)) {\r
196                         return false;\r
197                 }\r
198                 //評価データを作成して、評価器にセット\r
199                 this._deviation_data.setRaster(this._patt);             \r
200                 final NyARMatchPattResult mr=this.__detectMarkerLite_mr;\r
201                 int code_index = 0;\r
202                 int dir = 0;\r
203                 double c1 = 0;\r
204                 // コードと比較する\r
205                 for (int i = 0; i < this._match_patt.length; i++) {\r
206                         this._match_patt[i].evaluate(this._deviation_data,mr);\r
207                         double c2 = mr.confidence;\r
208                         if (c1 < c2) {\r
209                                 code_index = i;\r
210                                 c1 = c2;\r
211                                 dir = mr.direction;\r
212                         }\r
213                 }\r
214                 o_result.code_index = code_index;\r
215                 o_result.direction = dir;\r
216                 o_result.confidence = c1;\r
217                 return true;\r
218         }\r
219 \r
220         private TResult_selectARCodeIndex __detect_X_Marker_detect_result = new TResult_selectARCodeIndex();\r
221 \r
222         /**新規マーカ検索 現在認識中のマーカがないものとして、最も認識しやすいマーカを1個認識します。\r
223          */\r
224         private void detectNewMarker(INyARRgbRaster i_raster, NyARSquareStack i_stack) throws NyARException\r
225         {\r
226                 int number_of_square = i_stack.getLength();\r
227                 double cf = 0;\r
228                 int dir = 0;\r
229                 int code_index = -1;\r
230                 int square_index = 0;\r
231                 TResult_selectARCodeIndex detect_result = this.__detect_X_Marker_detect_result;\r
232                 for (int i = 0; i < number_of_square; i++) {\r
233                         if (!selectARCodeIndexFromList(i_raster, (i_stack.getItem(i)), detect_result)) {\r
234                                 // 見つからない。\r
235                                 return;\r
236                         }\r
237                         if (detect_result.confidence < this._cf_threshold_new) {\r
238                                 continue;\r
239                         }\r
240                         if (detect_result.confidence < cf) {\r
241                                 // 一致度が低い。\r
242                                 continue;\r
243                         }\r
244                         cf = detect_result.confidence;\r
245                         code_index = detect_result.code_index;\r
246                         square_index = i;\r
247                         dir = detect_result.direction;\r
248                 }\r
249                 // 認識状態を更新\r
250                 final boolean is_id_found=updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
251                 //閾値フィードバック(detectExistMarkerにもあるよ)\r
252                 if(!is_id_found){\r
253                         //マーカがなければ、探索+DualPTailで基準輝度検索\r
254                         this._threshold_detect.analyzeRaster(i_raster);\r
255                         this._threshold=(this._threshold+this._threshold_detect.getThreshold())/2;\r
256                 }\r
257         }\r
258 \r
259         /**マーカの継続認識 現在認識中のマーカを優先して認識します。 \r
260          * (注)この機能はたぶん今後いろいろ発展するからNewと混ぜないこと。\r
261          */\r
262         private void detectExistMarker(INyARRgbRaster i_raster, NyARSquareStack i_stack, int i_current_id) throws NyARException\r
263         {\r
264                 int number_of_square = i_stack.getLength();\r
265                 double cf = 0;\r
266                 int dir = 0;\r
267                 int code_index = -1;\r
268                 int square_index = 0;\r
269                 TResult_selectARCodeIndex detect_result = this.__detect_X_Marker_detect_result;\r
270                 for (int i = 0; i < number_of_square; i++) {\r
271                         if (!selectARCodeIndexFromList(i_raster,i_stack.getItem(i), detect_result)) {\r
272                                 // 見つからない。\r
273                                 return;\r
274                         }\r
275                         // 現在のマーカを認識したか?\r
276                         if (detect_result.code_index != i_current_id) {\r
277                                 // 認識中のマーカではないので無視\r
278                                 continue;\r
279                         }\r
280                         if (detect_result.confidence < this._cf_threshold_exist) {\r
281                                 continue;\r
282                         }\r
283                         if (detect_result.confidence < cf) {\r
284                                 // 一致度が高い方を選ぶ\r
285                                 continue;\r
286                         }\r
287                         cf = detect_result.confidence;\r
288                         code_index = detect_result.code_index;\r
289                         dir = detect_result.direction;\r
290                         square_index = i;\r
291                 }\r
292                 // 認識状態を更新\r
293                 final boolean is_id_found=updateStatus(this._square_list.getItem(square_index), code_index, cf, dir);\r
294                 //閾値フィードバック(detectExistMarkerにもあるよ)\r
295                 if(!is_id_found){\r
296                         //マーカがなければ、探索+DualPTailで基準輝度検索\r
297                         this._threshold_detect.analyzeRaster(i_raster);\r
298                         this._threshold=(this._threshold+this._threshold_detect.getThreshold())/2;\r
299                 }\r
300                 \r
301         }\r
302 \r
303         private NyARTransMatResult __NyARSquare_result = new NyARTransMatResult();\r
304 \r
305         /**     オブジェクトのステータスを更新し、必要に応じてハンドル関数を駆動します。\r
306          *      戻り値は、「実際にマーカを発見する事ができたか」です。クラスの状態とは異なります。\r
307          */\r
308         private boolean updateStatus(NyARSquare i_square, int i_code_index, double i_cf, int i_dir)  throws NyARException\r
309         {\r
310                 NyARTransMatResult result = this.__NyARSquare_result;\r
311                 if (this._current_arcode_index < 0) {// 未認識中\r
312                         if (i_code_index < 0) {// 未認識から未認識の遷移\r
313                                 // なにもしないよーん。\r
314                                 return false;\r
315                         } else {// 未認識から認識の遷移\r
316                                 this._current_arcode_index = i_code_index;\r
317                                 // イベント生成\r
318                                 // OnEnter\r
319                                 this.onEnterHandler(i_code_index);\r
320                                 // 変換行列を作成\r
321                                 this._transmat.transMat(i_square, i_dir, this._marker_width, result);\r
322                                 // OnUpdate\r
323                                 this.onUpdateHandler(i_square, result);\r
324                                 this._lost_delay_count = 0;\r
325                                 return true;\r
326                         }\r
327                 } else {// 認識中\r
328                         if (i_code_index < 0) {// 認識から未認識の遷移\r
329                                 this._lost_delay_count++;\r
330                                 if (this._lost_delay < this._lost_delay_count) {\r
331                                         // OnLeave\r
332                                         this._current_arcode_index = -1;\r
333                                         this.onLeaveHandler();\r
334                                 }\r
335                                 return false;\r
336                         } else if (i_code_index == this._current_arcode_index) {// 同じARCodeの再認識\r
337                                 // イベント生成\r
338                                 // 変換行列を作成\r
339                                 this._transmat.transMat(i_square, i_dir, this._marker_width, result);\r
340                                 // OnUpdate\r
341                                 this.onUpdateHandler(i_square, result);\r
342                                 this._lost_delay_count = 0;\r
343                                 return true;\r
344                         } else {// 異なるコードの認識→今はサポートしない。\r
345                                 throw new  NyARException();\r
346                         }\r
347                 }\r
348         }\r
349 \r
350         protected abstract void onEnterHandler(int i_code);\r
351 \r
352         protected abstract void onLeaveHandler();\r
353 \r
354         protected abstract void onUpdateHandler(NyARSquare i_square, NyARTransMatResult result);\r
355 }\r