OSDN Git Service

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