OSDN Git Service

[バックアップ]NyARToolkit for Java
[nyartoolkit-and/nyartoolkit-and.git] / trunk / test / jp / nyatla / nyartoolkit / dev / CopyOfNyARColorPatt_NyIdMarker.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.dev;\r
33 \r
34 import jp.nyatla.nyartoolkit.NyARException;\r
35 import jp.nyatla.nyartoolkit.core.NyARSquare;\r
36 import jp.nyatla.nyartoolkit.core.raster.rgb.*;\r
37 import jp.nyatla.nyartoolkit.core.rasterreader.*;\r
38 import jp.nyatla.nyartoolkit.core.types.*;\r
39 import jp.nyatla.nyartoolkit.core.utils.*;\r
40 import jp.nyatla.nyartoolkit.core.labeling.NyARLabelingLabel;\r
41 import jp.nyatla.nyartoolkit.core.pickup.*;\r
42 import jp.nyatla.nyartoolkit.nyidmarker.MarkerPattEncoder;\r
43 import jp.nyatla.nyartoolkit.nyidmarker.PerspectivePixelReader;\r
44 \r
45 \r
46 \r
47 /**\r
48  * 1区間にある1個のエッジ位置を推定するクラスです。\r
49  *\r
50  */\r
51 class NyARSingleEdgeFinder2\r
52 {\r
53         public static class TEdgeInfo\r
54         {\r
55                 double point;   //検出したエッジの位置\r
56                 int sub;                //エッジの差分\r
57         }       \r
58         private int[] _work;\r
59         private int _width;\r
60         private int _height;\r
61         public NyARSingleEdgeFinder2(int i_width,int i_height)\r
62         {\r
63                 this._work=new int[(i_width>i_height?i_width:i_height)+1];\r
64                 this._work[this._work.length-1]=0;\r
65                 this._width=i_width;\r
66                 this._height=i_height;\r
67                 return;\r
68         }\r
69         /**\r
70          * この関数は、一区間に1個のエッジが含まれていると仮定して、その位置を推定します。\r
71          * [n]個の配列を与えた場合、[n+2]~[n-1]の間にあるエッジを検出します。\r
72          * 検出方向は左→右の順です\r
73          * @param i_pixcel\r
74          * @param i_start\r
75          * @param i_length\r
76          * @param o_out\r
77          * @return\r
78          */\r
79         public boolean scanSingleEdgeLeftToRight(int[] i_pixcel,int i_y,TEdgeInfo o_out)\r
80         {\r
81                 final int[] temp=this._work;\r
82                 //1回微分(0-8)\r
83                 final int length=this._width-1;\r
84                 int p=i_y*this._width;\r
85                 for(int i2=0;i2<length;i2++){\r
86                         temp[i2]=i_pixcel[p+1]-i_pixcel[p];\r
87                         p++;\r
88                 }\r
89                 return scanSingleEdge(temp,length,o_out);\r
90         }\r
91         /**\r
92          * 線分内のエッジを検出します。\r
93          * この関数は、1区間に1個のエッジが含まれていると仮定して、その位置を推定します。\r
94          * [n]個の配列を与えた場合、[n+2]~[n-1]の間にあるエッジを検出します。\r
95          * 検出方向は右→左の順です\r
96          * @param i_pixcel\r
97          * @param i_start\r
98          * @param i_length\r
99          * @param o_out\r
100          * @return\r
101          */\r
102         public boolean scanSingleEdgeRightToLeft(int[] i_pixcel,int i_y,TEdgeInfo o_out)\r
103         {\r
104                 final int[] temp=this._work;\r
105                 //1回微分(0-8)\r
106                 final int length=this._width-1;\r
107                 int p=(i_y+1)*this._width-1;\r
108                 for(int i2=0;i2<length;i2++){\r
109                         temp[i2]=i_pixcel[p-1]-i_pixcel[p];\r
110                         p--;\r
111                 }\r
112                 return scanSingleEdge(temp,length,o_out);\r
113         }       \r
114         public boolean scanSingleEdgeTopToBottom(int[] i_pixcel,int i_x,TEdgeInfo o_out)\r
115         {\r
116                 final int[] temp=this._work;\r
117                 //1回微分(0-8)\r
118                 final int step=this._width;\r
119                 final int length=this._height-1;\r
120                 int p=i_x;\r
121                 for(int i2=0;i2<length;i2++){\r
122                         temp[i2]=i_pixcel[p+step]-i_pixcel[p];\r
123                         p+=step;\r
124                 }\r
125                 return scanSingleEdge(temp,length,o_out);\r
126         }\r
127         public boolean scanSingleEdgeBottomToTop(int[] i_pixcel,int i_x,TEdgeInfo o_out)\r
128         {\r
129                 final int[] temp=this._work;\r
130                 //1回微分(0-8)\r
131                 final int step=this._width;\r
132                 final int length=this._height-1;\r
133                 int p=i_x+step*length;\r
134                 for(int i2=0;i2<length;i2++){\r
135                         temp[i2]=i_pixcel[p-step]-i_pixcel[p];\r
136                         p-=step;\r
137                 }\r
138                 return scanSingleEdge(temp,length,o_out);\r
139         }       \r
140         private boolean scanSingleEdge(int[] i_pixels,int i_length,TEdgeInfo o_out)\r
141         {\r
142                 //微分(2回目)して、極値2か所を得る\r
143                 int max_index,min_index;\r
144                 int length=i_length-1;\r
145                 max_index=min_index=0;\r
146                 int max_value,min_value;\r
147                 max_value=min_value=0;\r
148                 for(int i2=0;i2<length;i2++){\r
149                         int t=i_pixels[i2+1]-i_pixels[i2];\r
150                         if(t>max_value){\r
151                                 max_index=i2;\r
152                                 max_value=t;\r
153                         }\r
154                         if(t<min_value){\r
155                                 min_index=i2;\r
156                                 min_value=t;\r
157                         }\r
158                 }\r
159                 //同符号である場合、範囲内にエッジはない\r
160                 if(max_value*min_value>=0){\r
161                         return false;\r
162                 }               \r
163                 o_out.point=(max_index+min_index)/2.0;\r
164                 o_out.sub=max_value-min_value;\r
165                 return true;\r
166         }\r
167         public int scanEdgeLeftToRight(int[] i_pixel,int i_y,int i_noise_th,double[] o_edge_index)\r
168         {\r
169                 final int[] temp=this._work;\r
170                 //1回微分(0-8)\r
171                 final int length=this._width-1;\r
172                 int p=i_y*this._width;\r
173                 for(int i2=0;i2<length;i2++){\r
174                         temp[i2]=i_pixel[p+1]-i_pixel[p];\r
175                         p++;\r
176                 }\r
177                 //0終端させるために1要素を後続に追加\r
178                 return scanEdge(temp,length+1,i_noise_th,o_edge_index);\r
179         }\r
180         private int scanEdge(int[] i_pixels,int i_length,int i_noise_th,double[] o_out)\r
181         {\r
182                 int points=0;\r
183                 final int length=i_length;\r
184                 //エッジ1区間を抜き出す\r
185                 for(int i2=0;i2<length;i2++){\r
186                         int t=i_pixels[i2];\r
187                         if(t>i_noise_th){\r
188                                 int st=i2;\r
189                                 i2++;\r
190                                 for(;i2<length;i2++){\r
191                                         t=i_pixels[i2];\r
192                                         if(t<=0){\r
193                                                 //(st - i2で1区間)\r
194                                                 //エッジ位置は区間の中央にする。\r
195                                                 o_out[points]=(st+i2)/2.0;\r
196                                                 points++;\r
197                                                 if(t<0){\r
198                                                         //マイナスであれば、0を補完する\r
199                                                         i2--;\r
200                                                         i_pixels[i2]=0;\r
201                                                 }\r
202                                                 break;\r
203                                         }\r
204 \r
205                                 }\r
206                         }else if(t<-i_noise_th){\r
207                                 int st=i2;\r
208                                 i2++;\r
209                                 for(;i2<length;i2++){\r
210                                         t=i_pixels[i2];\r
211                                         if(t>=0){\r
212                                                 //(st - i2で1区間)\r
213                                                 //エッジ位置は区間の中央にする。\r
214                                                 o_out[points]=(st+i2)/2.0;\r
215                                                 points++;\r
216                                                 if(t>0){\r
217                                                         //プラスであれば、0を補完する\r
218                                                         i2--;\r
219                                                         i_pixels[i2]=0;\r
220                                                 }\r
221                                                 break;\r
222                                         }\r
223                                 }\r
224                         }\r
225                 }\r
226                 return points;\r
227         }       \r
228         /**\r
229          * 指定した配列をノイズパターンとして、ノイズ値を計算します。\r
230          * このノイズ値は、scanEdgeのノイズ値として使用できます。\r
231          * @param i_pixels\r
232          * @param i_length\r
233          * @return\r
234          */\r
235         public int getNoiseValue(int[] i_pixels,int i_length)\r
236         {\r
237                 //1回微分して、その最大値と最小値を計算\r
238                 int length=i_length-1;\r
239                 int max_value,min_value;\r
240                 max_value=min_value=0;\r
241                 for(int i2=0;i2<length;i2++){\r
242                         int t=i_pixels[i2+1]-i_pixels[i2];\r
243                         if(t>max_value){\r
244                                 max_value=t;\r
245                         }\r
246                         if(t<min_value){\r
247                                 min_value=t;\r
248                         }\r
249                 }\r
250                 return (-min_value>max_value)?-min_value:max_value;\r
251         }       \r
252 }\r
253 \r
254 class MarkerEncoder2\r
255 {\r
256         private final static int[] _bit_table_3={\r
257                 25,     26,     27,     28,     29,     30,     31,\r
258                 48,     9,      10,     11,     12,     13,     32,\r
259                 47,     24,     1,      2,      3,      14,     33,\r
260                 46,     23,     8,      0,      4,      15,     34,\r
261                 45,     22,     7,      6,      5,      16,     35,\r
262                 44,     21,     20,     19,     18,     17,     36,\r
263                 43,     42,     41,     40,     39,     38,     37\r
264                 };      \r
265         private final static int[] _bit_table_2={\r
266                 9,      10,     11,     12,     13,\r
267                 24,     1,      2,      3,      14,\r
268                 23,     8,      0,      4,      15,\r
269                 22,     7,      6,      5,      16,\r
270                 21,     20,     19,     18,     17};\r
271         private final static int[][] _bit_tables={\r
272                 _bit_table_2,_bit_table_3\r
273         };\r
274         /**\r
275          * RECT(0):[0]=(0)\r
276          * RECT(1):[1]=(1-8)\r
277          * RECT(2):[2]=(9-16),[3]=(17-24)\r
278          * RECT(3):[4]=(25-32),[5]=(33-40),[6]=(41-48)\r
279          */\r
280         int[] _bit_table;\r
281         int[] _bits=new int[16];\r
282         int[] _work=new int[16];\r
283         int _model;\r
284         public void setBitByBitIndex(int i_index_no,int i_value)\r
285         {\r
286                 assert i_value==0 || i_value==1;\r
287                 final int bit_no=this._bit_table[i_index_no];\r
288                 if(bit_no==0){\r
289                         this._bits[0]=i_value;\r
290                 }else{\r
291                         int bidx=(bit_no-1)/8+1;\r
292                         int sidx=(bit_no-1)%8;\r
293                         this._bits[bidx]=(this._bits[bidx]&(~(0x01<<sidx)))|(i_value<<sidx);\r
294                 }\r
295                 return;\r
296         }\r
297         \r
298         public void setBit(int i_bit_no,int i_value)\r
299         {\r
300                 assert i_value==0 || i_value==1;\r
301                 if(i_bit_no==0){\r
302                         this._bits[0]=i_value;\r
303                 }else{\r
304                         int bidx=(i_bit_no-1)/8+1;\r
305                         int sidx=(i_bit_no-1)%8;\r
306                         this._bits[bidx]=(this._bits[bidx]&(~(0x01<<sidx)))|(i_value<<sidx);\r
307                 }\r
308                 return;\r
309         }\r
310         public int getBit(int i_bit_no)\r
311         {\r
312                 if(i_bit_no==0){\r
313                         return this._bits[0];\r
314                 }else{\r
315                         int bidx=(i_bit_no-1)/8+1;\r
316                         int sidx=(i_bit_no-1)%8;\r
317                         return (this._bits[bidx]>>(sidx))&(0x01);\r
318                 }\r
319         }\r
320         public boolean initEncoder(int i_model)\r
321         {\r
322                 if(i_model>=4 || i_model<2){\r
323                         //Lv4以降に対応する時は、この制限を変える。\r
324                         return false;\r
325                 }\r
326                 this._bit_table=_bit_tables[i_model-2];\r
327                 this._model=i_model;\r
328                 return true;\r
329         }\r
330         private int getDirection()\r
331         {\r
332                 int l,t,r,b;\r
333                 switch(this._model){\r
334                 case 2:\r
335                         //トラッキングセルを得る\r
336                         t=this._bits[2] & 0x07;\r
337                         r=(this._bits[2] & 0x70)>>4;\r
338                         b=this._bits[3] & 0x07;\r
339                         l=(this._bits[3] & 0x70)>>4;\r
340                         break;\r
341                 case 3:\r
342                 default:\r
343                         return -3;\r
344                 }\r
345                 //101であるかを確認\r
346                 if(t==0x05){\r
347                         if(r==0x05){\r
348                                 return (b!=0x05 && l!=0x05)?2:-2;\r
349                         }else if(l==0x05){\r
350                                 return (b!=0x05 && r!=0x05)?3:-2;\r
351                         }\r
352                 }else if(b==0x05){\r
353                         if(r==0x05){\r
354                                 return (t!=0x05 && l!=0x05)?1:-2;\r
355                         }else if(l==0x05){\r
356                                 return (t!=0x05 && r!=0x05)?0:-2;\r
357                         }\r
358                 }\r
359                 return -1;\r
360         }\r
361 \r
362         public boolean encode()\r
363         {\r
364                 int d=getDirection();\r
365                 if(d<0){\r
366                         return false;\r
367                 }\r
368                 //回転操作\r
369                 \r
370                 rotateDirection(d);\r
371                 //デコード\r
372                 \r
373                 return true;\r
374         }\r
375         private void rotateDirection(int i_direction)\r
376         {\r
377                 int sl=i_direction*2;\r
378                 int sr=8-sl;\r
379 \r
380                 int w1;\r
381                 //RECT1\r
382                 w1=this._bits[1];\r
383                 this._bits[1]=(w1<<sl)|(w1>>sr);\r
384                 \r
385                 //RECT2\r
386                 sl=i_direction*4;\r
387                 sr=16-sl;\r
388                 w1=this._bits[2]|(this._bits[3]<<8);\r
389                 w1=(w1<<sl)|(w1>>sr);\r
390                 this._bits[2]=w1 & 0xff;\r
391                 this._bits[3]=(w1>>8) & 0xff;\r
392 \r
393                 if(this._model<2){\r
394                         return;\r
395                 }\r
396 \r
397                 //RECT3\r
398                 sl=i_direction*6;\r
399                 sr=24-sl;                       \r
400                 w1=this._bits[4]|(this._bits[5]<<8)|(this._bits[6]<<16);\r
401                 w1=(w1<<sl)|(w1>>sr);\r
402                 this._bits[4]=w1 & 0xff;\r
403                 this._bits[5]=(w1>>8) & 0xff;\r
404                 this._bits[6]=(w1>>16) & 0xff;\r
405                 \r
406                 if(this._model<3){\r
407                         return;\r
408                 }\r
409                 //RECT4(Lv4以降はここの制限を変える)\r
410 //              shiftLeft(this._bits,7,3,i_direction*);\r
411 \r
412                 return;\r
413         }\r
414         public void shiftLeft(int[] i_pack,int i_start,int i_length,int i_ls)\r
415         {\r
416                 int[] work=this._work;\r
417                 //端数シフト\r
418                 final int mod_shift=i_ls%8;\r
419                 for(int i=i_length-1;i>=1;i--){\r
420                         work[i]=(i_pack[i+i_start]<<mod_shift)|(0xff&(i_pack[i+i_start-1]>>(8-mod_shift)));\r
421                 }\r
422                 work[0]=(i_pack[i_start]<<mod_shift)|(0xff&(i_pack[i_start+i_length-1]>>(8-mod_shift)));\r
423                 //バイトシフト\r
424                 final int byte_shift=(i_ls/8)%i_length;\r
425                 for(int i=i_length-1;i>=0;i--){\r
426                         i_pack[(byte_shift+i)%i_length+i_start]=0xff & work[i];\r
427                 }\r
428                 return;\r
429         }\r
430 \r
431         \r
432 }\r
433 \r
434 \r
435 /**\r
436  * NyARColorPatt_NyIdMarkerがラスタからPerspective変換して読みだすためのクラス\r
437  *\r
438  */\r
439 class PerspectivePixelReader2 extends NyARPerspectiveParamGenerator_O1\r
440 {\r
441         private double[] _cparam=new double[8];\r
442 \r
443         public PerspectivePixelReader2(int i_local_x,int i_local_y,int i_width, int i_height)\r
444         {\r
445                 super(i_local_x,i_local_y,i_width,i_height);\r
446                 this._temp1=new int[i_width];\r
447                 this._temp2=new int[i_width];\r
448                 this._pixcel_temp=new int[i_width*3];\r
449 \r
450                 return;\r
451         }\r
452         private int[] _temp1;\r
453         private int[] _temp2;\r
454         private int[] _pixcel_temp;\r
455         private INyARRgbRaster _raster;\r
456         public void setSourceRaster(INyARRgbRaster i_raster)\r
457         {\r
458                 this._raster=i_raster;\r
459                 return;\r
460         }\r
461         public boolean setSourceSquare(NyARIntPoint2d[] i_vertex)throws NyARException\r
462         {\r
463                 return this.getParam(i_vertex, this._cparam);\r
464         }\r
465         public void rectPixels(int i_lt_x,int i_lt_y,int i_width,int i_height,int[] o_pixcel)throws NyARException\r
466         {\r
467                 final double[] cpara=this._cparam;\r
468                 final INyARRgbPixelReader reader=this._raster.getRgbPixelReader();\r
469                 final int[] ref_x=this._temp1;\r
470                 final int[] ref_y=this._temp2;\r
471                 final int[] pixcel_temp=this._pixcel_temp;\r
472                 int out_index=0;\r
473 \r
474                 for(int i=0;i<i_height;i++){\r
475                         //1列分のピクセルのインデックス値を計算する。\r
476                         int cy0=1+i+i_lt_y;\r
477                         double cpy0_12=cpara[1]*cy0+cpara[2];\r
478                         double cpy0_45=cpara[4]*cy0+cpara[5];\r
479                         double cpy0_7=cpara[7]*cy0+1.0;                 \r
480                         int pt=0;\r
481                         for(int i2=0;i2<i_width;i2++)\r
482                         {\r
483                                 int cx0=1+i2+i_lt_x;\r
484 \r
485                                 double cp6_0=cpara[6]*cx0;\r
486                                 double cpx0_0=cpara[0]*cx0;\r
487                                 double cpx3_0=cpara[3]*cx0;\r
488                                 \r
489                                 final double d=cp6_0+cpy0_7;\r
490                                 ref_x[pt]=(int)((cpx0_0+cpy0_12)/d);\r
491                                 ref_y[pt]=(int)((cpx3_0+cpy0_45)/d);\r
492                                 pt++;\r
493                         }\r
494                         //1行分のピクセルを取得(場合によっては専用アクセサを書いた方がいい)\r
495                         reader.getPixelSet(ref_x,ref_y,i_width,pixcel_temp);\r
496                         //グレースケールにしながら、line→mapへの転写\r
497                         for(int i2=0;i2<i_width;i2++){\r
498                                 int index=i2*3;\r
499                                 o_pixcel[out_index]=(pixcel_temp[index+0]+pixcel_temp[index+1]+pixcel_temp[index+2])/3;\r
500                                 out_index++;\r
501                         }                       \r
502                 }\r
503                 return;\r
504         }\r
505 \r
506 \r
507                 \r
508         \r
509         //タイミングパターン用のパラメタ(FRQ_POINTS*FRQ_STEPが100を超えないようにすること)\r
510         private static int FRQ_STEP=2;\r
511         private static int FRQ_POINTS=45;\r
512         public static int FRQ_EDGE=5;\r
513 \r
514         \r
515         /**\r
516          * i_y1行目とi_y2行目を平均して、タイミングパターンの周波数を得ます。\r
517          * LHLを1周期として、たとえばLHLHLの場合は2を返します。LHLHやHLHL等の始端と終端のレベルが異なるパターンを\r
518          * 検出した場合、関数は失敗します。\r
519          * \r
520          * @param i_y1\r
521          * @param i_y2\r
522          * @param i_th_h\r
523          * @param i_th_l\r
524          * @param o_edge_index\r
525          * 検出したエッジ位置(H->L,L->H)のインデクスを受け取る配列です。\r
526          * [FRQ_POINTS]以上の配列を指定してください。\r
527          * @return\r
528          * @throws NyARException\r
529          */\r
530         public int getRowFrequency(int i_y1,int i_th_h,int i_th_l,int[] o_edge_index)throws NyARException\r
531         {\r
532                 final double[] cpara=this._cparam;\r
533                 final INyARRgbPixelReader reader=this._raster.getRgbPixelReader();\r
534                 final int[] ref_x=this._temp1;\r
535                 final int[] ref_y=this._temp2;\r
536                 final int[] pixcel_temp=this._pixcel_temp;\r
537 \r
538                 //2行分のピクセルインデックスを計算\r
539                 int cy0=1+i_y1;\r
540                 double cpy0_12=cpara[1]*cy0+cpara[2];\r
541                 double cpy0_45=cpara[4]*cy0+cpara[5];\r
542                 double cpy0_7=cpara[7]*cy0+1.0;                 \r
543 \r
544 \r
545                 int pt=0;\r
546                 for(int i2=0;i2<FRQ_POINTS;i2++)\r
547                 {\r
548                         double d;\r
549                         final int cx0=1+i2*FRQ_STEP+FRQ_EDGE;                   \r
550                         d=(cpara[6]*cx0)+cpy0_7;\r
551                         ref_x[pt]=(int)((cpara[0]*cx0+cpy0_12)/d);\r
552                         ref_y[pt]=(int)((cpara[3]*cx0+cpy0_45)/d);\r
553                         pt++;\r
554                 }\r
555                 \r
556                 //ピクセルを取得(入力画像を多様化するならここから先を調整すること)\r
557                 reader.getPixelSet(ref_x,ref_y,FRQ_POINTS,pixcel_temp);\r
558                 return getFreqInfo(pixcel_temp,i_th_h,i_th_l,o_edge_index);\r
559         }\r
560         public int getColFrequency(int i_x1,int i_th_h,int i_th_l,int[] o_edge_index)throws NyARException\r
561         {\r
562                 final double[] cpara=this._cparam;\r
563                 final INyARRgbPixelReader reader=this._raster.getRgbPixelReader();\r
564                 final int[] ref_x=this._temp1;\r
565                 final int[] ref_y=this._temp2;\r
566                 final int[] pixcel_temp=this._pixcel_temp;\r
567 \r
568                 final int cx0=1+i_x1;\r
569                 final double cp6_0=cpara[6]*cx0;\r
570                 final double cpx0_0=cpara[0]*cx0;\r
571                 final double cpx3_0=cpara[3]*cx0;\r
572 \r
573                 int pt=0;\r
574                 for(int i2=0;i2<FRQ_POINTS;i2++)\r
575                 {\r
576                         double d;\r
577                         int cy=1+i2*FRQ_STEP+FRQ_EDGE;\r
578                         double cpy_12=cpara[1]*cy+cpara[2];\r
579                         double cpy_45=cpara[4]*cy+cpara[5];\r
580                         double cpy_7=cpara[7]*cy+1.0;   \r
581                         \r
582                         d=cp6_0+cpy_7;\r
583                         ref_x[pt]=(int)((cpx0_0+cpy_12)/d);\r
584                         ref_y[pt]=(int)((cpx3_0+cpy_45)/d);\r
585                         pt++;\r
586                         \r
587                 }               \r
588         \r
589                 //ピクセルを取得(入力画像を多様化するならここから先を調整すること)\r
590                 reader.getPixelSet(ref_x,ref_y,FRQ_POINTS,pixcel_temp);\r
591                 return getFreqInfo(pixcel_temp,i_th_h,i_th_l,o_edge_index);\r
592         }\r
593 \r
594         /**\r
595          * デバックすんだらstaticにしておk\r
596          * @param i_pixcels\r
597          * @param i_th_h\r
598          * @param i_th_l\r
599          * @param o_edge_index\r
600          * @return\r
601          */\r
602         private int getFreqInfo(int[] i_pixcels,int i_th_h,int i_th_l,int[] o_edge_index)\r
603         {\r
604                 //トークンを解析して、周波数を計算\r
605                 int i=0;\r
606                 int frq_l2h=0;\r
607                 int frq_h2l=0;\r
608                 while(i<FRQ_POINTS){\r
609                         //L->Hトークンを検出する\r
610                         while(i<FRQ_POINTS){\r
611                                 final int index=i*3;\r
612                                 final int pix=(i_pixcels[index+0]+i_pixcels[index+1]+i_pixcels[index+2])/3;\r
613                                 if(pix>i_th_h){\r
614                                         //トークン発見\r
615                                         o_edge_index[frq_l2h+frq_h2l]=i;\r
616                                         frq_l2h++;\r
617                                         break;\r
618                                 }\r
619                                 i++;\r
620                         }\r
621                         i++;\r
622                         //L->Hトークンを検出する\r
623                         while(i<FRQ_POINTS){\r
624                                 final int index=i*3;\r
625                                 final int pix=(i_pixcels[index+0]+i_pixcels[index+1]+i_pixcels[index+2])/3;\r
626                                 if(pix<=i_th_l){\r
627                                         //トークン発見\r
628                                         o_edge_index[frq_l2h+frq_h2l]=i;\r
629                                         frq_h2l++;\r
630                                         break;\r
631                                 }\r
632                                 i++;\r
633                         }\r
634                         i++;\r
635                 }\r
636                 return frq_l2h==frq_h2l?frq_l2h:-1;                     \r
637         }\r
638 \r
639 \r
640 \r
641         public boolean readDataBits(double[] i_index_x,double[] i_index_y,int i_size,int i_th,MarkerPattEncoder o_bitbuffer)throws NyARException\r
642         {\r
643                 \r
644                 assert i_size*4<this._width;\r
645                 \r
646                 final double[] cpara=this._cparam;\r
647 \r
648                 final int[] ref_x=this._temp1;\r
649                 final int[] ref_y=this._temp2;\r
650                 final INyARRgbPixelReader reader=this._raster.getRgbPixelReader();\r
651                 final int[] pixcel_temp=this._pixcel_temp;\r
652                 \r
653                 int p=0;\r
654                 for(int i=0;i<i_size;i++){\r
655                         //1列分のピクセルのインデックス値を計算する。\r
656                         double cy0=1+i_index_y[i*2+0];\r
657                         double cy1=1+i_index_y[i*2+1];                  \r
658                         double cpy0_12=cpara[1]*cy0+cpara[2];\r
659                         double cpy0_45=cpara[4]*cy0+cpara[5];\r
660                         double cpy0_7=cpara[7]*cy0+1.0;\r
661                         double cpy1_12=cpara[1]*cy1+cpara[2];\r
662                         double cpy1_45=cpara[4]*cy1+cpara[5];\r
663                         double cpy1_7=cpara[7]*cy1+1.0;\r
664                         \r
665                         int pt=0;\r
666                         for(int i2=0;i2<i_size;i2++)\r
667                         {                       \r
668 \r
669                                 double d;\r
670                                 double cx0=1+i_index_x[i2*2+0];\r
671                                 double cx1=1+i_index_x[i2*2+1];\r
672 \r
673                                 double cp6_0=cpara[6]*cx0;\r
674                                 double cp6_1=cpara[6]*cx1;\r
675                                 double cpx0_0=cpara[0]*cx0;\r
676                                 double cpx3_0=cpara[3]*cx0;\r
677                                 \r
678                                 d=cp6_0+cpy0_7;\r
679                                 ref_x[pt]=(int)((cpx0_0+cpy0_12)/d);\r
680                                 ref_y[pt]=(int)((cpx3_0+cpy0_45)/d);\r
681                                 pt++;\r
682 \r
683                                 d=cp6_0+cpy1_7;\r
684                                 ref_x[pt]=(int)((cpx0_0+cpy1_12)/d);\r
685                                 ref_y[pt]=(int)((cpx3_0+cpy1_45)/d);\r
686                                 pt++;\r
687 \r
688                                 d=cp6_1+cpy0_7;\r
689                                 ref_x[pt]=(int)((cpara[0]*cx1+cpy0_12)/d);\r
690                                 ref_y[pt]=(int)((cpara[3]*cx1+cpy0_45)/d);\r
691                                 pt++;\r
692 \r
693                                 d=cp6_1+cpy1_7;\r
694                                 ref_x[pt]=(int)((cpara[0]*cx1+cpy1_12)/d);\r
695                                 ref_y[pt]=(int)((cpara[3]*cx1+cpy1_45)/d);\r
696                                 pt++;\r
697                         }\r
698                         //1行分のピクセルを取得(場合によっては専用アクセサを書いた方がいい)\r
699                         reader.getPixelSet(ref_x,ref_y,i_size*4,pixcel_temp);\r
700                         //グレースケールにしながら、line→mapへの転写\r
701                         for(int i2=0;i2<i_size;i2++){\r
702                                 int index=i2*3*4;\r
703                                 int pixel=(     pixcel_temp[index+0]+pixcel_temp[index+1]+pixcel_temp[index+2]+\r
704                                                         pixcel_temp[index+3]+pixcel_temp[index+4]+pixcel_temp[index+5]+\r
705                                                         pixcel_temp[index+6]+pixcel_temp[index+7]+pixcel_temp[index+8]+\r
706                                                         pixcel_temp[index+9]+pixcel_temp[index+10]+pixcel_temp[index+11])/(4*3);\r
707                                 o_bitbuffer.setBitByBitIndex(p,pixel>i_th?1:0);\r
708                                 p++;\r
709                         }\r
710                 }\r
711                 return true;\r
712         }\r
713         \r
714         public boolean setSquare(NyARIntPoint2d[] i_vertex) throws NyARException\r
715         {\r
716                 if (!getParam(i_vertex,this._cparam)) {\r
717                         return false;\r
718                 }\r
719                 return true;\r
720         }\r
721 }\r
722 \r
723 /**\r
724  * 遠近法を使ったパースペクティブ補正付きのINyARColorPatt\r
725  *\r
726  */\r
727 public class CopyOfNyARColorPatt_NyIdMarker implements INyARColorPatt\r
728 {\r
729         private int[] _patdata;\r
730         private NyARBufferReader _buf_reader;\r
731         private NyARRgbPixelReader_INT1D_GLAY_8 _pixelreader;\r
732         private NyARIntSize _size;\r
733         PerspectivePixelReader2 _perspective_gen;\r
734         private static final int LOCAL_LT=1;\r
735         /**\r
736          * 例えば、64\r
737          * @param i_width\r
738          * 取得画像の解像度幅\r
739          * @param i_height\r
740          * 取得画像の解像度高さ\r
741          * @param i_edge_percentage\r
742          * エッジ幅の割合(ARToolKit標準と同じなら、25)\r
743          */\r
744         public CopyOfNyARColorPatt_NyIdMarker(int i_model)\r
745         {\r
746                 //入力制限\r
747                 assert i_model==2;\r
748                 int resolution=i_model*2+1;\r
749                 this._size=new NyARIntSize(resolution,resolution);\r
750                 this._patdata = new int[resolution*resolution];\r
751                 this._buf_reader=new NyARBufferReader(this._patdata,NyARBufferReader.BUFFERFORMAT_INT1D_GLAY_8);\r
752                 this._pixelreader=new NyARRgbPixelReader_INT1D_GLAY_8(this._patdata,this._size);\r
753                 this._perspective_gen=new PerspectivePixelReader2(LOCAL_LT,LOCAL_LT,100,100);\r
754                 return;\r
755         }       \r
756         \r
757         public final int getWidth()\r
758         {\r
759                 return this._size.w;\r
760         }\r
761         public final int getHeight()\r
762         {\r
763                 return this._size.h;\r
764         }\r
765         public final NyARIntSize getSize()\r
766         {\r
767                 return  this._size;\r
768         }\r
769         public final INyARBufferReader getBufferReader()\r
770         {\r
771                 return this._buf_reader;\r
772         }\r
773         public final INyARRgbPixelReader getRgbPixelReader()\r
774         {\r
775                 return this._pixelreader;\r
776         }\r
777         \r
778 \r
779         public int[] vertex_x=new int[49*4];\r
780         public int[] vertex_y=new int[49*4];\r
781         public int[] vertex2_x=new int[400];\r
782         public int[] vertex2_y=new int[400];\r
783         public int[] line1=new int[45];\r
784         public int[] line2=new int[45];\r
785         public int[] sv=new int[4];\r
786         private int[] temp_pixcel=new int[144];\r
787 //      private NyARSingleEdgeFinder _edge_finder=new NyARSingleEdgeFinder(12,12);\r
788 \r
789 \r
790         /**\r
791          * マーカパラメータを格納する構造体\r
792          */\r
793         private class TMarkerParam{\r
794                 int threshold;\r
795                 int model;\r
796                 private double[] index_x=new double[25*2];\r
797                 private double[] index_y=new double[25*2];\r
798         }\r
799         /**\r
800          * 周期が等間隔か調べる。\r
801          * 次段半周期が、前段の80%より大きく、120%未満であるものを、等間隔周期であるとみなす。\r
802          * @param i_freq\r
803          * @param i_width\r
804          */\r
805         private boolean checkFreqWidth(int[] i_freq,int i_width)\r
806         {\r
807                 int c=i_freq[1]-i_freq[0];\r
808                 for(int i=1;i<i_width*2-1;i++){\r
809                         final int n=i_freq[i+1]-i_freq[i];\r
810                         final int v=n*100/c;\r
811                         if(v>150 || v<50){\r
812                                 return false;\r
813                         }\r
814                         c=n;\r
815                 }\r
816                 return true;\r
817         }\r
818         private static int MIN_FREQ=3;\r
819         private static int MAX_FREQ=10;\r
820         \r
821         private int getRowFreq(int i_y,int i_th_h,int i_th_l,int[] o_freq_index)throws NyARException\r
822         {\r
823                 //3,4,5,6,7,8,9,10\r
824                 int freq_index1[]=new int[45];\r
825                 int freq_count_table[]=new int[10];\r
826                 //0,2,4,6,8,10,12,14,16,18,20の要素を持つ配列\r
827                 int freq_table[][]=new int[10][20];\r
828                 //初期化\r
829                 \r
830                 //10-20ピクセル目からタイミングパターンを検出\r
831                 for(int i=i_y;i<i_y+10;i++){\r
832                         final int freq_t=this._perspective_gen.getRowFrequency(i,i_th_h,i_th_l,freq_index1);\r
833                         //周期は3-10であること\r
834                         if(freq_t<MIN_FREQ || freq_t>MAX_FREQ){\r
835                                 continue;\r
836                         }\r
837                         //周期は等間隔であること\r
838                         if(!checkFreqWidth(freq_index1,freq_t)){\r
839                                 continue;\r
840                         }\r
841                         //検出カウンタを追加\r
842                         freq_count_table[freq_t]++;\r
843                         for(int i2=0;i2<freq_t*2;i2++){\r
844                                 freq_table[freq_t][i2]+=freq_index1[i2];\r
845                         }\r
846                 }\r
847                 //一番成分の大きいものを得る\r
848                 int index=-1;\r
849                 int max=0;\r
850                 for(int i=0;i<MAX_FREQ;i++){\r
851                         if(max<freq_count_table[i]){\r
852                                 index=i;\r
853                                 max=freq_count_table[i];\r
854                         }\r
855                 }\r
856                 /*周波数インデクスを計算*/\r
857                 for(int i=0;i<index*2;i++)\r
858                 {\r
859                         o_freq_index[i]=freq_table[index][i]/max;\r
860                 }\r
861                 return index;\r
862         }\r
863         private int getColFreq(int i_y,int i_th_h,int i_th_l,int[] o_freq_index)throws NyARException\r
864         {\r
865                 //3,4,5,6,7,8,9,10\r
866                 int freq_index1[]=new int[45];\r
867                 int freq_count_table[]=new int[10];\r
868                 int freq_table[][]=new int[10][20];\r
869                 //初期化\r
870                 \r
871                 //10-20ピクセル目からタイミングパターンを検出\r
872                 for(int i=i_y;i<i_y+10;i++){\r
873                         final int freq_t=this._perspective_gen.getColFrequency(i,i_th_h,i_th_l,freq_index1);\r
874                         //周期は3-10であること\r
875                         if(freq_t<MIN_FREQ || freq_t>MAX_FREQ){\r
876                                 continue;\r
877                         }\r
878                         //周期は等間隔であること\r
879                         if(!checkFreqWidth(freq_index1,freq_t)){\r
880                                 continue;\r
881                         }\r
882                         //検出カウンタを追加\r
883                         freq_count_table[freq_t]++;\r
884                         for(int i2=0;i2<freq_t*2;i2++){\r
885                                 freq_table[freq_t][i2]+=freq_index1[i2];\r
886                         }\r
887                 }\r
888                 //一番成分の大きいものを得る\r
889                 int index=-1;\r
890                 int max=0;\r
891                 for(int i=0;i<MAX_FREQ;i++){\r
892                         if(max<freq_count_table[i]){\r
893                                 index=i;\r
894                                 max=freq_count_table[i];\r
895                         }\r
896                 }\r
897                 for(int i=0;i<10;i++){\r
898                         System.out.print(freq_count_table[i]+",");\r
899                 }\r
900                 System.out.println();\r
901                 if(index==-1){\r
902                         return -1;\r
903                 }\r
904                 /*周波数インデクスを計算*/\r
905                 for(int i=0;i<index*2;i++)\r
906                 {\r
907                         o_freq_index[i]=freq_table[index][i]/max;\r
908                 }\r
909                 return index;\r
910         }\r
911         private boolean detectMarkerParam(INyARRgbPixelReader i_reader,TMarkerParam o_param)throws NyARException\r
912         {\r
913                 TThreshold th=new TThreshold();\r
914                 \r
915                 detectThresholdValue(i_reader,10,10,th);\r
916                 //周波数測定(最も正しい周波数を検出する)\r
917 \r
918                 \r
919 \r
920 \r
921                 //左上,右下から、12x12(抽出範囲は10x10)の調査用矩形を抽出\r
922 \r
923 \r
924                 \r
925                 //周波数を測定\r
926                 int freq_index1[]=new int[45];\r
927                 int freq_index2[]=new int[45];\r
928                 int frq_t=getRowFreq(10,th.th_h,th.th_l,freq_index1);\r
929                 int frq_b=getRowFreq(80,th.th_h,th.th_l,freq_index2);\r
930                 //周波数はまとも?\r
931                 if((frq_t<0 && frq_b<0) || frq_t==frq_b){\r
932                         System.out.print("FRQ_R");\r
933                         return false;\r
934                 }\r
935                 //タイミングパターンからインデクスを作成\r
936                 int freq;\r
937                 int[] index;\r
938                 if(frq_t>frq_b){\r
939                         freq=frq_t;\r
940                         index=freq_index1;\r
941                 }else{\r
942                         freq=frq_b;\r
943                         index=freq_index2;\r
944                 }\r
945                 for(int i=0;i<freq*2-1;i++){\r
946                         o_param.index_x[i*2]=((index[i+1]-index[i])*2/5+index[i])*2+PerspectivePixelReader.FRQ_EDGE;\r
947                         o_param.index_x[i*2+1]=((index[i+1]-index[i])*3/5+index[i])*2+PerspectivePixelReader.FRQ_EDGE;\r
948                 }\r
949                 int frq_l=getColFreq(10,th.th_h,th.th_l,freq_index1);\r
950                 int frq_r=getColFreq(80,th.th_h,th.th_l,freq_index2);           \r
951                 //周波数はまとも?\r
952                 if((frq_l<0 && frq_r<0) || frq_l==frq_r){\r
953                         System.out.print("FRQ_C");\r
954                         return false;\r
955                 }\r
956                 //タイミングパターンからインデクスを作成\r
957                 if(frq_l>frq_r){\r
958                         freq=frq_l;\r
959                         index=freq_index1;\r
960                 }else{\r
961                         freq=frq_r;\r
962                         index=freq_index2;\r
963                 }\r
964                 for(int i=0;i<freq*2-1;i++){\r
965                         o_param.index_y[i*2]=((index[i+1]-index[i])*2/5+index[i])*2+PerspectivePixelReader.FRQ_EDGE;\r
966                         o_param.index_y[i*2+1]=((index[i+1]-index[i])*3/5+index[i])*2+PerspectivePixelReader.FRQ_EDGE;\r
967                 }\r
968 \r
969                 \r
970                 \r
971                 //Lv4以上は無理\r
972                 if(freq>4){\r
973                         System.out.print("LVL_4");\r
974                         return false;\r
975                 }\r
976                 o_param.model=freq-1;\r
977                 o_param.threshold=th.th;\r
978                 return true;\r
979                 \r
980         }\r
981         private class TThreshold{\r
982                 public int th_h;\r
983                 public int th_l;\r
984                 public int th;\r
985         }\r
986         /**\r
987          * 指定した場所のピクセル値を調査して、閾値を計算して返します。\r
988          * @param i_reader\r
989          * @param i_x\r
990          * @param i_y\r
991          * @return\r
992          * @throws NyARException\r
993          */\r
994         private void detectThresholdValue(INyARRgbPixelReader i_reader,int i_x,int i_y,TThreshold o_threshold)throws NyARException\r
995         {\r
996                 final int[] temp_pixel=this.temp_pixcel;\r
997                 //特定エリアから画素を得る\r
998                 this._perspective_gen.rectPixels(i_x,i_y,10,10,temp_pixel);\r
999                 //ソート\r
1000                 int len=100;\r
1001                 int h = len *13/10;\r
1002                 for(;;){\r
1003                     int swaps = 0;\r
1004                     for (int i = 0; i + h < len; i++) {\r
1005                         if (temp_pixel[i + h] > temp_pixel[i]) {\r
1006                             final int temp = temp_pixel[i + h];\r
1007                             temp_pixel[i + h] = temp_pixel[i];\r
1008                             temp_pixel[i] = temp;\r
1009                             swaps++;\r
1010                         }\r
1011                     }\r
1012                     if (h == 1) {\r
1013                         if (swaps == 0){\r
1014                                 break;\r
1015                         }\r
1016                     }else{\r
1017                         h=h*10/13;\r
1018                     }\r
1019                 }\r
1020                 //値の大きい方と小さい方の各4点を取得\r
1021                 //4点の中間を閾値中心とする\r
1022                 final int th_l=temp_pixel[99]+temp_pixel[98]+temp_pixel[97]+temp_pixel[96];\r
1023                 final int th_h=temp_pixel[0]+temp_pixel[1]+temp_pixel[2]+temp_pixel[3];\r
1024                 int th_sub=(th_h-th_l)/(4*5);//ヒステリシス(20%)\r
1025                 int th=(th_h+th_l)/8;\r
1026                 o_threshold.th=th;\r
1027                 o_threshold.th_h=th+th_sub;//ヒステリシス付き閾値\r
1028                 o_threshold.th_l=th-th_sub;//ヒステリシス付き閾値\r
1029                 System.out.println(o_threshold.th+","+o_threshold.th_h+","+o_threshold.th_l);\r
1030                 return;\r
1031         }       \r
1032         \r
1033 \r
1034         /**\r
1035          * \r
1036          * @param image\r
1037          * @param i_marker\r
1038          * @return 切り出しに失敗した\r
1039          * @throws Exception\r
1040          */\r
1041         public boolean pickFromRaster(INyARRgbRaster image, NyARSquare i_square)throws NyARException\r
1042         {\r
1043                 this._perspective_gen.setSourceRaster(image);\r
1044                 i_square.imvertex[0].x=149;\r
1045                 i_square.imvertex[0].y=179;\r
1046                 i_square.imvertex[0].x=27;\r
1047                 i_square.imvertex[0].y=96;\r
1048                 i_square.imvertex[0].x=152;\r
1049                 i_square.imvertex[0].y=29;\r
1050                 i_square.imvertex[0].x=280;\r
1051                 i_square.imvertex[0].y=72;\r
1052                 \r
1053                 //遠近法のパラメータを計算\r
1054                 if(!this._perspective_gen.setSourceSquare(i_square.imvertex)){\r
1055                         return false;\r
1056                 };\r
1057                 \r
1058                 final INyARRgbPixelReader reader=image.getRgbPixelReader();\r
1059 \r
1060 \r
1061                 TMarkerParam param=new TMarkerParam();\r
1062                 MarkerPattEncoder encoder=new MarkerPattEncoder();\r
1063                 //マーカパラメータを取得\r
1064                 if(!detectMarkerParam(reader,param))\r
1065                 {\r
1066                         System.out.println("E");\r
1067                         return false;\r
1068                 }               \r
1069                 final int resolution=(param.model*2)+1;\r
1070                 //Threshold検出\r
1071 \r
1072                 if(!encoder.initEncoder(param.model)){\r
1073                         return false;\r
1074                 }\r
1075                 //int i_stx,int i_sty,int size_x,int size_y,int i_resolution,int i_th,\r
1076                 //this._perspective_gen.readDataBits(st_x,st_y,size_x,size_y,resolution, param.threshold, encoder);\r
1077                 this._perspective_gen.readDataBits(param.index_x,param.index_y,resolution, param.threshold, encoder);\r
1078                 encoder.encode();\r
1079 \r
1080                 for(int i=0;i<49*4;i++){\r
1081                         this.vertex_x[i]=0;\r
1082                         this.vertex_y[i]=0;\r
1083                 }\r
1084                 for(int i=0;i<resolution*2;i++){\r
1085                         for(int i2=0;i2<resolution*2;i2++){\r
1086                                 this.vertex_x[i*resolution*2+i2]=(int)param.index_x[i2];\r
1087                                 this.vertex_y[i*resolution*2+i2]=(int)param.index_y[i];\r
1088                                 \r
1089                         }\r
1090                 }\r
1091 \r
1092                 System.out.println(param.model);\r
1093 /*\r
1094                 //マップを作りなおす\r
1095                 for(int i=0;i<size*size;i++){\r
1096                         this._patdata[i]=encoder.getBit(_role_table[i])==0?0:255;\r
1097                 }\r
1098 */                      \r
1099                 \r
1100                 \r
1101                 return true;\r
1102         }\r
1103         public static void main(String[] args)\r
1104         {\r
1105                 try {\r
1106                         double[] a=new double[10];\r
1107                         int[] d={\r
1108                                 //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9\r
1109                                         0,0,0,0,0,0,0,1,5,1,2,0,0,0,1,2,5,2,1,0,\r
1110                                         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};\r
1111                         NyARSingleEdgeFinder px=new NyARSingleEdgeFinder(20,2);\r
1112                         System.out.print(px.scanEdgeLeftToRight(d,0,0,a));\r
1113                         System.out.print("");\r
1114                 } catch (Exception e) {\r
1115                         e.printStackTrace();\r
1116                 }\r
1117 \r
1118         }       \r
1119 }