OSDN Git Service

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