OSDN Git Service

3d7370db6cea295994a54354ec3d66658a3d7d6a
[nyartoolkit-and/nyartoolkit-and.git] / src / jp / nyatla / nyartoolkit / core / 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.core;\r
33 \r
34 \r
35 \r
36 \r
37 import jp.nyatla.nyartoolkit.NyARException;\r
38 import jp.nyatla.util.IntValue;\r
39 /**\r
40  * イメージからマーカー情報を検出するクラス。\r
41  * このクラスは、arDetectMarker2.cとの置き換えになります。\r
42  * ラベリング済みのラスタデータからマーカー位置を検出して、結果を保持します。\r
43  *\r
44  */\r
45 public class NyARDetectMarker {\r
46     private static final int AR_AREA_MAX=100000;//#define   AR_AREA_MAX      100000\r
47     private static final int AR_AREA_MIN=70;//#define   AR_AREA_MIN          70\r
48 \r
49     private int area_max=AR_AREA_MAX;\r
50     private int area_min=AR_AREA_MIN;\r
51     private NyARMarker[] marker_holder; //マーカーデータの保持配列\r
52     private NyARMarker[] marker_info2_array;    //マーカーデータのインデックス配列\r
53     private int marker_num;\r
54     private int width,height;\r
55     /**\r
56      * 最大i_squre_max個のマーカーを検出するクラスを作成する。\r
57      * @param i_width\r
58      * @param i_height\r
59      * @param i_squre_max\r
60      */\r
61     public NyARDetectMarker(int i_width,int i_height,int i_squre_max)\r
62     {\r
63         width =i_width;\r
64         height=i_height;\r
65         marker_holder=new NyARMarker[i_squre_max];\r
66         marker_info2_array=new NyARMarker[i_squre_max];\r
67     }\r
68     public int getMarkerNum()\r
69     {\r
70         return marker_num;\r
71     }\r
72     public NyARMarker getMarker(int idx) throws NyARException\r
73     {\r
74         if(idx>=marker_num){\r
75             throw new NyARException();\r
76         }\r
77         return marker_info2_array[idx];\r
78     }\r
79     /**\r
80      * static int get_vertex( int x_coord[], int y_coord[], int st,  int ed,double thresh, int vertex[], int *vnum)\r
81      * 関数の代替関数\r
82      * @param x_coord\r
83      * @param y_coord\r
84      * @param st\r
85      * @param ed\r
86      * @param thresh\r
87      * @param vertex\r
88      * @param vnum\r
89      * @return\r
90      */\r
91     private static boolean get_vertex( int[] x_coord, int[] y_coord, int st,  int ed,double thresh, int vertex[],IntValue vnum)\r
92     {\r
93         double   d, dmax;\r
94         double   a, b, c;\r
95         int      i, v1=0;\r
96         \r
97         a = y_coord[ed] - y_coord[st];\r
98         b = x_coord[st] - x_coord[ed];\r
99         c = x_coord[ed]*y_coord[st] - y_coord[ed]*x_coord[st];\r
100         dmax = 0;\r
101         for(i=st+1;i<ed;i++) {\r
102             d = a*x_coord[i] + b*y_coord[i] + c;\r
103             if( d*d > dmax ) {\r
104                 dmax = d*d;\r
105                 v1 = i;\r
106             }\r
107         }\r
108         if( dmax/(a*a+b*b) > thresh ) {\r
109             if(!get_vertex(x_coord, y_coord, st,  v1, thresh, vertex, vnum)){\r
110                 return false;\r
111             }\r
112             if( vnum.get() > 5 ){\r
113                 return false;\r
114             }\r
115             vertex[vnum.get()] = v1;//vertex[(*vnum)] = v1;\r
116             vnum.inc();//(*vnum)++;\r
117         \r
118             if(!get_vertex(x_coord, y_coord, v1,  ed, thresh, vertex, vnum)){\r
119                 return false;\r
120             }\r
121         }\r
122         return true;\r
123     }\r
124     /**\r
125      * static int arDetectMarker2_check_square( int area, ARMarkerInfo2 *marker_info2, double factor )\r
126      * 関数の代替関数\r
127      * @param area\r
128      * @param i_marker_info2\r
129      * @param factor\r
130      * @return\r
131      */\r
132     private static boolean check_square( int area, NyARMarker i_marker_info2, double factor )\r
133         {\r
134             int             sx, sy;\r
135             int             dmax, d, v1;\r
136             int[] vertex=new int[10];//int             vertex[10]\r
137             int[] wv1=new int[10],wv2=new int[10];//int wv1[10],wv2[10];\r
138             int v2;//       int   wvnum1,wvnum2,v2;\r
139             double          thresh;\r
140             int             i;\r
141             IntValue wvnum1=new IntValue(),wvnum2=new IntValue();\r
142 \r
143 \r
144             dmax = 0;\r
145             v1 = 0;\r
146             sx = i_marker_info2.x_coord[0];//sx = marker_info2->x_coord[0];\r
147             sy = i_marker_info2.y_coord[0];//sy = marker_info2->y_coord[0];\r
148             for(i=1;i<i_marker_info2.coord_num-1;i++){//for(i=1;i<marker_info2->coord_num-1;i++) {\r
149                 d = (i_marker_info2.x_coord[i]-sx)*(i_marker_info2.x_coord[i]-sx)+ (i_marker_info2.y_coord[i]-sy)*(i_marker_info2.y_coord[i]-sy);\r
150                 if( d > dmax ) {\r
151                     dmax = d;\r
152                     v1 = i;\r
153                 }\r
154             }\r
155 \r
156             thresh = (area/0.75) * 0.01 * factor;\r
157 //          vnum = 1;\r
158             vertex[0] = 0;\r
159             wvnum1.set(0);//        wvnum1 = 0;\r
160             wvnum2.set(0);//        wvnum2 = 0;\r
161 \r
162             if(!get_vertex(i_marker_info2.x_coord, i_marker_info2.y_coord, 0,  v1,thresh, wv1, wvnum1)){            //if( get_vertex(marker_info2->x_coord, marker_info2->y_coord, 0,  v1,thresh, wv1, &wvnum1) < 0 ) {\r
163                 return false;\r
164             }\r
165             if(!get_vertex(i_marker_info2.x_coord, i_marker_info2.y_coord,v1,  i_marker_info2.coord_num-1, thresh, wv2, wvnum2)) {//if(get_vertex(marker_info2->x_coord, marker_info2->y_coord,v1,  marker_info2->coord_num-1, thresh, wv2, &wvnum2) < 0 ) {\r
166                 return false;\r
167             }\r
168 \r
169             if( wvnum1.get() == 1 && wvnum2.get() == 1 ) {//if( wvnum1 == 1 && wvnum2 == 1 ) {\r
170                 vertex[1] = wv1[0];\r
171                 vertex[2] = v1;\r
172                 vertex[3] = wv2[0];\r
173             }else if( wvnum1.get() > 1 && wvnum2.get() == 0 ) {//}else if( wvnum1 > 1 && wvnum2 == 0 ) {\r
174                 v2 = v1 / 2;\r
175                 wvnum1.set(0);wvnum2.set(0);//wvnum1 = wvnum2 = 0;\r
176                 if(!get_vertex(i_marker_info2.x_coord, i_marker_info2.y_coord,0,  v2, thresh, wv1, wvnum1)) {\r
177                     return false;\r
178                 }\r
179                 if(!get_vertex(i_marker_info2.x_coord, i_marker_info2.y_coord,v2,  v1, thresh, wv2, wvnum2)) {\r
180                     return false;\r
181                 }\r
182                 if( wvnum1.get() == 1 && wvnum2.get() == 1 ) {\r
183                     vertex[1] = wv1[0];\r
184                     vertex[2] = wv2[0];\r
185                     vertex[3] = v1;\r
186                 }else{\r
187                     return false;\r
188                 }\r
189             }else if( wvnum1.get() == 0 && wvnum2.get() > 1 ) {\r
190                 v2 = (v1 + i_marker_info2.coord_num-1) / 2;\r
191                 \r
192                 wvnum1.set(0);wvnum2.set(0);//wvnum1 = wvnum2 = 0;\r
193                 if(!get_vertex(i_marker_info2.x_coord, i_marker_info2.y_coord,v1, v2, thresh, wv1,wvnum1)) {\r
194                     return false;\r
195                 }\r
196                 if(!get_vertex(i_marker_info2.x_coord, i_marker_info2.y_coord,v2, i_marker_info2.coord_num-1, thresh, wv2, wvnum2)) {\r
197                     return false;\r
198                 }\r
199                 if( wvnum1.get() == 1 && wvnum2.get() == 1 ) {\r
200                     vertex[1] = v1;\r
201                     vertex[2] = wv1[0];\r
202                     vertex[3] = wv2[0];\r
203                 }\r
204                 else {\r
205                     return false;\r
206                 }\r
207             }\r
208             else {\r
209                 return false;\r
210             }\r
211 \r
212             i_marker_info2.vertex[0] = vertex[0];\r
213             i_marker_info2.vertex[1] = vertex[1];\r
214             i_marker_info2.vertex[2] = vertex[2];\r
215             i_marker_info2.vertex[3] = vertex[3];\r
216             i_marker_info2.vertex[4] = i_marker_info2.coord_num-1;\r
217 \r
218             return true;\r
219         }\r
220     /**\r
221      * int arGetContour( ARInt16 *limage, int *label_ref,int label, int clip[4], ARMarkerInfo2 *marker_info2 )\r
222      * 関数の代替品\r
223      * detectMarker関数から使う関数です。marker_holder[i_holder_num]にオブジェクトが無ければまず新規に作成し、もし\r
224      * 既に存在すればそこにマーカー情報を上書きして記録します。\r
225      * @param limage\r
226      * @param label_ref\r
227      * @param label\r
228      * @param clip\r
229      * @return\r
230      *  検出したマーカーからマーカーオブジェクトを生成して返す。\r
231      * @throws NyARException\r
232      */\r
233     private NyARMarker arGetContour(int i_holder_num,short[][] limage, int[] label_ref,int label, int[] clip) throws NyARException\r
234     {\r
235         final int[] xdir={0,  1, 1, 1, 0,-1,-1,-1}; //static int      xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1};\r
236         final int[] ydir={-1,-1, 0, 1, 1, 1, 0,-1};//static int      ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1};\r
237         //ShortPointer p1;//ARInt16         *p1;\r
238         int             sx=0, sy=0, dir;\r
239         int             dmax, d, v1=0;\r
240         int             i, j;\r
241     \r
242         j = clip[2];\r
243         //p1=ShortPointer.wrap(limage,j*xsize+clip.get());//p1 = &(limage[j*xsize+clip[0]]);\r
244         for( i = clip[0]; i <= clip[1]; i++){//for( i = clip[0]; i <= clip[1]; i++, p1++ ) {\r
245             if(limage[j][i] > 0 && label_ref[(limage[j][i])-1] == label ) {//if( *p1 > 0 && label_ref[(*p1)-1] == label ) {\r
246                 sx = i; sy = j;\r
247                 break;\r
248             }\r
249         }\r
250         if(i> clip[1]){//if( i > clip[1] ) {\r
251             System.out.println("??? 1");//printf();\r
252             throw new NyARException();//return(-1);\r
253         }\r
254         \r
255         //マーカーホルダが既に確保済みかを調べる\r
256         if(marker_holder[i_holder_num]==null){\r
257             //確保していなければ確保\r
258             marker_holder[i_holder_num]=new NyARMarker();\r
259         }\r
260         NyARMarker marker_ref=marker_holder[i_holder_num];\r
261 \r
262     \r
263         marker_ref.coord_num=1;//marker_info2->coord_num = 1;\r
264         marker_ref.x_coord[0]=sx;//marker_info2->x_coord[0] = sx;\r
265         marker_ref.y_coord[0]=sy;//marker_info2->y_coord[0] = sy;\r
266         dir = 5;\r
267     \r
268         for(;;){\r
269             int r=marker_ref.y_coord[marker_ref.coord_num-1];\r
270             int c=marker_ref.x_coord[marker_ref.coord_num-1];\r
271             //p1 = &(limage[marker_info2->y_coord[marker_info2->coord_num-1] * xsize+ marker_info2->x_coord[marker_info2->coord_num-1]]);\r
272             dir = (dir+5)%8;\r
273             for(i=0;i<8;i++) {\r
274                 if(limage[r+ydir[dir]][c+xdir[dir]]>0){//if( p1[ydir[dir]*xsize+xdir[dir]] > 0 ){\r
275                     break;\r
276                 }\r
277                 dir = (dir+1)%8;        \r
278             }\r
279             if( i == 8 ){\r
280                 System.out.println("??? 2");//printf("??? 2\n");\r
281                 throw new NyARException();//return(-1);\r
282             }\r
283             marker_ref.x_coord[marker_ref.coord_num]= marker_ref.x_coord[marker_ref.coord_num-1] + xdir[dir];//marker_info2->x_coord[marker_info2->coord_num]= marker_info2->x_coord[marker_info2->coord_num-1] + xdir[dir];\r
284             marker_ref.y_coord[marker_ref.coord_num]= marker_ref.y_coord[marker_ref.coord_num-1] + ydir[dir];//marker_info2->y_coord[marker_info2->coord_num]= marker_info2->y_coord[marker_info2->coord_num-1] + ydir[dir];\r
285             if( marker_ref.x_coord[marker_ref.coord_num] == sx && marker_ref.y_coord[marker_ref.coord_num] == sy ){\r
286                 break;\r
287             }\r
288             marker_ref.coord_num++;\r
289             if( marker_ref.coord_num == marker_ref.x_coord.length-1){//if( marker_info2.coord_num == Config.AR_CHAIN_MAX-1 ){\r
290                 System.out.println("??? 3");//printf("??? 3\n");\r
291                 throw new NyARException();//return(-1);\r
292             }\r
293         }\r
294     \r
295         dmax = 0;\r
296         for(i=1;i<marker_ref.coord_num;i++) {// for(i=1;i<marker_info2->coord_num;i++) {\r
297             d = (marker_ref.x_coord[i]-sx)*(marker_ref.x_coord[i]-sx)+ (marker_ref.y_coord[i]-sy)*(marker_ref.y_coord[i]-sy);//   d = (marker_info2->x_coord[i]-sx)*(marker_info2->x_coord[i]-sx)+ (marker_info2->y_coord[i]-sy)*(marker_info2->y_coord[i]-sy);\r
298             if( d > dmax ) {\r
299                 dmax = d;\r
300                 v1 = i;\r
301             }\r
302         }\r
303 \r
304         int[]      wx=new int[v1];//new int[Config.AR_CHAIN_MAX];\r
305         int[]      wy=new int[v1]; //new int[Config.AR_CHAIN_MAX];   \r
306         for(i=0;i<v1;i++) {\r
307             wx[i] = marker_ref.x_coord[i];//wx[i] = marker_info2->x_coord[i];\r
308             wy[i] = marker_ref.y_coord[i];//wy[i] = marker_info2->y_coord[i];\r
309         }\r
310         for(i=v1;i<marker_ref.coord_num;i++) {//for(i=v1;i<marker_info2->coord_num;i++) {\r
311             marker_ref.x_coord[i-v1] = marker_ref.x_coord[i];//marker_info2->x_coord[i-v1] = marker_info2->x_coord[i];\r
312             marker_ref.y_coord[i-v1] = marker_ref.y_coord[i];//marker_info2->y_coord[i-v1] = marker_info2->y_coord[i];\r
313         }\r
314         for(i=0;i<v1;i++) {\r
315             marker_ref.x_coord[i-v1+marker_ref.coord_num] = wx[i];//marker_info2->x_coord[i-v1+marker_info2->coord_num] = wx[i];\r
316             marker_ref.y_coord[i-v1+marker_ref.coord_num] = wy[i];//marker_info2->y_coord[i-v1+marker_info2->coord_num] = wy[i];\r
317         }\r
318         marker_ref.x_coord[marker_ref.coord_num] = marker_ref.x_coord[0];//marker_info2->x_coord[marker_info2->coord_num] = marker_info2->x_coord[0];\r
319         marker_ref.y_coord[marker_ref.coord_num] = marker_ref.y_coord[0];//marker_info2->y_coord[marker_info2->coord_num] = marker_info2->y_coord[0];\r
320         marker_ref.coord_num++;//marker_info2->coord_num++;\r
321     \r
322         return marker_ref;\r
323     }\r
324         /**\r
325          * ARMarkerInfo2 *arDetectMarker2( ARInt16 *limage, int label_num, int *label_ref,int *warea, double *wpos, int *wclip,int area_max, int area_min, double factor, int *marker_num )\r
326          * 関数の代替品\r
327          * ラベリング情報からマーカー一覧を作成して保持します。\r
328          * この関数を実行すると、前回のdetectMarker関数で計算した保持値は破壊されます。\r
329          * @param i_labeling\r
330          * ラベリング済みの情報を持つラベリングオブジェクト\r
331          * @param factor\r
332          * 何かの閾値?\r
333          * @return\r
334          * @throws NyARException\r
335          */\r
336 //      public void detectMarker(short[][] limage,int label_num,int[] label_ref,int[] warea,double[] wpos,int[] wclip,int area_max, int area_min, double factor) throws JartkException\r
337     public void detectMarker(NyARLabeling i_labeling,double factor) throws NyARException\r
338     {\r
339         int               xsize, ysize;\r
340         int               marker_num2;\r
341         double            d;\r
342         int[] warea     =i_labeling.getArea();\r
343         int label_num   =i_labeling.getLabelNum();\r
344         int[][] wclip   =i_labeling.getClip();\r
345         double[] wpos   =i_labeling.getPos();\r
346         short[][] limage        =i_labeling.getLabelImg();\r
347         int[] label_ref =i_labeling.getLabelRef();\r
348         \r
349         marker_num=0;\r
350         xsize =width;\r
351         ysize =height;\r
352         \r
353         marker_num2 = 0;\r
354         for(int i=0; i<label_num; i++ ) {\r
355             if( warea[i] < area_min || warea[i] > area_max ){\r
356                 continue;\r
357             }\r
358             if( wclip[i][0] == 1 || wclip[i][1] == xsize-2 ){//if( wclip[i*4+0] == 1 || wclip[i*4+1] == xsize-2 ){\r
359                 continue;\r
360             }\r
361             if( wclip[i][2] == 1 || wclip[i][3] == ysize-2 ){//if( wclip[i*4+2] == 1 || wclip[i*4+3] == ysize-2 ){\r
362                 continue;\r
363             }\r
364             //ret = arGetContour( limage, label_ref, i+1,&(wclip[i*4]), &(marker_info2[marker_num2]));\r
365             arGetContour(marker_num2,limage, label_ref, i+1,wclip[i]);\r
366             \r
367             boolean ret = check_square( warea[i], marker_holder[marker_num2], factor );//ret = check_square( warea[i], &(marker_info2[marker_num2]), factor );\r
368             if(!ret){\r
369                 //後半で整理するからここはいらない。//         marker_holder[marker_num2]=null;\r
370                 continue;\r
371             }\r
372             marker_holder[marker_num2].area   = warea[i];\r
373             marker_holder[marker_num2].pos[0] = wpos[i*2+0];\r
374             marker_holder[marker_num2].pos[1] = wpos[i*2+1];\r
375             marker_num2++;\r
376             //マーカーリストが上限に達した\r
377             if( marker_num2 == marker_holder.length){\r
378                 break;\r
379             }\r
380         }\r
381         for(int i=0; i < marker_num2; i++ ) {\r
382             for(int j=i+1; j < marker_num2; j++ ) {\r
383                 d = (marker_holder[i].pos[0] - marker_holder[j].pos[0])*\r
384                     (marker_holder[i].pos[0] - marker_holder[j].pos[0])+\r
385                     (marker_holder[i].pos[1] - marker_holder[j].pos[1])*\r
386                     (marker_holder[i].pos[1] - marker_holder[j].pos[1]);\r
387                 if(marker_holder[i].area >marker_holder[j].area ) {\r
388                     if( d <marker_holder[i].area / 4 ) {\r
389                         marker_holder[j].area = 0;\r
390                     }\r
391                 }else{\r
392                     if( d < marker_holder[j].area / 4 ) {\r
393                         marker_holder[i].area = 0;\r
394                     }\r
395                 }\r
396             }\r
397         }\r
398         //みつかったマーカーを整理する。\r
399         //エリアが0のマーカーを外した配列を作って、その数もついでに計算\r
400         for(int i=0;i<marker_num2;i++){\r
401             if(marker_holder[i].area==0.0){\r
402                 continue;\r
403             }\r
404             marker_info2_array[marker_num]=marker_holder[i];\r
405             marker_num++;\r
406         }        \r
407 //        for( i=0; i < marker_num2; i++ ) {\r
408 //            if( marker_info2_array[i].area == 0.0 ) {\r
409 //                for( j=i+1; j < marker_num2; j++ ){\r
410 //                    marker_info2_array[j-1] = marker_info2_array[j];\r
411 //                }\r
412 //                marker_num2--;\r
413 //            }\r
414 //        }\r
415         //発見したマーカー数をセット\r
416 //        marker_num=marker_num2;//*marker_num = marker_num2;\r
417         //return( &(marker_info2[0]) );\r
418     }\r
419 \r
420 }\r