OSDN Git Service

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