OSDN Git Service

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