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.types.*;
\r
31 import jp.nyatla.nyartoolkit.core.utils.*;
\r
40 * NyARColorPatt_NyIdMarkerがラスタからPerspective変換して読みだすためのクラス
\r
43 final class PerspectivePixelReader
\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
50 public PerspectivePixelReader()
\r
55 public boolean setSourceSquare(NyARIntPoint2d[] i_vertex)throws NyARException
\r
57 return this._param_gen.getParam(READ_RESOLUTION,READ_RESOLUTION,i_vertex, this._cparam);
\r
59 public boolean setSourceSquare(NyARDoublePoint2d[] i_vertex)throws NyARException
\r
61 return this._param_gen.getParam(READ_RESOLUTION,READ_RESOLUTION,i_vertex, this._cparam);
\r
72 * o_pixelへの格納場所の先頭インデクス
\r
74 * @throws NyARException
\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
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
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
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
97 for(int i2=0;i2<i_width;i2++)
\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
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
116 o_pixel[out_index]=(pixcel_temp[index+0]+pixcel_temp[index+1]+pixcel_temp[index+2])/3;
\r
123 * i_freqにあるゼロクロス点の周期が、等間隔か調べます。
\r
124 * 次段半周期が、前段の80%より大きく、120%未満であるものを、等間隔周期であるとみなします。
\r
128 private static boolean checkFreqWidth(int[] i_freq,int i_width)
\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
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
148 * 見つかれば0以上、密辛ければ0未満
\r
150 private static int getMaxFreq(int[] i_freq_count_table,int[] i_freq_table,int[] o_freq_table)
\r
155 for(int i=0;i<MAX_FREQ;i++){
\r
156 if(max<i_freq_count_table[i]){
\r
158 max=i_freq_count_table[i];
\r
165 final int st=(index-1)*index;
\r
166 for(int i=0;i<index*2;i++)
\r
168 o_freq_table[i]=i_freq_table[st+i]*FRQ_STEP/max;
\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
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
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
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
194 * i_y1行目とi_y2行目を平均して、タイミングパターンの周波数を得ます。
\r
195 * LHLを1周期として、たとえばLHLHLの場合は2を返します。LHLHやHLHL等の始端と終端のレベルが異なるパターンを
\r
202 * @param o_edge_index
\r
203 * 検出したエッジ位置(H->L,L->H)のインデクスを受け取る配列です。
\r
204 * [FRQ_POINTS]以上の配列を指定してください。
\r
206 * @throws NyARException
\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
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
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
222 for(int i=0;i<110;i++){
\r
225 final int raster_width=i_raster_size.w;
\r
226 final int raster_height=i_raster_size.h;
\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
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
241 for(int i2=0;i2<FRQ_POINTS;i2++)
\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
256 //ピクセルを取得(入力画像を多様化するならここから先を調整すること)
\r
257 i_reader.getPixelSet(ref_x,ref_y,FRQ_POINTS,pixcel_temp);
\r
259 //o_edge_indexを一時的に破壊して調査する
\r
260 final int freq_t=getFreqInfo(pixcel_temp,i_th_h,i_th_l,o_edge_index);
\r
263 if(freq_t<MIN_FREQ || freq_t>MAX_FREQ){
\r
267 if(!checkFreqWidth(o_edge_index,freq_t)){
\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
277 return getMaxFreq(freq_count_table,freq_table,o_edge_index);
\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
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
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
293 final int[] freq_table=this._freq_table;
\r
294 for(int i=0;i<110;i++){
\r
297 final int raster_width=i_raster_size.w;
\r
298 final int raster_height=i_raster_size.h;
\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
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
313 for(int i2=0;i2<FRQ_POINTS;i2++)
\r
315 int cy=1+i2*FRQ_STEP+FRQ_EDGE;
\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
329 //ピクセルを取得(入力画像を多様化するならここを調整すること)
\r
330 i_reader.getPixelSet(ref_x,ref_y,FRQ_POINTS,pixcel_temp);
\r
332 final int freq_t=getFreqInfo(pixcel_temp,i_th_h,i_th_l,o_edge_index);
\r
334 if(freq_t<MIN_FREQ || freq_t>MAX_FREQ){
\r
338 if(!checkFreqWidth(o_edge_index,freq_t)){
\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
348 return getMaxFreq(freq_count_table,freq_table,o_edge_index);
\r
352 * デバックすんだらstaticにしておk
\r
356 * @param o_edge_index
\r
359 private static int getFreqInfo(int[] i_pixcels,int i_th_h,int i_th_l,int[] o_edge_index)
\r
365 while(i<FRQ_POINTS){
\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
372 o_edge_index[frq_l2h+frq_h2l]=i;
\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 return frq_l2h==frq_h2l?frq_l2h:-1;
\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
404 public static class TThreshold{
\r
419 * ピクセル配列の上位、下位の4ピクセルのピクセル値平均を求めます。
\r
420 * この関数は、(4/i_pixcel.length)の領域を占有するPtail法で双方向の閾値を求めることになります。
\r
425 private void getPtailHighAndLow(int[] i_pixcel,THighAndLow i_out)
\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
430 for(int i=i_pixcel.length-1;i>=1;i--){
\r
431 final int pix=i_pixcel[i];
\r
475 i_out.l=(l0+l1+l2+l3)/4;
\r
476 i_out.h=(h0+h1+h2+h3)/4;
\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
483 * 指定した場所のピクセル値を調査して、閾値を計算して返します。
\r
488 * @throws NyARException
\r
490 public void detectThresholdValue(INyARRgbPixelReader i_reader,NyARIntSize i_raster_size,TThreshold o_threshold)throws NyARException
\r
492 final int[] th_pixels=this._th_pixels;
\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
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
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
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
506 final THighAndLow hl=this.__detectThresholdValue_hl;
\r
508 getPtailHighAndLow(th_pixels,hl);
\r
513 int th=(hl.h+hl.l)/2;
\r
515 int th_sub=(hl.h-hl.l)/5;
\r
518 o_threshold.th_h=th+th_sub;//ヒステリシス付き閾値
\r
519 o_threshold.th_l=th-th_sub;//ヒステリシス付き閾値
\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
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
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
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
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
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
564 private boolean getHighPixelCenter(int i_st,int[] i_pixels,int i_width,int i_height,int i_th,NyARIntPoint2d o_point)
\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
579 if(number_of_pos>0){
\r
580 pos_x/=number_of_pos;
\r
581 pos_y/=number_of_pos;
\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
594 final int[] freq_index1=this.__detectDataBitsIndex_freq_index1;
\r
595 final int[] freq_index2=this.__detectDataBitsIndex_freq_index2;
\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
600 if((frq_t<0 && frq_b<0) || frq_t==frq_b){
\r
603 //タイミングパターンからインデクスを作成
\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
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
622 if((frq_l<0 && frq_r<0) || frq_l==frq_r){
\r
625 //タイミングパターンからインデクスを作成
\r
634 if(freq_v!=freq_h){
\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
645 if(freq_v>MAX_FREQ){
\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
654 public boolean readDataBits(INyARRgbPixelReader i_reader,NyARIntSize i_raster_size,PerspectivePixelReader.TThreshold i_th,MarkerPattEncoder o_bitbuffer)throws NyARException
\r
656 final int raster_width=i_raster_size.w;
\r
657 final int raster_height=i_raster_size.h;
\r
659 final double[] index_x=this.__readDataBits_index_bit_x;
\r
660 final double[] index_y=this.__readDataBits_index_bit_y;
\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
669 if(!o_bitbuffer.initEncoder(size-1)){
\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
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
684 final int th=i_th.th;
\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
698 for(int i2=0;i2<resolution;i2++)
\r
702 double cx0=1+index_x[i2*2+0];
\r
703 double cx1=1+index_x[i2*2+1];
\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
709 double cp6_1=cpara_6*cx1;
\r
710 double cpx0_1=cpara_0*cx1;
\r
711 double cpx3_1=cpara_3*cx1;
\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
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
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
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
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
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
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
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
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
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
763 o_bitbuffer.setBitByBitIndex(p,pixel>th?0:1);
\r
769 public boolean setSquare(NyARIntPoint2d[] i_vertex) throws NyARException
\r
771 if (!this._param_gen.getParam(READ_RESOLUTION,READ_RESOLUTION,i_vertex,this._cparam)) {
\r
778 class MarkerPattDecoder
\r
780 public void decode(int model,int domain,int mask)
\r
789 class MarkerPattEncoder
\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
800 private static final int[] _bit_table_2={
\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
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
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
821 assert i_value==0 || i_value==1;
\r
822 final int bit_no=this._bit_table[i_index_no];
\r
824 this._bits[0]=i_value;
\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
833 public void setBit(int i_bit_no,int i_value)
\r
835 assert i_value==0 || i_value==1;
\r
837 this._bits[0]=i_value;
\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
845 public int getBit(int i_bit_no)
\r
848 return this._bits[0];
\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
855 public int getModel()
\r
857 return this._model;
\r
859 private static int getControlValue(int i_model,int[] i_data)
\r
864 v=(i_data[2] & 0x0e)>>1;
\r
867 v=(i_data[4] & 0x3e)>>1;
\r
868 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
897 public boolean initEncoder(int i_model)
\r
899 if(i_model>3 || i_model<2){
\r
900 //Lv4以降に対応する時は、この制限を変える。
\r
903 this._bit_table=_bit_tables[i_model-2];
\r
904 this._model=i_model;
\r
907 private int getDirection()
\r
911 switch(this._model){
\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
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
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
937 }else if(b==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
947 * 格納しているマーカパターンをエンコードして、マーカデータを返します。
\r
950 * 成功すればマーカの方位を返却します。失敗すると-1を返します。
\r
953 public int encode(NyIdMarkerPattern o_out)
\r
955 final int d=getDirection();
\r
960 getRotatedBits(d,o_out.data);
\r
961 final int model=this._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
974 private void getRotatedBits(int i_direction,int[] o_out)
\r
976 int sl=i_direction*2;
\r
980 o_out[0]=this._bits[0];
\r
983 o_out[1]=((w1<<sl)|(w1>>sr))& 0xff;
\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
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
1006 if(this._model<3){
\r
1009 //RECT4(Lv4以降はここの制限を変える)
\r
1010 // shiftLeft(this._bits,7,3,i_direction*8);
\r
1011 // if(this._model<4){
\r
1016 public void shiftLeft(int[] i_pack,int i_start,int i_length,int i_ls)
\r
1018 int[] work=this._work;
\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
1024 work[0]=(i_pack[i_start]<<mod_shift)|(0xff&(i_pack[i_start+i_length-1]>>(8-mod_shift)));
\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
1034 * ラスタ画像の任意矩形から、NyARIdMarkerDataを抽出します。
\r
1037 public class NyIdMarkerPickup
\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
1044 public NyIdMarkerPickup()
\r
1046 this._perspective_reader=new PerspectivePixelReader();
\r
1050 * imageの4頂点で囲まれた矩形からidマーカを読みだします。
\r
1056 * @throws NyARException
\r
1058 public final boolean pickFromRaster(INyARRgbRaster image, NyARDoublePoint2d[] i_vertex,NyIdMarkerPattern o_data,NyIdMarkerParam o_param)throws NyARException
\r
1061 if(!this._perspective_reader.setSourceSquare(i_vertex)){
\r
1064 return this._pickFromRaster(image,o_data,o_param);
\r
1067 * imageの4頂点で囲まれた矩形からidマーカを読みだします。
\r
1073 * @throws NyARException
\r
1075 public final boolean pickFromRaster(INyARRgbRaster image, NyARIntPoint2d[] i_vertex,NyIdMarkerPattern o_data,NyIdMarkerParam o_param)throws NyARException
\r
1077 if(!this._perspective_reader.setSourceSquare(i_vertex)){
\r
1080 return this._pickFromRaster(image,o_data,o_param);
\r
1084 * i_imageから、idマーカを読みだします。
\r
1085 * o_dataにはマーカデータ、o_paramにはマーカのパラメータを返却します。
\r
1091 * @throws NyARException
\r
1093 private final boolean _pickFromRaster(INyARRgbRaster image, NyIdMarkerPattern o_data,NyIdMarkerParam o_param)throws NyARException
\r
1095 INyARRgbPixelReader reader=image.getRgbPixelReader();
\r
1096 NyARIntSize raster_size=image.getSize();
\r
1098 final PerspectivePixelReader.TThreshold th=this.__pickFromRaster_th;
\r
1099 final MarkerPattEncoder encoder=this.__pickFromRaster_encoder;
\r
1101 this._perspective_reader.detectThresholdValue(reader,raster_size,th);
\r
1103 if(!this._perspective_reader.readDataBits(reader,raster_size,th, encoder)){
\r
1106 final int d=encoder.encode(o_data);
\r
1110 o_param.direction=d;
\r
1111 o_param.threshold=th.th;
\r