OSDN Git Service

Merge branch 'git-svn'
[nyartoolkit-and/nyartoolkit-and.git] / tags / 2.2.0 / src / jp / nyatla / nyartoolkit / core / labeling / NyARLabeling_ARToolKit.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.core.labeling;\r
33 \r
34 import jp.nyatla.nyartoolkit.NyARException;\r
35 import jp.nyatla.nyartoolkit.core.raster.*;\r
36 import jp.nyatla.nyartoolkit.core.types.*;\r
37 \r
38 /**\r
39  * ARToolKit互換のラベリングクラスです。 ARToolKitと同一な評価結果を返します。\r
40  * \r
41  */\r
42 public class NyARLabeling_ARToolKit implements INyARLabeling\r
43 {\r
44         private static final int WORK_SIZE = 1024 * 32;// #define WORK_SIZE 1024*32\r
45 \r
46         private final NyARWorkHolder work_holder = new NyARWorkHolder(WORK_SIZE);\r
47 \r
48         private NyARIntSize _dest_size;\r
49 \r
50         private INyARLabelingImage _out_image;\r
51 \r
52         public void attachDestination(INyARLabelingImage i_destination_image) throws NyARException\r
53         {\r
54                 // サイズチェック\r
55                 NyARIntSize size = i_destination_image.getSize();\r
56                 this._out_image = i_destination_image;\r
57 \r
58                 // NyLabelingImageのイメージ初期化(枠書き)\r
59                 int[] img = (int[]) i_destination_image.getBufferReader().getBuffer();\r
60                 int bottom_ptr = (size.h - 1) * size.w;\r
61                 for (int i = 0; i < size.w; i++) {\r
62                         img[i] = 0;\r
63                         img[bottom_ptr + i] = 0;\r
64                 }\r
65                 for (int i = 0; i < size.h; i++) {\r
66                         img[i * size.w] = 0;\r
67                         img[(i + 1) * size.w - 1] = 0;\r
68                 }\r
69 \r
70                 // サイズ(参照値)を保存\r
71                 this._dest_size = size;\r
72                 return;\r
73         }\r
74 \r
75         public INyARLabelingImage getAttachedDestination()\r
76         {\r
77                 return this._out_image;\r
78         }\r
79 \r
80         /**\r
81          * static ARInt16 *labeling2( ARUint8 *image, int thresh,int *label_num, int **area, double **pos, int **clip,int **label_ref, int LorR ) 関数の代替品\r
82          * ラスタimageをラベリングして、結果を保存します。 Optimize:STEP[1514->1493]\r
83          * \r
84          * @param i_raster\r
85          * @throws NyARException\r
86          */\r
87         public void labeling(NyARBinRaster i_raster) throws NyARException\r
88         {\r
89                 int label_img_ptr1, label_pixel;\r
90                 int i, j;\r
91                 int n, k; /* work */\r
92 \r
93                 // サイズチェック\r
94                 NyARIntSize in_size = i_raster.getSize();\r
95                 this._dest_size.isEqualSize(in_size);\r
96 \r
97                 final int lxsize = in_size.w;// lxsize = arUtil_c.arImXsize;\r
98                 final int lysize = in_size.h;// lysize = arUtil_c.arImYsize;\r
99                 final int[] label_img = (int[]) this._out_image.getBufferReader().getBuffer();\r
100 \r
101                 // 枠作成はインスタンスを作った直後にやってしまう。\r
102 \r
103                 // ラベリング情報のリセット(ラベリングインデックスを使用)\r
104                 this._out_image.reset(true);\r
105 \r
106                 int[] label_idxtbl = this._out_image.getIndexArray();\r
107                 int[] raster_buf = (int[]) i_raster.getBufferReader().getBuffer();\r
108 \r
109                 int[] work2_pt;\r
110                 int wk_max = 0;\r
111 \r
112                 int pixel_index;\r
113                 int[][] work2 = this.work_holder.work2;\r
114 \r
115                 // [1,1](ptr0)と、[0,1](ptr1)のインデクス値を計算する。\r
116                 for (j = 1; j < lysize - 1; j++) {// for (int j = 1; j < lysize - 1;j++, pnt += poff*2, pnt2 += 2) {\r
117                         pixel_index = j * lxsize + 1;\r
118                         label_img_ptr1 = pixel_index - lxsize;// label_img_pt1 = label_img[j - 1];\r
119                         for (i = 1; i < lxsize - 1; i++, pixel_index++, label_img_ptr1++) {// for(int i = 1; i < lxsize-1;i++, pnt+=poff, pnt2++) {\r
120                                 // RGBの合計値が閾値より小さいかな?\r
121                                 if (raster_buf[pixel_index] != 0) {\r
122                                         label_img[pixel_index] = 0;// label_img_pt0[i] = 0;// *pnt2 = 0;\r
123                                 } else {\r
124                                         // pnt1 = ShortPointer.wrap(pnt2, -lxsize);//pnt1 =&(pnt2[-lxsize]);\r
125                                         if (label_img[label_img_ptr1] > 0) {// if (label_img_pt1[i] > 0) {// if( *pnt1 > 0 ) {\r
126                                                 label_pixel = label_img[label_img_ptr1];// label_pixel = label_img_pt1[i];// *pnt2 = *pnt1;\r
127 \r
128                                                 work2_pt = work2[label_pixel - 1];\r
129                                                 work2_pt[0]++;// work2[((*pnt2)-1)*7+0] ++;\r
130                                                 work2_pt[1] += i;// work2[((*pnt2)-1)*7+1] += i;\r
131                                                 work2_pt[2] += j;// work2[((*pnt2)-1)*7+2] += j;\r
132                                                 work2_pt[6] = j;// work2[((*pnt2)-1)*7+6] = j;\r
133                                         } else if (label_img[label_img_ptr1 + 1] > 0) {// } else if (label_img_pt1[i + 1] > 0) {// }else if(*(pnt1+1) > 0 ) {\r
134                                                 if (label_img[label_img_ptr1 - 1] > 0) {// if (label_img_pt1[i - 1] > 0) {// if( *(pnt1-1) > 0 ) {\r
135                                                         label_pixel = label_idxtbl[label_img[label_img_ptr1 + 1] - 1];// m = label_idxtbl[label_img_pt1[i + 1] - 1];// m\r
136                                                                                                                                                                                         // =work[*(pnt1+1)-1];\r
137                                                         n = label_idxtbl[label_img[label_img_ptr1 - 1] - 1];// n = label_idxtbl[label_img_pt1[i - 1] - 1];// n =work[*(pnt1-1)-1];\r
138                                                         if (label_pixel > n) {\r
139                                                                 // wk=IntPointer.wrap(work, 0);//wk = &(work[0]);\r
140                                                                 for (k = 0; k < wk_max; k++) {\r
141                                                                         if (label_idxtbl[k] == label_pixel) {// if( *wk == m )\r
142                                                                                 label_idxtbl[k] = n;// *wk = n;\r
143                                                                         }\r
144                                                                 }\r
145                                                                 label_pixel = n;// *pnt2 = n;\r
146                                                         } else if (label_pixel < n) {\r
147                                                                 // wk=IntPointer.wrap(work,0);//wk = &(work[0]);\r
148                                                                 for (k = 0; k < wk_max; k++) {\r
149                                                                         if (label_idxtbl[k] == n) {// if( *wk == n ){\r
150                                                                                 label_idxtbl[k] = label_pixel;// *wk = m;\r
151                                                                         }\r
152                                                                 }\r
153                                                         }\r
154                                                         work2_pt = work2[label_pixel - 1];\r
155                                                         work2_pt[0]++;\r
156                                                         work2_pt[1] += i;\r
157                                                         work2_pt[2] += j;\r
158                                                         work2_pt[6] = j;\r
159                                                 } else if ((label_img[pixel_index - 1]) > 0) {// } else if ((label_img_pt0[i - 1]) > 0) {// }else if(*(pnt2-1) > 0) {\r
160                                                         label_pixel = label_idxtbl[label_img[label_img_ptr1 + 1] - 1];// m = label_idxtbl[label_img_pt1[i + 1] - 1];// m =work[*(pnt1+1)-1];\r
161                                                         n = label_idxtbl[label_img[pixel_index - 1] - 1];// n = label_idxtbl[label_img_pt0[i - 1] - 1];// n =work[*(pnt2-1)-1];\r
162                                                         if (label_pixel > n) {\r
163                                                                 for (k = 0; k < wk_max; k++) {\r
164                                                                         if (label_idxtbl[k] == label_pixel) {// if( *wk == m ){\r
165                                                                                 label_idxtbl[k] = n;// *wk = n;\r
166                                                                         }\r
167                                                                 }\r
168                                                                 label_pixel = n;// *pnt2 = n;\r
169                                                         } else if (label_pixel < n) {\r
170                                                                 for (k = 0; k < wk_max; k++) {\r
171                                                                         if (label_idxtbl[k] == n) {// if( *wk == n ){\r
172                                                                                 label_idxtbl[k] = label_pixel;// *wk = m;\r
173                                                                         }\r
174                                                                 }\r
175                                                         }\r
176                                                         work2_pt = work2[label_pixel - 1];\r
177                                                         work2_pt[0]++;// work2[((*pnt2)-1)*7+0] ++;\r
178                                                         work2_pt[1] += i;// work2[((*pnt2)-1)*7+1] += i;\r
179                                                         work2_pt[2] += j;// work2[((*pnt2)-1)*7+2] += j;\r
180                                                 } else {\r
181 \r
182                                                         label_pixel = label_img[label_img_ptr1 + 1];// label_pixel = label_img_pt1[i + 1];// *pnt2 =\r
183                                                         // *(pnt1+1);\r
184 \r
185                                                         work2_pt = work2[label_pixel - 1];\r
186                                                         work2_pt[0]++;// work2[((*pnt2)-1)*7+0] ++;\r
187                                                         work2_pt[1] += i;// work2[((*pnt2)-1)*7+1] += i;\r
188                                                         work2_pt[2] += j;// work2[((*pnt2)-1)*7+2] += j;\r
189                                                         if (work2_pt[3] > i) {// if(work2[((*pnt2)-1)*7+3] > i ){\r
190                                                                 work2_pt[3] = i;// work2[((*pnt2)-1)*7+3] = i;\r
191                                                         }\r
192                                                         work2_pt[6] = j;// work2[((*pnt2)-1)*7+6] = j;\r
193                                                 }\r
194                                         } else if ((label_img[label_img_ptr1 - 1]) > 0) {// } else if ((label_img_pt1[i - 1]) > 0) {// }else if(\r
195                                                 // *(pnt1-1) > 0 ) {\r
196                                                 label_pixel = label_img[label_img_ptr1 - 1];// label_pixel = label_img_pt1[i - 1];// *pnt2 =\r
197                                                 // *(pnt1-1);\r
198 \r
199                                                 work2_pt = work2[label_pixel - 1];\r
200                                                 work2_pt[0]++;// work2[((*pnt2)-1)*7+0] ++;\r
201                                                 work2_pt[1] += i;// work2[((*pnt2)-1)*7+1] += i;\r
202                                                 work2_pt[2] += j;// work2[((*pnt2)-1)*7+2] += j;\r
203                                                 if (work2_pt[4] < i) {// if( work2[((*pnt2)-1)*7+4] <i ){\r
204                                                         work2_pt[4] = i;// work2[((*pnt2)-1)*7+4] = i;\r
205                                                 }\r
206                                                 work2_pt[6] = j;// work2[((*pnt2)-1)*7+6] = j;\r
207                                         } else if (label_img[pixel_index - 1] > 0) {// } else if (label_img_pt0[i - 1] > 0) {// }else if(*(pnt2-1) > 0) {\r
208                                                 label_pixel = label_img[pixel_index - 1];// label_pixel = label_img_pt0[i - 1];// *pnt2 =*(pnt2-1);\r
209 \r
210                                                 work2_pt = work2[label_pixel - 1];\r
211                                                 work2_pt[0]++;// work2[((*pnt2)-1)*7+0] ++;\r
212                                                 work2_pt[1] += i;// work2[((*pnt2)-1)*7+1] += i;\r
213                                                 work2_pt[2] += j;// work2[((*pnt2)-1)*7+2] += j;\r
214                                                 if (work2_pt[4] < i) {// if( work2[((*pnt2)-1)*7+4] <i ){\r
215                                                         work2_pt[4] = i;// work2[((*pnt2)-1)*7+4] = i;\r
216                                                 }\r
217                                         } else {\r
218                                                 // 現在地までの領域を予約\r
219                                                 this.work_holder.reserv(wk_max);\r
220                                                 wk_max++;\r
221                                                 label_idxtbl[wk_max - 1] = wk_max;\r
222                                                 label_pixel = wk_max;// work[wk_max-1] = *pnt2 = wk_max;\r
223                                                 work2_pt = work2[wk_max - 1];\r
224                                                 work2_pt[0] = 1;\r
225                                                 work2_pt[1] = i;\r
226                                                 work2_pt[2] = j;\r
227                                                 work2_pt[3] = i;\r
228                                                 work2_pt[4] = i;\r
229                                                 work2_pt[5] = j;\r
230                                                 work2_pt[6] = j;\r
231                                         }\r
232                                         label_img[pixel_index] = label_pixel;// label_img_pt0[i] = label_pixel;\r
233                                 }\r
234                         }\r
235 \r
236                 }\r
237                 // インデックステーブルとラベル数の計算\r
238                 int wlabel_num = 1;// *label_num = *wlabel_num = j - 1;\r
239 \r
240                 for (i = 0; i < wk_max; i++) {// for(int i = 1; i <= wk_max; i++,wk++) {\r
241                         label_idxtbl[i] = (label_idxtbl[i] == i + 1) ? wlabel_num++ : label_idxtbl[label_idxtbl[i] - 1];// *wk=(*wk==i)?j++:work[(*wk)-1];\r
242                 }\r
243                 wlabel_num -= 1;// *label_num = *wlabel_num = j - 1;\r
244                 if (wlabel_num == 0) {// if( *label_num == 0 ) {\r
245                         // 発見数0\r
246                         this._out_image.getLabelStack().clear();\r
247                         return;\r
248                 }\r
249                 // ラベル情報の保存等\r
250                 NyARLabelingLabelStack label_list = this._out_image.getLabelStack();\r
251 \r
252                 // ラベルバッファを予約\r
253                 label_list.reserv(wlabel_num);\r
254 \r
255                 // エリアと重心、クリップ領域を計算\r
256                 NyARLabelingLabel label_pt;\r
257                 NyARLabelingLabel[] labels = (NyARLabelingLabel[]) label_list.getArray();\r
258                 for (i = 0; i < wlabel_num; i++) {\r
259                         label_pt = labels[i];\r
260                         label_pt.id = i + 1;\r
261                         label_pt.area = 0;\r
262                         label_pt.pos_x = label_pt.pos_y = 0;\r
263                         label_pt.clip_l = lxsize;// wclip[i*4+0] = lxsize;\r
264                         label_pt.clip_t = lysize;// wclip[i*4+2] = lysize;\r
265                         label_pt.clip_r = label_pt.clip_b = 0;// wclip[i*4+3] = 0;\r
266                 }\r
267 \r
268                 for (i = 0; i < wk_max; i++) {\r
269                         label_pt = labels[label_idxtbl[i] - 1];\r
270                         work2_pt = work2[i];\r
271                         label_pt.area += work2_pt[0];\r
272                         label_pt.pos_x += work2_pt[1];\r
273                         label_pt.pos_y += work2_pt[2];\r
274                         if (label_pt.clip_l > work2_pt[3]) {\r
275                                 label_pt.clip_l = work2_pt[3];\r
276                         }\r
277                         if (label_pt.clip_r < work2_pt[4]) {\r
278                                 label_pt.clip_r = work2_pt[4];\r
279                         }\r
280                         if (label_pt.clip_t > work2_pt[5]) {\r
281                                 label_pt.clip_t = work2_pt[5];\r
282                         }\r
283                         if (label_pt.clip_b < work2_pt[6]) {\r
284                                 label_pt.clip_b = work2_pt[6];\r
285                         }\r
286                 }\r
287 \r
288                 for (i = 0; i < wlabel_num; i++) {// for(int i = 0; i < *label_num; i++ ) {\r
289                         label_pt = labels[i];\r
290                         label_pt.pos_x /= label_pt.area;\r
291                         label_pt.pos_y /= label_pt.area;\r
292                 }\r
293                 return;\r
294         }\r
295 \r
296 }\r
297 \r
298 /**\r
299  * NyARLabeling_O2のworkとwork2を可変長にするためのクラス\r
300  * \r
301  * \r
302  */\r
303 final class NyARWorkHolder\r
304 {\r
305         private final static int ARRAY_APPEND_STEP = 256;\r
306 \r
307         public final int[][] work2;\r
308 \r
309         private int allocate_size;\r
310 \r
311         /**\r
312          * 最大i_holder_size個の動的割り当てバッファを準備する。\r
313          * \r
314          * @param i_holder_size\r
315          */\r
316         public NyARWorkHolder(int i_holder_size)\r
317         {\r
318                 // ポインタだけははじめに確保しておく\r
319                 this.work2 = new int[i_holder_size][];\r
320                 this.allocate_size = 0;\r
321         }\r
322 \r
323         /**\r
324          * i_indexで指定した番号までのバッファを準備する。\r
325          * \r
326          * @param i_index\r
327          */\r
328         public final void reserv(int i_index) throws NyARException\r
329         {\r
330                 // アロケート済みなら即リターン\r
331                 if (this.allocate_size > i_index) {\r
332                         return;\r
333                 }\r
334                 // 要求されたインデクスは範囲外\r
335                 if (i_index >= this.work2.length) {\r
336                         throw new NyARException();\r
337                 }\r
338                 // 追加アロケート範囲を計算\r
339                 int range = i_index + ARRAY_APPEND_STEP;\r
340                 if (range >= this.work2.length) {\r
341                         range = this.work2.length;\r
342                 }\r
343                 // アロケート\r
344                 for (int i = this.allocate_size; i < range; i++) {\r
345                         this.work2[i] = new int[7];\r
346                 }\r
347                 this.allocate_size = range;\r
348         }\r
349 }\r