OSDN Git Service

[TAG]NyARToolkit-2.0.0
[nyartoolkit-and/nyartoolkit-and.git] / branches / nyatla / src / jp / nyatla / nyartoolkit / detector / NyARDetectMarker.java
1 /* \r
2  * PROJECT: NyARToolkit\r
3  * --------------------------------------------------------------------------------\r
4  * This work is based on the original ARToolKit developed by\r
5  *   Hirokazu Kato\r
6  *   Mark Billinghurst\r
7  *   HITLab, University of Washington, Seattle\r
8  * http://www.hitl.washington.edu/artoolkit/\r
9  *\r
10  * The NyARToolkit is Java version ARToolkit class library.\r
11  * Copyright (C)2008 R.Iizuka\r
12  *\r
13  * This program is free software; you can redistribute it and/or\r
14  * modify it under the terms of the GNU General Public License\r
15  * as published by the Free Software Foundation; either version 2\r
16  * of the License, or (at your option) any later version.\r
17  * \r
18  * This program is distributed in the hope that it will be useful,\r
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
21  * GNU General Public License for more details.\r
22  * \r
23  * You should have received a copy of the GNU General Public License\r
24  * along with this framework; if not, write to the Free Software\r
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
26  * \r
27  * For further information please contact.\r
28  *      http://nyatla.jp/nyatoolkit/\r
29  *      <airmail(at)ebony.plala.or.jp>\r
30  * \r
31  */\r
32 package jp.nyatla.nyartoolkit.detector;\r
33 \r
34 import jp.nyatla.nyartoolkit.NyARException;\r
35 import jp.nyatla.nyartoolkit.core.*;\r
36 import jp.nyatla.nyartoolkit.core.match.*;\r
37 import jp.nyatla.nyartoolkit.core.param.NyARParam;\r
38 import jp.nyatla.nyartoolkit.core.pickup.*;\r
39 import jp.nyatla.nyartoolkit.core.raster.*;\r
40 import jp.nyatla.nyartoolkit.core.raster.rgb.*;\r
41 import jp.nyatla.nyartoolkit.core.transmat.*;\r
42 import jp.nyatla.nyartoolkit.core.rasterfilter.rgb2bin.*;\r
43 import jp.nyatla.nyartoolkit.core.types.*;\r
44 \r
45 class NyARDetectMarkerResult\r
46 {\r
47         public int arcode_id;\r
48 \r
49         public int direction;\r
50 \r
51         public double confidence;\r
52 \r
53         public NyARSquare ref_square;\r
54 }\r
55 \r
56 class NyARDetectMarkerResultHolder\r
57 {\r
58         public NyARDetectMarkerResult[] result_array = new NyARDetectMarkerResult[1];\r
59 \r
60         /**\r
61          * result_holderを最大i_reserve_size個の要素を格納できるように予約します。\r
62          * \r
63          * @param i_reserve_size\r
64          */\r
65         public void reservHolder(int i_reserve_size)\r
66         {\r
67                 if (i_reserve_size >= result_array.length) {\r
68                         int new_size = i_reserve_size + 5;\r
69                         result_array = new NyARDetectMarkerResult[new_size];\r
70                         for (int i = 0; i < new_size; i++) {\r
71                                 result_array[i] = new NyARDetectMarkerResult();\r
72                         }\r
73                 }\r
74         }\r
75 }\r
76 \r
77 /**\r
78  * 複数のマーカーを検出し、それぞれに最も一致するARコードを、コンストラクタで登録したARコードから 探すクラスです。最大300個を認識しますが、ゴミラベルを認識したりするので100個程度が限界です。\r
79  * \r
80  */\r
81 public class NyARDetectMarker\r
82 {\r
83         private static final int AR_SQUARE_MAX = 300;\r
84 \r
85         private boolean _is_continue = false;\r
86 \r
87         private NyARMatchPatt_Color_WITHOUT_PCA _match_patt;\r
88 \r
89         private INyARSquareDetector _square_detect;\r
90 \r
91         private final NyARSquareStack _square_list = new NyARSquareStack(AR_SQUARE_MAX);\r
92 \r
93         private NyARCode[] _codes;\r
94 \r
95         protected INyARTransMat _transmat;\r
96 \r
97         private double[] _marker_width;\r
98 \r
99         private int _number_of_code;\r
100 \r
101         // 検出結果の保存用\r
102         private INyARColorPatt _patt;\r
103 \r
104         private NyARDetectMarkerResultHolder _result_holder = new NyARDetectMarkerResultHolder();\r
105 \r
106         /**\r
107          * 複数のマーカーを検出し、最も一致するARCodeをi_codeから検索するオブジェクトを作ります。\r
108          * \r
109          * @param i_param\r
110          * カメラパラメータを指定します。\r
111          * @param i_code\r
112          * 検出するマーカーのARCode配列を指定します。配列要素のインデックス番号が、そのままgetARCodeIndex関数で 得られるARCodeインデックスになります。 例えば、要素[1]のARCodeに一致したマーカーである場合は、getARCodeIndexは1を返します。\r
113          * 先頭からi_number_of_code個の要素には、有効な値を指定する必要があります。\r
114          * @param i_marker_width\r
115          * i_codeのマーカーサイズをミリメートルで指定した配列を指定します。 先頭からi_number_of_code個の要素には、有効な値を指定する必要があります。\r
116          * @param i_number_of_code\r
117          * i_codeに含まれる、ARCodeの数を指定します。\r
118          * @throws NyARException\r
119          */\r
120         public NyARDetectMarker(NyARParam i_param, NyARCode[] i_code, double[] i_marker_width, int i_number_of_code) throws NyARException\r
121         {\r
122                 final NyARIntSize scr_size=i_param.getScreenSize();\r
123                 // 解析オブジェクトを作る\r
124                 this._square_detect = new NyARSquareDetector(i_param.getDistortionFactor(),scr_size);\r
125                 this._transmat = new NyARTransMat(i_param);\r
126                 // 比較コードを保存\r
127                 this._codes = i_code;\r
128                 // 比較コードの解像度は全部同じかな?(違うとパターンを複数種つくらないといけないから)\r
129                 final int cw = i_code[0].getWidth();\r
130                 final int ch = i_code[0].getHeight();\r
131                 for (int i = 1; i < i_number_of_code; i++) {\r
132                         if (cw != i_code[i].getWidth() || ch != i_code[i].getHeight()) {\r
133                                 // 違う解像度のが混ざっている。\r
134                                 throw new NyARException();\r
135                         }\r
136                 }\r
137                 // 評価パターンのホルダを作る\r
138                 this._patt = new NyARColorPatt_O3(cw, ch);\r
139                 this._number_of_code = i_number_of_code;\r
140 \r
141                 this._marker_width = i_marker_width;\r
142                 // 評価器を作る。\r
143                 this._match_patt = new NyARMatchPatt_Color_WITHOUT_PCA();\r
144                 //2値画像バッファを作る\r
145                 this._bin_raster=new NyARBinRaster(scr_size.w,scr_size.h);              \r
146         }\r
147 \r
148         private NyARBinRaster _bin_raster;\r
149 \r
150         private NyARRasterFilter_ARToolkitThreshold _tobin_filter = new NyARRasterFilter_ARToolkitThreshold(100);\r
151 \r
152         /**\r
153          * i_imageにマーカー検出処理を実行し、結果を記録します。\r
154          * \r
155          * @param i_raster\r
156          * マーカーを検出するイメージを指定します。\r
157          * @param i_thresh\r
158          * 検出閾値を指定します。0~255の範囲で指定してください。 通常は100~130くらいを指定します。\r
159          * @return 見つかったマーカーの数を返します。 マーカーが見つからない場合は0を返します。\r
160          * @throws NyARException\r
161          */\r
162         public int detectMarkerLite(INyARRgbRaster i_raster, int i_threshold) throws NyARException\r
163         {\r
164                 // サイズチェック\r
165                 if (!this._bin_raster.getSize().isEqualSize(i_raster.getSize())) {\r
166                         throw new NyARException();\r
167                 }\r
168 \r
169                 // ラスタを2値イメージに変換する.\r
170                 this._tobin_filter.setThreshold(i_threshold);\r
171                 this._tobin_filter.doFilter(i_raster, this._bin_raster);\r
172 \r
173                 NyARSquareStack l_square_list = this._square_list;\r
174                 // スクエアコードを探す\r
175                 this._square_detect.detectMarker(this._bin_raster, l_square_list);\r
176 \r
177                 final int number_of_square = l_square_list.getLength();\r
178                 // コードは見つかった?\r
179                 if (number_of_square < 1) {\r
180                         // ないや。おしまい。\r
181                         return 0;\r
182                 }\r
183                 // 保持リストのサイズを調整\r
184                 this._result_holder.reservHolder(number_of_square);\r
185 \r
186                 // 1スクエア毎に、一致するコードを決定していく\r
187                 for (int i = 0; i < number_of_square; i++) {\r
188                         NyARSquare square = (NyARSquare)l_square_list.getItem(i);\r
189                         // 評価基準になるパターンをイメージから切り出す\r
190                         if (!this._patt.pickFromRaster(i_raster, square)) {\r
191                                 // イメージの切り出しは失敗することもある。\r
192                                 continue;\r
193                         }\r
194                         // パターンを評価器にセット\r
195                         if (!this._match_patt.setPatt(this._patt)) {\r
196                                 // 計算に失敗した。\r
197                                 throw new NyARException();\r
198                         }\r
199                         // コードと順番に比較していく\r
200                         int code_index = 0;\r
201                         _match_patt.evaluate(_codes[0]);\r
202                         double confidence = _match_patt.getConfidence();\r
203                         int direction = _match_patt.getDirection();\r
204                         for (int i2 = 1; i2 < this._number_of_code; i2++) {\r
205                                 // コードと比較する\r
206                                 _match_patt.evaluate(_codes[i2]);\r
207                                 double c2 = _match_patt.getConfidence();\r
208                                 if (confidence > c2) {\r
209                                         continue;\r
210                                 }\r
211                                 // より一致するARCodeの情報を保存\r
212                                 code_index = i2;\r
213                                 direction = _match_patt.getDirection();\r
214                                 confidence = c2;\r
215                         }\r
216                         // i番目のパターン情報を保存する。\r
217                         final NyARDetectMarkerResult result = this._result_holder.result_array[i];\r
218                         result.arcode_id = code_index;\r
219                         result.confidence = confidence;\r
220                         result.direction = direction;\r
221                         result.ref_square = square;\r
222                 }\r
223                 return number_of_square;\r
224         }\r
225 \r
226         /**\r
227          * i_indexのマーカーに対する変換行列を計算し、結果値をo_resultへ格納します。 直前に実行したdetectMarkerLiteが成功していないと使えません。\r
228          * \r
229          * @param i_index\r
230          * マーカーのインデックス番号を指定します。 直前に実行したdetectMarkerLiteの戻り値未満かつ0以上である必要があります。\r
231          * @param o_result\r
232          * 結果値を受け取るオブジェクトを指定してください。\r
233          * @throws NyARException\r
234          */\r
235         public void getTransmationMatrix(int i_index, NyARTransMatResult o_result) throws NyARException\r
236         {\r
237                 final NyARDetectMarkerResult result = this._result_holder.result_array[i_index];\r
238                 // 一番一致したマーカーの位置とかその辺を計算\r
239                 if (_is_continue) {\r
240                         _transmat.transMatContinue(result.ref_square, result.direction, _marker_width[result.arcode_id], o_result);\r
241                 } else {\r
242                         _transmat.transMat(result.ref_square, result.direction, _marker_width[result.arcode_id], o_result);\r
243                 }\r
244                 return;\r
245         }\r
246 \r
247         /**\r
248          * i_indexのマーカーの一致度を返します。\r
249          * \r
250          * @param i_index\r
251          * マーカーのインデックス番号を指定します。 直前に実行したdetectMarkerLiteの戻り値未満かつ0以上である必要があります。\r
252          * @return マーカーの一致度を返します。0~1までの値をとります。 一致度が低い場合には、誤認識の可能性が高くなります。\r
253          * @throws NyARException\r
254          */\r
255         public double getConfidence(int i_index)\r
256         {\r
257                 return this._result_holder.result_array[i_index].confidence;\r
258         }\r
259 \r
260         /**\r
261          * i_indexのマーカーの方位を返します。\r
262          * \r
263          * @param i_index\r
264          * マーカーのインデックス番号を指定します。 直前に実行したdetectMarkerLiteの戻り値未満かつ0以上である必要があります。\r
265          * @return 0,1,2,3の何れかを返します。\r
266          */\r
267         public int getDirection(int i_index)\r
268         {\r
269                 return this._result_holder.result_array[i_index].direction;\r
270         }\r
271 \r
272         /**\r
273          * i_indexのマーカーのARCodeインデックスを返します。\r
274          * \r
275          * @param i_index\r
276          * マーカーのインデックス番号を指定します。 直前に実行したdetectMarkerLiteの戻り値未満かつ0以上である必要があります。\r
277          * @return\r
278          */\r
279         public int getARCodeIndex(int i_index)\r
280         {\r
281                 return this._result_holder.result_array[i_index].arcode_id;\r
282         }\r
283 \r
284         /**\r
285          * getTransmationMatrixの計算モードを設定します。\r
286          * \r
287          * @param i_is_continue\r
288          * TRUEなら、transMatContinueを使用します。 FALSEなら、transMatを使用します。\r
289          */\r
290         public void setContinueMode(boolean i_is_continue)\r
291         {\r
292                 this._is_continue = i_is_continue;\r
293         }\r
294 \r
295 }\r