OSDN Git Service

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