OSDN Git Service

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