2 * PROJECT: NyARToolkit
\r
3 * --------------------------------------------------------------------------------
\r
4 * This work is based on the original ARToolKit developed by
\r
7 * HITLab, University of Washington, Seattle
\r
8 * http://www.hitl.washington.edu/artoolkit/
\r
10 * The NyARToolkit is Java version ARToolkit class library.
\r
11 * Copyright (C)2008 R.Iizuka
\r
13 * This program is free software; you can redistribute it and/or
\r
14 * modify it under the terms of the GNU General Public License
\r
15 * as published by the Free Software Foundation; either version 2
\r
16 * of the License, or (at your option) any later version.
\r
18 * This program is distributed in the hope that it will be useful,
\r
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
21 * GNU General Public License for more details.
\r
23 * You should have received a copy of the GNU General Public License
\r
24 * along with this framework; if not, write to the Free Software
\r
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
27 * For further information please contact.
\r
28 * http://nyatla.jp/nyatoolkit/
\r
29 * <airmail(at)ebony.plala.or.jp>
\r
32 package jp.nyatla.nyartoolkit.nyidmarker;
\r
34 import jp.nyatla.nyartoolkit.NyARException;
\r
35 import jp.nyatla.nyartoolkit.core.NyARSquare;
\r
36 import jp.nyatla.nyartoolkit.core.raster.rgb.*;
\r
37 import jp.nyatla.nyartoolkit.core.rasterreader.*;
\r
38 import jp.nyatla.nyartoolkit.core.types.*;
\r
39 import jp.nyatla.nyartoolkit.core.utils.*;
\r
48 * NyARColorPatt_NyIdMarkerがラスタからPerspective変換して読みだすためのクラス
\r
51 class PerspectivePixelReader
\r
53 private NyARPerspectiveParamGenerator _param_gen=new NyARPerspectiveParamGenerator_O1(1,1,100,100);
\r
54 private double[] _cparam=new double[8];
\r
56 private INyARRgbRaster _raster;
\r
57 private NyARIntSize _raster_size;
\r
59 public PerspectivePixelReader()
\r
63 public void setSourceRaster(INyARRgbRaster i_raster)
\r
65 this._raster=i_raster;
\r
66 this._raster_size=i_raster.getSize();
\r
69 public boolean setSourceSquare(NyARIntPoint2d[] i_vertex)throws NyARException
\r
71 return this._param_gen.getParam(i_vertex, this._cparam);
\r
83 * o_pixelへの格納場所の先頭インデクス
\r
85 * @throws NyARException
\r
87 private boolean rectPixels(int i_lt_x,int i_lt_y,int i_step_x,int i_step_y,int i_width,int i_height,int i_out_st,int[] o_pixel)throws NyARException
\r
89 final double[] cpara=this._cparam;
\r
90 final INyARRgbPixelReader reader=this._raster.getRgbPixelReader();
\r
91 final int[] ref_x=this._ref_x;
\r
92 final int[] ref_y=this._ref_y;
\r
93 final int[] pixcel_temp=this._pixcel_temp;
\r
94 final int raster_width=this._raster_size.w;
\r
95 final int raster_height=this._raster_size.h;
\r
97 int out_index=i_out_st;
\r
98 final double cpara_6=cpara[6];
\r
99 final double cpara_0=cpara[0];
\r
100 final double cpara_3=cpara[3];
\r
102 for(int i=0;i<i_height;i++){
\r
103 //1列分のピクセルのインデックス値を計算する。
\r
104 int cy0=1+i*i_step_y+i_lt_y;
\r
105 double cpy0_12=cpara[1]*cy0+cpara[2];
\r
106 double cpy0_45=cpara[4]*cy0+cpara[5];
\r
107 double cpy0_7=cpara[7]*cy0+1.0;
\r
109 for(int i2=0;i2<i_width;i2++)
\r
111 final int cx0=1+i2*i_step_x+i_lt_x;
\r
112 final double d=cpara_6*cx0+cpy0_7;
\r
113 final int x=(int)((cpara_0*cx0+cpy0_12)/d);
\r
114 final int y=(int)((cpara_3*cx0+cpy0_45)/d);
\r
115 if(x<0||y<0||x>=raster_width||y>=raster_height)
\r
123 //1行分のピクセルを取得(場合によっては専用アクセサを書いた方がいい)
\r
124 reader.getPixelSet(ref_x,ref_y,i_width,pixcel_temp);
\r
125 //グレースケールにしながら、line→mapへの転写
\r
126 for(int i2=0;i2<i_width;i2++){
\r
128 o_pixel[out_index]=(pixcel_temp[index+0]+pixcel_temp[index+1]+pixcel_temp[index+2])/3;
\r
135 * i_freqにあるゼロクロス点の周期が、等間隔か調べます。
\r
136 * 次段半周期が、前段の80%より大きく、120%未満であるものを、等間隔周期であるとみなします。
\r
140 private static boolean checkFreqWidth(int[] i_freq,int i_width)
\r
142 int c=i_freq[1]-i_freq[0];
\r
143 final int count=i_width*2-1;
\r
144 for(int i=1;i<count;i++){
\r
145 final int n=i_freq[i+1]-i_freq[i];
\r
146 final int v=n*100/c;
\r
155 * i_freq_count_tableとi_freq_tableの内容を調査し、最も大きな周波数成分を返します。
\r
156 * @param i_freq_count_table
\r
157 * @param i_freq_table
\r
158 * @param o_freq_table
\r
160 * 見つかれば0以上、密辛ければ0未満
\r
162 private static int getMaxFreq(int[] i_freq_count_table,int[] i_freq_table,int[] o_freq_table)
\r
167 for(int i=0;i<MAX_FREQ;i++){
\r
168 if(max<i_freq_count_table[i]){
\r
170 max=i_freq_count_table[i];
\r
177 final int st=(index-1)*index;
\r
178 for(int i=0;i<index*2;i++)
\r
180 o_freq_table[i]=i_freq_table[st+i]*FRQ_STEP/max;
\r
186 //タイミングパターン用のパラメタ(FRQ_POINTS*FRQ_STEPが100を超えないようにすること)
\r
187 private static final int FRQ_EDGE=5;
\r
188 private static final int FRQ_STEP=2;
\r
189 private static final int FRQ_POINTS=(100-(FRQ_EDGE*2))/FRQ_STEP;
\r
192 private static final int MIN_FREQ=3;
\r
193 private static final int MAX_FREQ=10;
\r
194 private static final int FREQ_SAMPLE_NUM=4;
\r
195 private static final int MAX_DATA_BITS=MAX_FREQ+MAX_FREQ-1;
\r
197 private final int[] _ref_x=new int[108];
\r
198 private final int[] _ref_y=new int[108];
\r
199 //(model+1)*4*3とTHRESHOLD_PIXEL*3のどちらか大きい方
\r
200 private int[] _pixcel_temp=new int[108*3];
\r
202 private final int[] _freq_count_table=new int[MAX_FREQ];
\r
203 private final int[] _freq_table=new int[(MAX_FREQ*2-1)*MAX_FREQ*2/2];
\r
206 * i_y1行目とi_y2行目を平均して、タイミングパターンの周波数を得ます。
\r
207 * LHLを1周期として、たとえばLHLHLの場合は2を返します。LHLHやHLHL等の始端と終端のレベルが異なるパターンを
\r
214 * @param o_edge_index
\r
215 * 検出したエッジ位置(H->L,L->H)のインデクスを受け取る配列です。
\r
216 * [FRQ_POINTS]以上の配列を指定してください。
\r
218 * @throws NyARException
\r
220 public int getRowFrequency(int i_y1,int i_th_h,int i_th_l,int[] o_edge_index)throws NyARException
\r
223 final int[] freq_count_table=this._freq_count_table;
\r
224 //0,2,4,6,8,10,12,14,16,18,20の要素を持つ配列
\r
225 final int freq_table[]=this._freq_table;
\r
227 final double[] cpara=this._cparam;
\r
228 final INyARRgbPixelReader reader=this._raster.getRgbPixelReader();
\r
229 final int[] ref_x=this._ref_x;
\r
230 final int[] ref_y=this._ref_y;
\r
231 final int[] pixcel_temp=this._pixcel_temp;
\r
232 for(int i=0;i<10;i++){
\r
233 freq_count_table[i]=0;
\r
235 for(int i=0;i<110;i++){
\r
238 final int raster_width=this._raster_size.w;
\r
239 final int raster_height=this._raster_size.h;
\r
241 final double cpara_0=cpara[0];
\r
242 final double cpara_3=cpara[3];
\r
243 final double cpara_6=cpara[6];
\r
245 //10-20ピクセル目からタイミングパターンを検出
\r
246 for(int i=0;i<FREQ_SAMPLE_NUM;i++){
\r
247 //2行分のピクセルインデックスを計算
\r
248 final double cy0=1+i_y1+i;
\r
249 final double cpy0_12=cpara[1]*cy0+cpara[2];
\r
250 final double cpy0_45=cpara[4]*cy0+cpara[5];
\r
251 final double cpy0_7=cpara[7]*cy0+1.0;
\r
254 for(int i2=0;i2<FRQ_POINTS;i2++)
\r
256 final double cx0=1+i2*FRQ_STEP+FRQ_EDGE;
\r
257 final double d=(cpara_6*cx0)+cpy0_7;
\r
258 final int x=(int)((cpara_0*cx0+cpy0_12)/d);
\r
259 final int y=(int)((cpara_3*cx0+cpy0_45)/d);
\r
260 if(x<0||y<0||x>=raster_width||y>=raster_height)
\r
269 //ピクセルを取得(入力画像を多様化するならここから先を調整すること)
\r
270 reader.getPixelSet(ref_x,ref_y,FRQ_POINTS,pixcel_temp);
\r
272 //o_edge_indexを一時的に破壊して調査する
\r
273 final int freq_t=getFreqInfo(pixcel_temp,i_th_h,i_th_l,o_edge_index);
\r
276 if(freq_t<MIN_FREQ || freq_t>MAX_FREQ){
\r
280 if(!checkFreqWidth(o_edge_index,freq_t)){
\r
284 freq_count_table[freq_t]++;
\r
285 final int table_st=(freq_t-1)*freq_t;
\r
286 for(int i2=0;i2<freq_t*2;i2++){
\r
287 freq_table[table_st+i2]+=o_edge_index[i2];
\r
290 return getMaxFreq(freq_count_table,freq_table,o_edge_index);
\r
293 public int getColFrequency(int i_x1,int i_th_h,int i_th_l,int[] o_edge_index)throws NyARException
\r
295 final double[] cpara=this._cparam;
\r
296 final INyARRgbPixelReader reader=this._raster.getRgbPixelReader();
\r
297 final int[] ref_x=this._ref_x;
\r
298 final int[] ref_y=this._ref_y;
\r
299 final int[] pixcel_temp=this._pixcel_temp;
\r
300 //0,2,4,6,8,10,12,14,16,18,20=(11*20)/2=110
\r
302 final int[] freq_count_table=this._freq_count_table;
\r
303 for(int i=0;i<10;i++){
\r
304 freq_count_table[i]=0;
\r
306 final int freq_table[]=this._freq_table;
\r
307 for(int i=0;i<110;i++){
\r
310 final int raster_width=this._raster_size.w;
\r
311 final int raster_height=this._raster_size.h;
\r
314 final double cpara7=cpara[7];
\r
315 final double cpara4=cpara[4];
\r
316 final double cpara1=cpara[1];
\r
317 //基準点から4ピクセルを参照パターンとして抽出
\r
318 for(int i=0;i<FREQ_SAMPLE_NUM;i++){
\r
321 final double cp6_0=cpara[6]*cx0;
\r
322 final double cpx0_0=cpara[0]*cx0+cpara[2];
\r
323 final double cpx3_0=cpara[3]*cx0+cpara[5];
\r
326 for(int i2=0;i2<FRQ_POINTS;i2++)
\r
328 int cy=1+i2*FRQ_STEP+FRQ_EDGE;
\r
330 final double d=cp6_0+cpara7*cy+1.0;
\r
331 final int x=(int)((cpx0_0+cpara1*cy)/d);
\r
332 final int y=(int)((cpx3_0+cpara4*cy)/d);
\r
333 if(x<0||y<0||x>=raster_width||y>=raster_height)
\r
342 //ピクセルを取得(入力画像を多様化するならここを調整すること)
\r
343 reader.getPixelSet(ref_x,ref_y,FRQ_POINTS,pixcel_temp);
\r
345 final int freq_t=getFreqInfo(pixcel_temp,i_th_h,i_th_l,o_edge_index);
\r
347 if(freq_t<MIN_FREQ || freq_t>MAX_FREQ){
\r
351 if(!checkFreqWidth(o_edge_index,freq_t)){
\r
355 freq_count_table[freq_t]++;
\r
356 final int table_st=(freq_t-1)*freq_t;
\r
357 for(int i2=0;i2<freq_t*2;i2++){
\r
358 freq_table[table_st+i2]+=o_edge_index[i2];
\r
361 return getMaxFreq(freq_count_table,freq_table,o_edge_index);
\r
365 * デバックすんだらstaticにしておk
\r
369 * @param o_edge_index
\r
372 private static int getFreqInfo(int[] i_pixcels,int i_th_h,int i_th_l,int[] o_edge_index)
\r
378 while(i<FRQ_POINTS){
\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
385 o_edge_index[frq_l2h+frq_h2l]=i;
\r
393 while(i<FRQ_POINTS){
\r
394 final int index=i*3;
\r
395 final int pix=(i_pixcels[index+0]+i_pixcels[index+1]+i_pixcels[index+2])/3;
\r
398 o_edge_index[frq_l2h+frq_h2l]=i;
\r
406 return frq_l2h==frq_h2l?frq_l2h:-1;
\r
409 private final static int THRESHOLD_EDGE=10;
\r
410 private final static int THRESHOLD_STEP=2;
\r
411 private final static int THRESHOLD_WIDTH=10;
\r
412 private final static int THRESHOLD_PIXEL=THRESHOLD_WIDTH/THRESHOLD_STEP;
\r
413 private final static int THRESHOLD_SAMPLE=THRESHOLD_PIXEL*THRESHOLD_PIXEL;
\r
414 private final static int THRESHOLD_SAMPLE_LT=THRESHOLD_EDGE;
\r
415 private final static int THRESHOLD_SAMPLE_RB=100-THRESHOLD_WIDTH-THRESHOLD_EDGE;
\r
417 public static class TThreshold{
\r
432 * ピクセル配列の上位、下位の4ピクセルのピクセル値平均を求めます。
\r
433 * この関数は、(4/i_pixcel.length)の領域を占有するPtail法で双方向の閾値を求めることになります。
\r
438 private void getPtailHighAndLow(int[] i_pixcel,THighAndLow i_out)
\r
440 int h3,h2,h1,h0,l3,l2,l1,l0;
\r
441 h3=h2=h1=h0=l3=l2=l1=l0=i_pixcel[0];
\r
443 for(int i=i_pixcel.length-1;i>=1;i--){
\r
444 final int pix=i_pixcel[i];
\r
488 i_out.l=(l0+l1+l2+l3)/4;
\r
489 i_out.h=(h0+h1+h2+h3)/4;
\r
492 private THighAndLow __detectThresholdValue_hl=new THighAndLow();
\r
493 private NyARIntPoint2d __detectThresholdValue_tpt=new NyARIntPoint2d();
\r
494 private int[] _th_pixels=new int[THRESHOLD_SAMPLE*4];
\r
496 * 指定した場所のピクセル値を調査して、閾値を計算して返します。
\r
501 * @throws NyARException
\r
503 public void detectThresholdValue(INyARRgbPixelReader i_reader,int i_x,int i_y,TThreshold o_threshold)throws NyARException
\r
505 final int[] th_pixels=this._th_pixels;
\r
507 //左上のピックアップ領域からピクセルを得る(00-24)
\r
508 rectPixels(THRESHOLD_SAMPLE_LT,THRESHOLD_SAMPLE_LT,THRESHOLD_STEP,THRESHOLD_STEP,THRESHOLD_PIXEL,THRESHOLD_PIXEL,0,th_pixels);
\r
510 //左下のピックアップ領域からピクセルを得る(25-49)
\r
511 rectPixels(THRESHOLD_SAMPLE_LT,THRESHOLD_SAMPLE_RB,THRESHOLD_STEP,THRESHOLD_STEP,THRESHOLD_PIXEL,THRESHOLD_PIXEL,THRESHOLD_SAMPLE,th_pixels);
\r
513 //右上のピックアップ領域からピクセルを得る(50-74)
\r
514 rectPixels(THRESHOLD_SAMPLE_RB,THRESHOLD_SAMPLE_LT,THRESHOLD_STEP,THRESHOLD_STEP,THRESHOLD_PIXEL,THRESHOLD_PIXEL,THRESHOLD_SAMPLE*2,th_pixels);
\r
516 //右下のピックアップ領域からピクセルを得る(75-99)
\r
517 rectPixels(THRESHOLD_SAMPLE_RB,THRESHOLD_SAMPLE_RB,THRESHOLD_STEP,THRESHOLD_STEP,THRESHOLD_PIXEL,THRESHOLD_PIXEL,THRESHOLD_SAMPLE*3,th_pixels);
\r
519 final THighAndLow hl=this.__detectThresholdValue_hl;
\r
521 getPtailHighAndLow(th_pixels,hl);
\r
526 int th=(hl.h+hl.l)/2;
\r
528 int th_sub=(hl.h-hl.l)/5;
\r
531 o_threshold.th_h=th+th_sub;//ヒステリシス付き閾値
\r
532 o_threshold.th_l=th-th_sub;//ヒステリシス付き閾値
\r
535 int lt_x,lt_y,lb_x,lb_y,rt_x,rt_y,rb_x,rb_y;
\r
536 final NyARIntPoint2d tpt=this.__detectThresholdValue_tpt;
\r
538 if(getHighPixelCenter(0,th_pixels,THRESHOLD_PIXEL,THRESHOLD_PIXEL,th,tpt)){
\r
539 lt_x=tpt.x*THRESHOLD_STEP;
\r
540 lt_y=tpt.y*THRESHOLD_STEP;
\r
546 if(getHighPixelCenter(THRESHOLD_SAMPLE*1,th_pixels,THRESHOLD_PIXEL,THRESHOLD_PIXEL,th,tpt)){
\r
547 lb_x=tpt.x*THRESHOLD_STEP;
\r
548 lb_y=tpt.y*THRESHOLD_STEP;
\r
554 if(getHighPixelCenter(THRESHOLD_SAMPLE*2,th_pixels,THRESHOLD_PIXEL,THRESHOLD_PIXEL,th,tpt)){
\r
555 rt_x=tpt.x*THRESHOLD_STEP;
\r
556 rt_y=tpt.y*THRESHOLD_STEP;
\r
562 if(getHighPixelCenter(THRESHOLD_SAMPLE*3,th_pixels,THRESHOLD_PIXEL,THRESHOLD_PIXEL,th,tpt)){
\r
563 rb_x=tpt.x*THRESHOLD_STEP;
\r
564 rb_y=tpt.y*THRESHOLD_STEP;
\r
570 o_threshold.lt_x=(lt_x+lb_x)/2+THRESHOLD_SAMPLE_LT-1;
\r
571 o_threshold.rb_x=(rt_x+rb_x)/2+THRESHOLD_SAMPLE_RB+1;
\r
572 o_threshold.lt_y=(lt_y+rt_y)/2+THRESHOLD_SAMPLE_LT-1;
\r
573 o_threshold.rb_y=(lb_y+rb_y)/2+THRESHOLD_SAMPLE_RB+1;
\r
577 private boolean getHighPixelCenter(int i_st,final int[] i_pixels,int i_width,int i_height,int i_th,NyARIntPoint2d o_point)
\r
582 int number_of_pos=0;
\r
583 for(int i=0;i<i_height;i++){
\r
584 for(int i2=0;i2<i_width;i2++){
\r
585 if(i_pixels[rp++]>i_th){
\r
592 if(number_of_pos>0){
\r
593 pos_x/=number_of_pos;
\r
594 pos_y/=number_of_pos;
\r
602 private int[] __detectDataBitsIndex_freq_index1=new int[FRQ_POINTS];
\r
603 private int[] __detectDataBitsIndex_freq_index2=new int[FRQ_POINTS];
\r
604 private int detectDataBitsIndex(PerspectivePixelReader.TThreshold i_th,double[] o_index_row,double[] o_index_col) throws NyARException
\r
607 final int freq_index1[]=this.__detectDataBitsIndex_freq_index1;
\r
608 final int freq_index2[]=this.__detectDataBitsIndex_freq_index2;
\r
611 int frq_t=getRowFrequency(i_th.lt_y,i_th.th_h,i_th.th_l,freq_index1);
\r
612 int frq_b=getRowFrequency(i_th.rb_y,i_th.th_h,i_th.th_l,freq_index2);
\r
614 if((frq_t<0 && frq_b<0) || frq_t==frq_b){
\r
617 //タイミングパターンからインデクスを作成
\r
627 for(int i=0;i<freq_h+freq_h-1;i++){
\r
628 o_index_row[i*2]=((index[i+1]-index[i])*2/5+index[i])+FRQ_EDGE;
\r
629 o_index_row[i*2+1]=((index[i+1]-index[i])*3/5+index[i])+FRQ_EDGE;
\r
633 final int frq_l=getColFrequency(i_th.lt_x,i_th.th_h,i_th.th_l,freq_index1);
\r
634 final int frq_r=getColFrequency(i_th.rb_x,i_th.th_h,i_th.th_l,freq_index2);
\r
636 if((frq_l<0 && frq_r<0) || frq_l==frq_r){
\r
639 //タイミングパターンからインデクスを作成
\r
648 if(freq_v!=freq_h){
\r
652 for(int i=0;i<freq_v+freq_v-1;i++){
\r
653 final int w=index[i];
\r
654 final int w2=index[i+1]-w;
\r
655 o_index_col[i*2]=((w2)*2/5+w)+FRQ_EDGE;
\r
656 o_index_col[i*2+1]=((w2)*3/5+w)+FRQ_EDGE;
\r
659 if(freq_v>MAX_FREQ){
\r
665 private double[] __readDataBits_index_bit_x=new double[MAX_DATA_BITS*2];
\r
666 private double[] __readDataBits_index_bit_y=new double[MAX_DATA_BITS*2];
\r
668 public boolean readDataBits(PerspectivePixelReader.TThreshold i_th,MarkerPattEncoder o_bitbuffer)throws NyARException
\r
670 final double[] index_x=this.__readDataBits_index_bit_x;
\r
671 final double[] index_y=this.__readDataBits_index_bit_y;
\r
673 final int size=detectDataBitsIndex(i_th,index_x,index_y);
\r
674 final int resolution=size+size-1;
\r
678 if(!o_bitbuffer.initEncoder(size-1)){
\r
682 final double[] cpara=this._cparam;
\r
683 final int[] ref_x=this._ref_x;
\r
684 final int[] ref_y=this._ref_y;
\r
685 final INyARRgbPixelReader reader=this._raster.getRgbPixelReader();
\r
686 final int[] pixcel_temp=this._pixcel_temp;
\r
688 final double cpara_0=cpara[0];
\r
689 final double cpara_1=cpara[1];
\r
690 final double cpara_3=cpara[3];
\r
691 final double cpara_6=cpara[6];
\r
694 final int th=i_th.th;
\r
696 for(int i=0;i<resolution;i++){
\r
697 //1列分のピクセルのインデックス値を計算する。
\r
698 double cy0=1+index_y[i*2+0];
\r
699 double cy1=1+index_y[i*2+1];
\r
700 double cpy0_12=cpara_1*cy0+cpara[2];
\r
701 double cpy0_45=cpara[4]*cy0+cpara[5];
\r
702 double cpy0_7=cpara[7]*cy0+1.0;
\r
703 double cpy1_12=cpara_1*cy1+cpara[2];
\r
704 double cpy1_45=cpara[4]*cy1+cpara[5];
\r
705 double cpy1_7=cpara[7]*cy1+1.0;
\r
708 for(int i2=0;i2<resolution;i2++)
\r
712 double cx0=1+index_x[i2*2+0];
\r
713 double cx1=1+index_x[i2*2+1];
\r
715 double cp6_0=cpara_6*cx0;
\r
716 double cpx0_0=cpara_0*cx0;
\r
717 double cpx3_0=cpara_3*cx0;
\r
719 double cp6_1=cpara_6*cx1;
\r
720 double cpx0_1=cpara_0*cx1;
\r
721 double cpx3_1=cpara_3*cx1;
\r
724 ref_x[pt]=(int)((cpx0_0+cpy0_12)/d);
\r
725 ref_y[pt]=(int)((cpx3_0+cpy0_45)/d);
\r
729 ref_x[pt]=(int)((cpx0_0+cpy1_12)/d);
\r
730 ref_y[pt]=(int)((cpx3_0+cpy1_45)/d);
\r
734 ref_x[pt]=(int)((cpx0_1+cpy0_12)/d);
\r
735 ref_y[pt]=(int)((cpx3_1+cpy0_45)/d);
\r
739 ref_x[pt]=(int)((cpx0_1+cpy1_12)/d);
\r
740 ref_y[pt]=(int)((cpx3_1+cpy1_45)/d);
\r
743 //1行分のピクセルを取得(場合によっては専用アクセサを書いた方がいい)
\r
744 reader.getPixelSet(ref_x,ref_y,resolution*4,pixcel_temp);
\r
745 //グレースケールにしながら、line→mapへの転写
\r
746 for(int i2=0;i2<resolution;i2++){
\r
748 int pixel=( pixcel_temp[index+0]+pixcel_temp[index+1]+pixcel_temp[index+2]+
\r
749 pixcel_temp[index+3]+pixcel_temp[index+4]+pixcel_temp[index+5]+
\r
750 pixcel_temp[index+6]+pixcel_temp[index+7]+pixcel_temp[index+8]+
\r
751 pixcel_temp[index+9]+pixcel_temp[index+10]+pixcel_temp[index+11])/(4*3);
\r
753 o_bitbuffer.setBitByBitIndex(p,pixel>th?0:1);
\r
758 for(int i=0;i<225*4;i++){
\r
759 this.vertex_x[i]=0;
\r
760 this.vertex_y[i]=0;
\r
762 for(int i=0;i<(resolution)*2;i++){
\r
763 for(int i2=0;i2<(resolution)*2;i2++){
\r
764 this.vertex_x[i*(resolution)*2+i2]=(int)index_x[i2];
\r
765 this.vertex_y[i*(resolution)*2+i2]=(int)index_y[i];
\r
771 public boolean setSquare(NyARIntPoint2d[] i_vertex) throws NyARException
\r
773 if (!this._param_gen.getParam(i_vertex,this._cparam)) {
\r
780 class MarkerPattDecoder
\r
782 public void decode(int model,int domain,int mask)
\r
791 class MarkerPattEncoder
\r
793 private final static int[] _bit_table_3={
\r
794 25, 26, 27, 28, 29, 30, 31,
\r
795 48, 9, 10, 11, 12, 13, 32,
\r
796 47, 24, 1, 2, 3, 14, 33,
\r
797 46, 23, 8, 0, 4, 15, 34,
\r
798 45, 22, 7, 6, 5, 16, 35,
\r
799 44, 21, 20, 19, 18, 17, 36,
\r
800 43, 42, 41, 40, 39, 38, 37
\r
802 private final static int[] _bit_table_2={
\r
807 21, 20, 19, 18, 17};
\r
808 private final static int[][] _bit_tables={
\r
809 _bit_table_2,_bit_table_3,null,null,null,null,null,
\r
813 * RECT(1):[1]=(1-8)
\r
814 * RECT(2):[2]=(9-16),[3]=(17-24)
\r
815 * RECT(3):[4]=(25-32),[5]=(33-40),[6]=(41-48)
\r
818 int[] _bits=new int[16];
\r
819 int[] _work=new int[16];
\r
821 public void setBitByBitIndex(int i_index_no,int i_value)
\r
823 assert i_value==0 || i_value==1;
\r
824 final int bit_no=this._bit_table[i_index_no];
\r
826 this._bits[0]=i_value;
\r
828 int bidx=(bit_no-1)/8+1;
\r
829 int sidx=(bit_no-1)%8;
\r
830 this._bits[bidx]=(this._bits[bidx]&(~(0x01<<sidx)))|(i_value<<sidx);
\r
835 public void setBit(int i_bit_no,int i_value)
\r
837 assert i_value==0 || i_value==1;
\r
839 this._bits[0]=i_value;
\r
841 int bidx=(i_bit_no-1)/8+1;
\r
842 int sidx=(i_bit_no-1)%8;
\r
843 this._bits[bidx]=(this._bits[bidx]&(~(0x01<<sidx)))|(i_value<<sidx);
\r
847 public int getBit(int i_bit_no)
\r
850 return this._bits[0];
\r
852 int bidx=(i_bit_no-1)/8+1;
\r
853 int sidx=(i_bit_no-1)%8;
\r
854 return (this._bits[bidx]>>(sidx))&(0x01);
\r
857 public int getModel()
\r
859 return this._model;
\r
861 private static int getControlValue(int i_model,int[] i_data)
\r
866 v=(i_data[2] & 0x0e)>>1;
\r
869 v=(i_data[4] & 0x3e)>>1;
\r
870 return v>=21?v-1:v;
\r
878 public static int getCheckValue(int i_model,int[] i_data)
\r
883 v=(i_data[2] & 0xe0)>>5;
\r
886 v=((i_data[4] & 0x80)>>7) |((i_data[5] & 0x0f)<<1);
\r
895 public boolean initEncoder(int i_model)
\r
897 if(i_model>3 || i_model<2){
\r
898 //Lv4以降に対応する時は、この制限を変える。
\r
901 this._bit_table=_bit_tables[i_model-2];
\r
902 this._model=i_model;
\r
905 private int getDirection()
\r
909 switch(this._model){
\r
912 t=this._bits[2] & 0x1f;
\r
913 r=((this._bits[2] & 0xf0)>>4)|((this._bits[3]&0x01)<<4);
\r
914 b=this._bits[3] & 0x1f;
\r
915 l=((this._bits[3] & 0xf0)>>4)|((this._bits[2]&0x01)<<4);
\r
919 t=this._bits[4] & 0x7f;
\r
920 r=((this._bits[4] & 0xc0)>>6)|((this._bits[5] & 0x1f)<<2);
\r
921 b=((this._bits[5] & 0xf0)>>4)|((this._bits[6] & 0x07)<<4);
\r
922 l=((this._bits[6] & 0xfc)>>2)|((this._bits[4] & 0x01)<<6);
\r
931 return (b!=timing_pat && l!=timing_pat)?2:-2;
\r
932 }else if(l==timing_pat){
\r
933 return (b!=timing_pat && r!=timing_pat)?3:-2;
\r
935 }else if(b==timing_pat){
\r
937 return (t!=timing_pat && l!=timing_pat)?1:-2;
\r
938 }else if(l==timing_pat){
\r
939 return (t!=timing_pat && r!=timing_pat)?0:-2;
\r
945 * 格納しているマーカパターンをエンコードして、マーカデータを返します。
\r
948 * 成功すればマーカの方位を返却します。失敗すると-1を返します。
\r
951 public int encode(NyIdMarkerPattern o_out)
\r
953 final int d=getDirection();
\r
958 getRotatedBits(d,o_out.data);
\r
959 final int model=this._model;
\r
962 int control_bits=getControlValue(model,o_out.data);
\r
963 o_out.check=getCheckValue(model,o_out.data);
\r
964 o_out.ctrl_mask=control_bits%5;
\r
965 o_out.ctrl_domain=control_bits/5;
\r
966 if(o_out.ctrl_domain!=0 || o_out.ctrl_mask!=0){
\r
972 private void getRotatedBits(int i_direction,int[] o_out)
\r
974 int sl=i_direction*2;
\r
978 o_out[0]=this._bits[0];
\r
981 o_out[1]=((w1<<sl)|(w1>>sr))& 0xff;
\r
986 w1=this._bits[2]|(this._bits[3]<<8);
\r
987 w1=(w1<<sl)|(w1>>sr);
\r
988 o_out[2]=w1 & 0xff;
\r
989 o_out[3]=(w1>>8) & 0xff;
\r
998 w1=this._bits[4]|(this._bits[5]<<8)|(this._bits[6]<<16);
\r
999 w1=(w1<<sl)|(w1>>sr);
\r
1000 o_out[4]=w1 & 0xff;
\r
1001 o_out[5]=(w1>>8) & 0xff;
\r
1002 o_out[6]=(w1>>16) & 0xff;
\r
1004 if(this._model<3){
\r
1007 //RECT4(Lv4以降はここの制限を変える)
\r
1008 // shiftLeft(this._bits,7,3,i_direction*8);
\r
1009 // if(this._model<4){
\r
1014 public void shiftLeft(int[] i_pack,int i_start,int i_length,int i_ls)
\r
1016 int[] work=this._work;
\r
1018 final int mod_shift=i_ls%8;
\r
1019 for(int i=i_length-1;i>=1;i--){
\r
1020 work[i]=(i_pack[i+i_start]<<mod_shift)|(0xff&(i_pack[i+i_start-1]>>(8-mod_shift)));
\r
1022 work[0]=(i_pack[i_start]<<mod_shift)|(0xff&(i_pack[i_start+i_length-1]>>(8-mod_shift)));
\r
1024 final int byte_shift=(i_ls/8)%i_length;
\r
1025 for(int i=i_length-1;i>=0;i--){
\r
1026 i_pack[(byte_shift+i)%i_length+i_start]=0xff & work[i];
\r
1032 * ラスタ画像の任意矩形から、NyARIdMarkerDataを抽出します。
\r
1035 public class NyIdMarkerPickup
\r
1037 private PerspectivePixelReader _perspective_reader;
\r
1038 private final PerspectivePixelReader.TThreshold __pickFromRaster_th=new PerspectivePixelReader.TThreshold();
\r
1039 private final MarkerPattEncoder __pickFromRaster_encoder=new MarkerPattEncoder();
\r
1042 public NyIdMarkerPickup()
\r
1044 this._perspective_reader=new PerspectivePixelReader();
\r
1048 * i_imageから、idマーカを読みだします。
\r
1049 * o_dataにはマーカデータ、o_paramにはまーかのパラメータを返却します。
\r
1055 * @throws NyARException
\r
1057 public boolean pickFromRaster(INyARRgbRaster image, NyARSquare i_square,NyIdMarkerPattern o_data,NyIdMarkerParam o_param)throws NyARException
\r
1059 this._perspective_reader.setSourceRaster(image);
\r
1062 if(!this._perspective_reader.setSourceSquare(i_square.imvertex)){
\r
1066 final INyARRgbPixelReader reader=image.getRgbPixelReader();
\r
1069 final PerspectivePixelReader.TThreshold th=this.__pickFromRaster_th;
\r
1070 final MarkerPattEncoder encoder=this.__pickFromRaster_encoder;
\r
1072 this._perspective_reader.detectThresholdValue(reader,10,10,th);
\r
1074 if(!this._perspective_reader.readDataBits(th, encoder)){
\r
1077 final int d=encoder.encode(o_data);
\r
1081 o_param.direction=d;
\r
1082 o_param.threshold=th.th;
\r