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
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
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
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
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
25 package jp.nyatla.nyartoolkit.nyidmarker;
\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
41 * NyARColorPatt_NyIdMarkerがラスタからPerspective変換して読みだすためのクラス
\r
44 final class PerspectivePixelReader
\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
51 public PerspectivePixelReader()
\r
56 public boolean setSourceSquare(NyARIntPoint2d[] i_vertex)throws NyARException
\r
58 return this._param_gen.getParam(READ_RESOLUTION,READ_RESOLUTION,i_vertex, this._cparam);
\r
60 public boolean setSourceSquare(NyARDoublePoint2d[] i_vertex)throws NyARException
\r
62 return this._param_gen.getParam(READ_RESOLUTION,READ_RESOLUTION,i_vertex, this._cparam);
\r
73 * o_pixelへの格納場所の先頭インデクス
\r
75 * @throws NyARException
\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
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
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
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
98 for(int i2=0;i2<i_width;i2++)
\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
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
117 o_pixel[out_index]=(pixcel_temp[index+0]+pixcel_temp[index+1]+pixcel_temp[index+2])/3;
\r
124 * i_freqにあるゼロクロス点の周期が、等間隔か調べます。
\r
125 * 次段半周期が、前段の80%より大きく、120%未満であるものを、等間隔周期であるとみなします。
\r
129 private static boolean checkFreqWidth(int[] i_freq,int i_width)
\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
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
149 * 見つかれば0以上、密辛ければ0未満
\r
151 private static int getMaxFreq(int[] i_freq_count_table,int[] i_freq_table,int[] o_freq_table)
\r
156 for(int i=0;i<MAX_FREQ;i++){
\r
157 if(max<i_freq_count_table[i]){
\r
159 max=i_freq_count_table[i];
\r
166 final int st=(index-1)*index;
\r
167 for(int i=0;i<index*2;i++)
\r
169 o_freq_table[i]=i_freq_table[st+i]*FRQ_STEP/max;
\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
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
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
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
195 * i_y1行目とi_y2行目を平均して、タイミングパターンの周波数を得ます。
\r
196 * LHLを1周期として、たとえばLHLHLの場合は2を返します。LHLHやHLHL等の始端と終端のレベルが異なるパターンを
\r
203 * @param o_edge_index
\r
204 * 検出したエッジ位置(H->L,L->H)のインデクスを受け取る配列です。
\r
205 * [FRQ_POINTS]以上の配列を指定してください。
\r
207 * @throws NyARException
\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
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
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
224 for(int i=0;i<110;i++){
\r
227 final int raster_width=i_raster_size.w;
\r
228 final int raster_height=i_raster_size.h;
\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
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
243 for(int i2=0;i2<FRQ_POINTS;i2++)
\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
258 //ピクセルを取得(入力画像を多様化するならここから先を調整すること)
\r
259 i_reader.getPixelSet(ref_x,ref_y,FRQ_POINTS,pixcel_temp);
\r
261 //o_edge_indexを一時的に破壊して調査する
\r
262 final int freq_t=getFreqInfo(pixcel_temp,i_th_h,i_th_l,o_edge_index);
\r
265 if(freq_t<MIN_FREQ || freq_t>MAX_FREQ){
\r
269 if(!checkFreqWidth(o_edge_index,freq_t)){
\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
279 return getMaxFreq(freq_count_table,freq_table,o_edge_index);
\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
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
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
295 final int[] freq_table=this._freq_table;
\r
296 for(int i=0;i<110;i++){
\r
299 final int raster_width=i_raster_size.w;
\r
300 final int raster_height=i_raster_size.h;
\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
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
315 for(int i2=0;i2<FRQ_POINTS;i2++)
\r
317 int cy=1+i2*FRQ_STEP+FRQ_EDGE;
\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
331 //ピクセルを取得(入力画像を多様化するならここを調整すること)
\r
332 i_reader.getPixelSet(ref_x,ref_y,FRQ_POINTS,pixcel_temp);
\r
334 final int freq_t=getFreqInfo(pixcel_temp,i_th_h,i_th_l,o_edge_index);
\r
336 if(freq_t<MIN_FREQ || freq_t>MAX_FREQ){
\r
340 if(!checkFreqWidth(o_edge_index,freq_t)){
\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
350 return getMaxFreq(freq_count_table,freq_table,o_edge_index);
\r
354 * デバックすんだらstaticにしておk
\r
358 * @param o_edge_index
\r
361 private static int getFreqInfo(int[] i_pixcels,int i_th_h,int i_th_l,int[] o_edge_index)
\r
367 while(i<FRQ_POINTS){
\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
374 o_edge_index[frq_l2h+frq_h2l]=i;
\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
387 o_edge_index[frq_l2h+frq_h2l]=i;
\r
395 return frq_l2h==frq_h2l?frq_l2h:-1;
\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
406 public static class TThreshold{
\r
421 * ピクセル配列の上位、下位の4ピクセルのピクセル値平均を求めます。
\r
422 * この関数は、(4/i_pixcel.length)の領域を占有するPtail法で双方向の閾値を求めることになります。
\r
427 private void getPtailHighAndLow(int[] i_pixcel,THighAndLow i_out)
\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
432 for(int i=i_pixcel.length-1;i>=1;i--){
\r
433 final int pix=i_pixcel[i];
\r
477 i_out.l=(l0+l1+l2+l3)/4;
\r
478 i_out.h=(h0+h1+h2+h3)/4;
\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
485 * 指定した場所のピクセル値を調査して、閾値を計算して返します。
\r
490 * @throws NyARException
\r
492 public void detectThresholdValue(INyARRgbPixelReader i_reader,NyARIntSize i_raster_size,TThreshold o_threshold)throws NyARException
\r
494 final int[] th_pixels=this._th_pixels;
\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
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
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
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
508 final THighAndLow hl=this.__detectThresholdValue_hl;
\r
510 getPtailHighAndLow(th_pixels,hl);
\r
515 int th=(hl.h+hl.l)/2;
\r
517 int th_sub=(hl.h-hl.l)/5;
\r
520 o_threshold.th_h=th+th_sub;//ヒステリシス付き閾値
\r
521 o_threshold.th_l=th-th_sub;//ヒステリシス付き閾値
\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
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
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
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
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
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
566 private boolean getHighPixelCenter(int i_st,final int[] i_pixels,int i_width,int i_height,int i_th,NyARIntPoint2d o_point)
\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
581 if(number_of_pos>0){
\r
582 pos_x/=number_of_pos;
\r
583 pos_y/=number_of_pos;
\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
596 final int[] freq_index1=this.__detectDataBitsIndex_freq_index1;
\r
597 final int[] freq_index2=this.__detectDataBitsIndex_freq_index2;
\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
602 if((frq_t<0 && frq_b<0) || frq_t==frq_b){
\r
605 //タイミングパターンからインデクスを作成
\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
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
624 if((frq_l<0 && frq_r<0) || frq_l==frq_r){
\r
627 //タイミングパターンからインデクスを作成
\r
636 if(freq_v!=freq_h){
\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
647 if(freq_v>MAX_FREQ){
\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
656 public boolean readDataBits(INyARRgbPixelReader i_reader,NyARIntSize i_raster_size,PerspectivePixelReader.TThreshold i_th,MarkerPattEncoder o_bitbuffer)throws NyARException
\r
658 final double[] index_x=this.__readDataBits_index_bit_x;
\r
659 final double[] index_y=this.__readDataBits_index_bit_y;
\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
668 if(!o_bitbuffer.initEncoder(size-1)){
\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
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
683 final int th=i_th.th;
\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
697 for(int i2=0;i2<resolution;i2++)
\r
701 double cx0=1+index_x[i2*2+0];
\r
702 double cx1=1+index_x[i2*2+1];
\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
708 double cp6_1=cpara_6*cx1;
\r
709 double cpx0_1=cpara_0*cx1;
\r
710 double cpx3_1=cpara_3*cx1;
\r
713 ref_x[pt]=(int)((cpx0_0+cpy0_12)/d);
\r
714 ref_y[pt]=(int)((cpx3_0+cpy0_45)/d);
\r
718 ref_x[pt]=(int)((cpx0_0+cpy1_12)/d);
\r
719 ref_y[pt]=(int)((cpx3_0+cpy1_45)/d);
\r
723 ref_x[pt]=(int)((cpx0_1+cpy0_12)/d);
\r
724 ref_y[pt]=(int)((cpx3_1+cpy0_45)/d);
\r
728 ref_x[pt]=(int)((cpx0_1+cpy1_12)/d);
\r
729 ref_y[pt]=(int)((cpx3_1+cpy1_45)/d);
\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
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
743 o_bitbuffer.setBitByBitIndex(p,pixel>th?0:1);
\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
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
761 public boolean setSquare(NyARIntPoint2d[] i_vertex) throws NyARException
\r
763 if (!this._param_gen.getParam(READ_RESOLUTION,READ_RESOLUTION,i_vertex,this._cparam)) {
\r
770 class MarkerPattDecoder
\r
772 public void decode(int model,int domain,int mask)
\r
781 class MarkerPattEncoder
\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
792 private final static int[] _bit_table_2={
\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
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
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
813 assert i_value==0 || i_value==1;
\r
814 final int bit_no=this._bit_table[i_index_no];
\r
816 this._bits[0]=i_value;
\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
825 public void setBit(int i_bit_no,int i_value)
\r
827 assert i_value==0 || i_value==1;
\r
829 this._bits[0]=i_value;
\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
837 public int getBit(int i_bit_no)
\r
840 return this._bits[0];
\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
847 public int getModel()
\r
849 return this._model;
\r
851 private static int getControlValue(int i_model,int[] i_data)
\r
856 v=(i_data[2] & 0x0e)>>1;
\r
859 v=(i_data[4] & 0x3e)>>1;
\r
860 return v>=21?v-1:v;
\r
870 public static int getCheckValue(int i_model,int[] i_data)
\r
875 v=(i_data[2] & 0xe0)>>5;
\r
878 v=((i_data[4] & 0x80)>>7) |((i_data[5] & 0x0f)<<1);
\r
889 public boolean initEncoder(int i_model)
\r
891 if(i_model>3 || i_model<2){
\r
892 //Lv4以降に対応する時は、この制限を変える。
\r
895 this._bit_table=_bit_tables[i_model-2];
\r
896 this._model=i_model;
\r
899 private int getDirection()
\r
903 switch(this._model){
\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
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
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
929 }else if(b==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
939 * 格納しているマーカパターンをエンコードして、マーカデータを返します。
\r
942 * 成功すればマーカの方位を返却します。失敗すると-1を返します。
\r
945 public int encode(NyIdMarkerPattern o_out)
\r
947 final int d=getDirection();
\r
952 getRotatedBits(d,o_out.data);
\r
953 final int model=this._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
966 private void getRotatedBits(int i_direction,int[] o_out)
\r
968 int sl=i_direction*2;
\r
972 o_out[0]=this._bits[0];
\r
975 o_out[1]=((w1<<sl)|(w1>>sr))& 0xff;
\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
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
1001 //RECT4(Lv4以降はここの制限を変える)
\r
1002 // shiftLeft(this._bits,7,3,i_direction*8);
\r
1003 // if(this._model<4){
\r
1008 public void shiftLeft(int[] i_pack,int i_start,int i_length,int i_ls)
\r
1010 int[] work=this._work;
\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
1016 work[0]=(i_pack[i_start]<<mod_shift)|(0xff&(i_pack[i_start+i_length-1]>>(8-mod_shift)));
\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
1026 * ラスタ画像の任意矩形から、NyARIdMarkerDataを抽出します。
\r
1029 public class NyIdMarkerPickup
\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
1036 public NyIdMarkerPickup()
\r
1038 this._perspective_reader=new PerspectivePixelReader();
\r
1042 * imageの4頂点で囲まれた矩形からidマーカを読みだします。
\r
1048 * @throws NyARException
\r
1050 public final boolean pickFromRaster(INyARRgbRaster image, NyARDoublePoint2d[] i_vertex,NyIdMarkerPattern o_data,NyIdMarkerParam o_param)throws NyARException
\r
1053 if(!this._perspective_reader.setSourceSquare(i_vertex)){
\r
1056 return this._pickFromRaster(image,o_data,o_param);
\r
1059 * imageの4頂点で囲まれた矩形からidマーカを読みだします。
\r
1065 * @throws NyARException
\r
1067 public final boolean pickFromRaster(INyARRgbRaster image, NyARIntPoint2d[] i_vertex,NyIdMarkerPattern o_data,NyIdMarkerParam o_param)throws NyARException
\r
1069 if(!this._perspective_reader.setSourceSquare(i_vertex)){
\r
1072 return this._pickFromRaster(image,o_data,o_param);
\r
1076 * i_imageから、idマーカを読みだします。
\r
1077 * o_dataにはマーカデータ、o_paramにはマーカのパラメータを返却します。
\r
1083 * @throws NyARException
\r
1085 private final boolean _pickFromRaster(INyARRgbRaster image, NyIdMarkerPattern o_data,NyIdMarkerParam o_param)throws NyARException
\r
1087 INyARRgbPixelReader reader=image.getRgbPixelReader();
\r
1088 NyARIntSize raster_size=image.getSize();
\r
1090 final PerspectivePixelReader.TThreshold th=this.__pickFromRaster_th;
\r
1091 final MarkerPattEncoder encoder=this.__pickFromRaster_encoder;
\r
1093 this._perspective_reader.detectThresholdValue(reader,raster_size,th);
\r
1095 if(!this._perspective_reader.readDataBits(reader,raster_size,th, encoder)){
\r
1098 final int d=encoder.encode(o_data);
\r
1102 o_param.direction=d;
\r
1103 o_param.threshold=th.th;
\r