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
\r
8 * modify it under the terms of the GNU Lesser General Public License
\r
9 * as published by the Free Software Foundation; either version 3
\r
10 * of the License, or (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 Lesser General Public License for more details
\r
17 * You should have received a copy of the GNU Lesser General Public
\r
18 * License 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 class PerspectivePixelReader
\r
46 private NyARPerspectiveParamGenerator _param_gen=new NyARPerspectiveParamGenerator_O1(1,1,100,100);
\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(i_vertex, this._cparam);
\r
69 * o_pixelへの格納場所の先頭インデクス
\r
71 * @throws NyARException
\r
73 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
75 final double[] cpara=this._cparam;
\r
76 final int[] ref_x=this._ref_x;
\r
77 final int[] ref_y=this._ref_y;
\r
78 final int[] pixcel_temp=this._pixcel_temp;
\r
79 final int raster_width=i_raster_size.w;
\r
80 final int raster_height=i_raster_size.h;
\r
82 int out_index=i_out_st;
\r
83 final double cpara_6=cpara[6];
\r
84 final double cpara_0=cpara[0];
\r
85 final double cpara_3=cpara[3];
\r
87 for(int i=0;i<i_height;i++){
\r
88 //1列分のピクセルのインデックス値を計算する。
\r
89 int cy0=1+i*i_step_y+i_lt_y;
\r
90 double cpy0_12=cpara[1]*cy0+cpara[2];
\r
91 double cpy0_45=cpara[4]*cy0+cpara[5];
\r
92 double cpy0_7=cpara[7]*cy0+1.0;
\r
94 for(int i2=0;i2<i_width;i2++)
\r
96 final int cx0=1+i2*i_step_x+i_lt_x;
\r
97 final double d=cpara_6*cx0+cpy0_7;
\r
98 final int x=(int)((cpara_0*cx0+cpy0_12)/d);
\r
99 final int y=(int)((cpara_3*cx0+cpy0_45)/d);
\r
100 if(x<0||y<0||x>=raster_width||y>=raster_height)
\r
108 //1行分のピクセルを取得(場合によっては専用アクセサを書いた方がいい)
\r
109 i_reader.getPixelSet(ref_x,ref_y,i_width,pixcel_temp);
\r
110 //グレースケールにしながら、line→mapへの転写
\r
111 for(int i2=0;i2<i_width;i2++){
\r
113 o_pixel[out_index]=(pixcel_temp[index+0]+pixcel_temp[index+1]+pixcel_temp[index+2])/3;
\r
120 * i_freqにあるゼロクロス点の周期が、等間隔か調べます。
\r
121 * 次段半周期が、前段の80%より大きく、120%未満であるものを、等間隔周期であるとみなします。
\r
125 private static boolean checkFreqWidth(int[] i_freq,int i_width)
\r
127 int c=i_freq[1]-i_freq[0];
\r
128 final int count=i_width*2-1;
\r
129 for(int i=1;i<count;i++){
\r
130 final int n=i_freq[i+1]-i_freq[i];
\r
131 final int v=n*100/c;
\r
140 * i_freq_count_tableとi_freq_tableの内容を調査し、最も大きな周波数成分を返します。
\r
141 * @param i_freq_count_table
\r
142 * @param i_freq_table
\r
143 * @param o_freq_table
\r
145 * 見つかれば0以上、密辛ければ0未満
\r
147 private static int getMaxFreq(int[] i_freq_count_table,int[] i_freq_table,int[] o_freq_table)
\r
152 for(int i=0;i<MAX_FREQ;i++){
\r
153 if(max<i_freq_count_table[i]){
\r
155 max=i_freq_count_table[i];
\r
162 final int st=(index-1)*index;
\r
163 for(int i=0;i<index*2;i++)
\r
165 o_freq_table[i]=i_freq_table[st+i]*FRQ_STEP/max;
\r
171 //タイミングパターン用のパラメタ(FRQ_POINTS*FRQ_STEPが100を超えないようにすること)
\r
172 private static final int FRQ_EDGE=5;
\r
173 private static final int FRQ_STEP=2;
\r
174 private static final int FRQ_POINTS=(100-(FRQ_EDGE*2))/FRQ_STEP;
\r
177 private static final int MIN_FREQ=3;
\r
178 private static final int MAX_FREQ=10;
\r
179 private static final int FREQ_SAMPLE_NUM=4;
\r
180 private static final int MAX_DATA_BITS=MAX_FREQ+MAX_FREQ-1;
\r
182 private final int[] _ref_x=new int[108];
\r
183 private final int[] _ref_y=new int[108];
\r
184 //(model+1)*4*3とTHRESHOLD_PIXEL*3のどちらか大きい方
\r
185 private int[] _pixcel_temp=new int[108*3];
\r
187 private final int[] _freq_count_table=new int[MAX_FREQ];
\r
188 private final int[] _freq_table=new int[(MAX_FREQ*2-1)*MAX_FREQ*2/2];
\r
191 * i_y1行目とi_y2行目を平均して、タイミングパターンの周波数を得ます。
\r
192 * LHLを1周期として、たとえばLHLHLの場合は2を返します。LHLHやHLHL等の始端と終端のレベルが異なるパターンを
\r
199 * @param o_edge_index
\r
200 * 検出したエッジ位置(H->L,L->H)のインデクスを受け取る配列です。
\r
201 * [FRQ_POINTS]以上の配列を指定してください。
\r
203 * @throws NyARException
\r
205 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
208 final int[] freq_count_table=this._freq_count_table;
\r
209 //0,2,4,6,8,10,12,14,16,18,20の要素を持つ配列
\r
210 final int freq_table[]=this._freq_table;
\r
212 final double[] cpara=this._cparam;
\r
213 // final INyARRgbPixelReader reader=this._raster.getRgbPixelReader();
\r
214 final int[] ref_x=this._ref_x;
\r
215 final int[] ref_y=this._ref_y;
\r
216 final int[] pixcel_temp=this._pixcel_temp;
\r
217 for(int i=0;i<10;i++){
\r
218 freq_count_table[i]=0;
\r
220 for(int i=0;i<110;i++){
\r
223 final int raster_width=i_raster_size.w;
\r
224 final int raster_height=i_raster_size.h;
\r
226 final double cpara_0=cpara[0];
\r
227 final double cpara_3=cpara[3];
\r
228 final double cpara_6=cpara[6];
\r
230 //10-20ピクセル目からタイミングパターンを検出
\r
231 for(int i=0;i<FREQ_SAMPLE_NUM;i++){
\r
232 //2行分のピクセルインデックスを計算
\r
233 final double cy0=1+i_y1+i;
\r
234 final double cpy0_12=cpara[1]*cy0+cpara[2];
\r
235 final double cpy0_45=cpara[4]*cy0+cpara[5];
\r
236 final double cpy0_7=cpara[7]*cy0+1.0;
\r
239 for(int i2=0;i2<FRQ_POINTS;i2++)
\r
241 final double cx0=1+i2*FRQ_STEP+FRQ_EDGE;
\r
242 final double d=(cpara_6*cx0)+cpy0_7;
\r
243 final int x=(int)((cpara_0*cx0+cpy0_12)/d);
\r
244 final int y=(int)((cpara_3*cx0+cpy0_45)/d);
\r
245 if(x<0||y<0||x>=raster_width||y>=raster_height)
\r
254 //ピクセルを取得(入力画像を多様化するならここから先を調整すること)
\r
255 i_reader.getPixelSet(ref_x,ref_y,FRQ_POINTS,pixcel_temp);
\r
257 //o_edge_indexを一時的に破壊して調査する
\r
258 final int freq_t=getFreqInfo(pixcel_temp,i_th_h,i_th_l,o_edge_index);
\r
261 if(freq_t<MIN_FREQ || freq_t>MAX_FREQ){
\r
265 if(!checkFreqWidth(o_edge_index,freq_t)){
\r
269 freq_count_table[freq_t]++;
\r
270 final int table_st=(freq_t-1)*freq_t;
\r
271 for(int i2=0;i2<freq_t*2;i2++){
\r
272 freq_table[table_st+i2]+=o_edge_index[i2];
\r
275 return getMaxFreq(freq_count_table,freq_table,o_edge_index);
\r
278 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
280 final double[] cpara=this._cparam;
\r
281 // final INyARRgbPixelReader reader=this._raster.getRgbPixelReader();
\r
282 final int[] ref_x=this._ref_x;
\r
283 final int[] ref_y=this._ref_y;
\r
284 final int[] pixcel_temp=this._pixcel_temp;
\r
285 //0,2,4,6,8,10,12,14,16,18,20=(11*20)/2=110
\r
287 final int[] freq_count_table=this._freq_count_table;
\r
288 for(int i=0;i<10;i++){
\r
289 freq_count_table[i]=0;
\r
291 final int[] freq_table=this._freq_table;
\r
292 for(int i=0;i<110;i++){
\r
295 final int raster_width=i_raster_size.w;
\r
296 final int raster_height=i_raster_size.h;
\r
299 final double cpara7=cpara[7];
\r
300 final double cpara4=cpara[4];
\r
301 final double cpara1=cpara[1];
\r
302 //基準点から4ピクセルを参照パターンとして抽出
\r
303 for(int i=0;i<FREQ_SAMPLE_NUM;i++){
\r
306 final double cp6_0=cpara[6]*cx0;
\r
307 final double cpx0_0=cpara[0]*cx0+cpara[2];
\r
308 final double cpx3_0=cpara[3]*cx0+cpara[5];
\r
311 for(int i2=0;i2<FRQ_POINTS;i2++)
\r
313 int cy=1+i2*FRQ_STEP+FRQ_EDGE;
\r
315 final double d=cp6_0+cpara7*cy+1.0;
\r
316 final int x=(int)((cpx0_0+cpara1*cy)/d);
\r
317 final int y=(int)((cpx3_0+cpara4*cy)/d);
\r
318 if(x<0||y<0||x>=raster_width||y>=raster_height)
\r
327 //ピクセルを取得(入力画像を多様化するならここを調整すること)
\r
328 i_reader.getPixelSet(ref_x,ref_y,FRQ_POINTS,pixcel_temp);
\r
330 final int freq_t=getFreqInfo(pixcel_temp,i_th_h,i_th_l,o_edge_index);
\r
332 if(freq_t<MIN_FREQ || freq_t>MAX_FREQ){
\r
336 if(!checkFreqWidth(o_edge_index,freq_t)){
\r
340 freq_count_table[freq_t]++;
\r
341 final int table_st=(freq_t-1)*freq_t;
\r
342 for(int i2=0;i2<freq_t*2;i2++){
\r
343 freq_table[table_st+i2]+=o_edge_index[i2];
\r
346 return getMaxFreq(freq_count_table,freq_table,o_edge_index);
\r
350 * デバックすんだらstaticにしておk
\r
354 * @param o_edge_index
\r
357 private static int getFreqInfo(int[] i_pixcels,int i_th_h,int i_th_l,int[] o_edge_index)
\r
363 while(i<FRQ_POINTS){
\r
365 while(i<FRQ_POINTS){
\r
366 final int index=i*3;
\r
367 final int pix=(i_pixcels[index+0]+i_pixcels[index+1]+i_pixcels[index+2])/3;
\r
370 o_edge_index[frq_l2h+frq_h2l]=i;
\r
378 while(i<FRQ_POINTS){
\r
379 final int index=i*3;
\r
380 final int pix=(i_pixcels[index+0]+i_pixcels[index+1]+i_pixcels[index+2])/3;
\r
383 o_edge_index[frq_l2h+frq_h2l]=i;
\r
391 return frq_l2h==frq_h2l?frq_l2h:-1;
\r
394 private final static int THRESHOLD_EDGE=10;
\r
395 private final static int THRESHOLD_STEP=2;
\r
396 private final static int THRESHOLD_WIDTH=10;
\r
397 private final static int THRESHOLD_PIXEL=THRESHOLD_WIDTH/THRESHOLD_STEP;
\r
398 private final static int THRESHOLD_SAMPLE=THRESHOLD_PIXEL*THRESHOLD_PIXEL;
\r
399 private final static int THRESHOLD_SAMPLE_LT=THRESHOLD_EDGE;
\r
400 private final static int THRESHOLD_SAMPLE_RB=100-THRESHOLD_WIDTH-THRESHOLD_EDGE;
\r
402 public static class TThreshold{
\r
417 * ピクセル配列の上位、下位の4ピクセルのピクセル値平均を求めます。
\r
418 * この関数は、(4/i_pixcel.length)の領域を占有するPtail法で双方向の閾値を求めることになります。
\r
423 private void getPtailHighAndLow(int[] i_pixcel,THighAndLow i_out)
\r
425 int h3,h2,h1,h0,l3,l2,l1,l0;
\r
426 h3=h2=h1=h0=l3=l2=l1=l0=i_pixcel[0];
\r
428 for(int i=i_pixcel.length-1;i>=1;i--){
\r
429 final int pix=i_pixcel[i];
\r
473 i_out.l=(l0+l1+l2+l3)/4;
\r
474 i_out.h=(h0+h1+h2+h3)/4;
\r
477 private THighAndLow __detectThresholdValue_hl=new THighAndLow();
\r
478 private NyARIntPoint2d __detectThresholdValue_tpt=new NyARIntPoint2d();
\r
479 private int[] _th_pixels=new int[THRESHOLD_SAMPLE*4];
\r
481 * 指定した場所のピクセル値を調査して、閾値を計算して返します。
\r
486 * @throws NyARException
\r
488 public void detectThresholdValue(INyARRgbPixelReader i_reader,NyARIntSize i_raster_size,TThreshold o_threshold)throws NyARException
\r
490 final int[] th_pixels=this._th_pixels;
\r
492 //左上のピックアップ領域からピクセルを得る(00-24)
\r
493 rectPixels(i_reader,i_raster_size,THRESHOLD_SAMPLE_LT,THRESHOLD_SAMPLE_LT,THRESHOLD_STEP,THRESHOLD_STEP,THRESHOLD_PIXEL,THRESHOLD_PIXEL,0,th_pixels);
\r
495 //左下のピックアップ領域からピクセルを得る(25-49)
\r
496 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
498 //右上のピックアップ領域からピクセルを得る(50-74)
\r
499 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
501 //右下のピックアップ領域からピクセルを得る(75-99)
\r
502 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
504 final THighAndLow hl=this.__detectThresholdValue_hl;
\r
506 getPtailHighAndLow(th_pixels,hl);
\r
511 int th=(hl.h+hl.l)/2;
\r
513 int th_sub=(hl.h-hl.l)/5;
\r
516 o_threshold.th_h=th+th_sub;//ヒステリシス付き閾値
\r
517 o_threshold.th_l=th-th_sub;//ヒステリシス付き閾値
\r
520 int lt_x,lt_y,lb_x,lb_y,rt_x,rt_y,rb_x,rb_y;
\r
521 final NyARIntPoint2d tpt=this.__detectThresholdValue_tpt;
\r
523 if(getHighPixelCenter(0,th_pixels,THRESHOLD_PIXEL,THRESHOLD_PIXEL,th,tpt)){
\r
524 lt_x=tpt.x*THRESHOLD_STEP;
\r
525 lt_y=tpt.y*THRESHOLD_STEP;
\r
531 if(getHighPixelCenter(THRESHOLD_SAMPLE*1,th_pixels,THRESHOLD_PIXEL,THRESHOLD_PIXEL,th,tpt)){
\r
532 lb_x=tpt.x*THRESHOLD_STEP;
\r
533 lb_y=tpt.y*THRESHOLD_STEP;
\r
539 if(getHighPixelCenter(THRESHOLD_SAMPLE*2,th_pixels,THRESHOLD_PIXEL,THRESHOLD_PIXEL,th,tpt)){
\r
540 rt_x=tpt.x*THRESHOLD_STEP;
\r
541 rt_y=tpt.y*THRESHOLD_STEP;
\r
547 if(getHighPixelCenter(THRESHOLD_SAMPLE*3,th_pixels,THRESHOLD_PIXEL,THRESHOLD_PIXEL,th,tpt)){
\r
548 rb_x=tpt.x*THRESHOLD_STEP;
\r
549 rb_y=tpt.y*THRESHOLD_STEP;
\r
555 o_threshold.lt_x=(lt_x+lb_x)/2+THRESHOLD_SAMPLE_LT-1;
\r
556 o_threshold.rb_x=(rt_x+rb_x)/2+THRESHOLD_SAMPLE_RB+1;
\r
557 o_threshold.lt_y=(lt_y+rt_y)/2+THRESHOLD_SAMPLE_LT-1;
\r
558 o_threshold.rb_y=(lb_y+rb_y)/2+THRESHOLD_SAMPLE_RB+1;
\r
562 private boolean getHighPixelCenter(int i_st,final int[] i_pixels,int i_width,int i_height,int i_th,NyARIntPoint2d o_point)
\r
567 int number_of_pos=0;
\r
568 for(int i=0;i<i_height;i++){
\r
569 for(int i2=0;i2<i_width;i2++){
\r
570 if(i_pixels[rp++]>i_th){
\r
577 if(number_of_pos>0){
\r
578 pos_x/=number_of_pos;
\r
579 pos_y/=number_of_pos;
\r
587 private int[] __detectDataBitsIndex_freq_index1=new int[FRQ_POINTS];
\r
588 private int[] __detectDataBitsIndex_freq_index2=new int[FRQ_POINTS];
\r
589 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 final int[] freq_index1=this.__detectDataBitsIndex_freq_index1;
\r
593 final int[] freq_index2=this.__detectDataBitsIndex_freq_index2;
\r
595 int frq_t=getRowFrequency(i_reader,i_raster_size,i_th.lt_y,i_th.th_h,i_th.th_l,freq_index1);
\r
596 int frq_b=getRowFrequency(i_reader,i_raster_size,i_th.rb_y,i_th.th_h,i_th.th_l,freq_index2);
\r
598 if((frq_t<0 && frq_b<0) || frq_t==frq_b){
\r
601 //タイミングパターンからインデクスを作成
\r
611 for(int i=0;i<freq_h+freq_h-1;i++){
\r
612 o_index_row[i*2]=((index[i+1]-index[i])*2/5+index[i])+FRQ_EDGE;
\r
613 o_index_row[i*2+1]=((index[i+1]-index[i])*3/5+index[i])+FRQ_EDGE;
\r
617 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
618 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
620 if((frq_l<0 && frq_r<0) || frq_l==frq_r){
\r
623 //タイミングパターンからインデクスを作成
\r
632 if(freq_v!=freq_h){
\r
636 for(int i=0;i<freq_v+freq_v-1;i++){
\r
637 final int w=index[i];
\r
638 final int w2=index[i+1]-w;
\r
639 o_index_col[i*2]=((w2)*2/5+w)+FRQ_EDGE;
\r
640 o_index_col[i*2+1]=((w2)*3/5+w)+FRQ_EDGE;
\r
643 if(freq_v>MAX_FREQ){
\r
649 private double[] __readDataBits_index_bit_x=new double[MAX_DATA_BITS*2];
\r
650 private double[] __readDataBits_index_bit_y=new double[MAX_DATA_BITS*2];
\r
652 public boolean readDataBits(INyARRgbPixelReader i_reader,NyARIntSize i_raster_size,PerspectivePixelReader.TThreshold i_th,MarkerPattEncoder o_bitbuffer)throws NyARException
\r
654 final double[] index_x=this.__readDataBits_index_bit_x;
\r
655 final double[] index_y=this.__readDataBits_index_bit_y;
\r
659 final int size=detectDataBitsIndex(i_reader,i_raster_size,i_th,index_x,index_y);
\r
660 final int resolution=size+size-1;
\r
664 if(!o_bitbuffer.initEncoder(size-1)){
\r
668 final double[] cpara=this._cparam;
\r
669 final int[] ref_x=this._ref_x;
\r
670 final int[] ref_y=this._ref_y;
\r
671 final int[] pixcel_temp=this._pixcel_temp;
\r
673 final double cpara_0=cpara[0];
\r
674 final double cpara_1=cpara[1];
\r
675 final double cpara_3=cpara[3];
\r
676 final double cpara_6=cpara[6];
\r
679 final int th=i_th.th;
\r
681 for(int i=0;i<resolution;i++){
\r
682 //1列分のピクセルのインデックス値を計算する。
\r
683 double cy0=1+index_y[i*2+0];
\r
684 double cy1=1+index_y[i*2+1];
\r
685 double cpy0_12=cpara_1*cy0+cpara[2];
\r
686 double cpy0_45=cpara[4]*cy0+cpara[5];
\r
687 double cpy0_7=cpara[7]*cy0+1.0;
\r
688 double cpy1_12=cpara_1*cy1+cpara[2];
\r
689 double cpy1_45=cpara[4]*cy1+cpara[5];
\r
690 double cpy1_7=cpara[7]*cy1+1.0;
\r
693 for(int i2=0;i2<resolution;i2++)
\r
697 double cx0=1+index_x[i2*2+0];
\r
698 double cx1=1+index_x[i2*2+1];
\r
700 double cp6_0=cpara_6*cx0;
\r
701 double cpx0_0=cpara_0*cx0;
\r
702 double cpx3_0=cpara_3*cx0;
\r
704 double cp6_1=cpara_6*cx1;
\r
705 double cpx0_1=cpara_0*cx1;
\r
706 double cpx3_1=cpara_3*cx1;
\r
709 ref_x[pt]=(int)((cpx0_0+cpy0_12)/d);
\r
710 ref_y[pt]=(int)((cpx3_0+cpy0_45)/d);
\r
714 ref_x[pt]=(int)((cpx0_0+cpy1_12)/d);
\r
715 ref_y[pt]=(int)((cpx3_0+cpy1_45)/d);
\r
719 ref_x[pt]=(int)((cpx0_1+cpy0_12)/d);
\r
720 ref_y[pt]=(int)((cpx3_1+cpy0_45)/d);
\r
724 ref_x[pt]=(int)((cpx0_1+cpy1_12)/d);
\r
725 ref_y[pt]=(int)((cpx3_1+cpy1_45)/d);
\r
728 //1行分のピクセルを取得(場合によっては専用アクセサを書いた方がいい)
\r
729 i_reader.getPixelSet(ref_x,ref_y,resolution*4,pixcel_temp);
\r
730 //グレースケールにしながら、line→mapへの転写
\r
731 for(int i2=0;i2<resolution;i2++){
\r
733 int pixel=( pixcel_temp[index+0]+pixcel_temp[index+1]+pixcel_temp[index+2]+
\r
734 pixcel_temp[index+3]+pixcel_temp[index+4]+pixcel_temp[index+5]+
\r
735 pixcel_temp[index+6]+pixcel_temp[index+7]+pixcel_temp[index+8]+
\r
736 pixcel_temp[index+9]+pixcel_temp[index+10]+pixcel_temp[index+11])/(4*3);
\r
738 o_bitbuffer.setBitByBitIndex(p,pixel>th?0:1);
\r
743 for(int i=0;i<225*4;i++){
\r
744 this.vertex_x[i]=0;
\r
745 this.vertex_y[i]=0;
\r
747 for(int i=0;i<(resolution)*2;i++){
\r
748 for(int i2=0;i2<(resolution)*2;i2++){
\r
749 this.vertex_x[i*(resolution)*2+i2]=(int)index_x[i2];
\r
750 this.vertex_y[i*(resolution)*2+i2]=(int)index_y[i];
\r
756 public boolean setSquare(NyARIntPoint2d[] i_vertex) throws NyARException
\r
758 if (!this._param_gen.getParam(i_vertex,this._cparam)) {
\r
765 class MarkerPattDecoder
\r
767 public void decode(int model,int domain,int mask)
\r
776 class MarkerPattEncoder
\r
778 private final static int[] _bit_table_3={
\r
779 25, 26, 27, 28, 29, 30, 31,
\r
780 48, 9, 10, 11, 12, 13, 32,
\r
781 47, 24, 1, 2, 3, 14, 33,
\r
782 46, 23, 8, 0, 4, 15, 34,
\r
783 45, 22, 7, 6, 5, 16, 35,
\r
784 44, 21, 20, 19, 18, 17, 36,
\r
785 43, 42, 41, 40, 39, 38, 37
\r
787 private final static int[] _bit_table_2={
\r
792 21, 20, 19, 18, 17};
\r
793 private final static int[][] _bit_tables={
\r
794 _bit_table_2,_bit_table_3,null,null,null,null,null,
\r
798 * RECT(1):[1]=(1-8)
\r
799 * RECT(2):[2]=(9-16),[3]=(17-24)
\r
800 * RECT(3):[4]=(25-32),[5]=(33-40),[6]=(41-48)
\r
803 int[] _bits=new int[16];
\r
804 int[] _work=new int[16];
\r
806 public void setBitByBitIndex(int i_index_no,int i_value)
\r
808 assert i_value==0 || i_value==1;
\r
809 final int bit_no=this._bit_table[i_index_no];
\r
811 this._bits[0]=i_value;
\r
813 int bidx=(bit_no-1)/8+1;
\r
814 int sidx=(bit_no-1)%8;
\r
815 this._bits[bidx]=(this._bits[bidx]&(~(0x01<<sidx)))|(i_value<<sidx);
\r
820 public void setBit(int i_bit_no,int i_value)
\r
822 assert i_value==0 || i_value==1;
\r
824 this._bits[0]=i_value;
\r
826 int bidx=(i_bit_no-1)/8+1;
\r
827 int sidx=(i_bit_no-1)%8;
\r
828 this._bits[bidx]=(this._bits[bidx]&(~(0x01<<sidx)))|(i_value<<sidx);
\r
832 public int getBit(int i_bit_no)
\r
835 return this._bits[0];
\r
837 int bidx=(i_bit_no-1)/8+1;
\r
838 int sidx=(i_bit_no-1)%8;
\r
839 return (this._bits[bidx]>>(sidx))&(0x01);
\r
842 public int getModel()
\r
844 return this._model;
\r
846 private static int getControlValue(int i_model,int[] i_data)
\r
851 v=(i_data[2] & 0x0e)>>1;
\r
854 v=(i_data[4] & 0x3e)>>1;
\r
855 return v>=21?v-1:v;
\r
865 public static int getCheckValue(int i_model,int[] i_data)
\r
870 v=(i_data[2] & 0xe0)>>5;
\r
873 v=((i_data[4] & 0x80)>>7) |((i_data[5] & 0x0f)<<1);
\r
884 public boolean initEncoder(int i_model)
\r
886 if(i_model>3 || i_model<2){
\r
887 //Lv4以降に対応する時は、この制限を変える。
\r
890 this._bit_table=_bit_tables[i_model-2];
\r
891 this._model=i_model;
\r
894 private int getDirection()
\r
898 switch(this._model){
\r
901 t=this._bits[2] & 0x1f;
\r
902 r=((this._bits[2] & 0xf0)>>4)|((this._bits[3]&0x01)<<4);
\r
903 b=this._bits[3] & 0x1f;
\r
904 l=((this._bits[3] & 0xf0)>>4)|((this._bits[2]&0x01)<<4);
\r
908 t=this._bits[4] & 0x7f;
\r
909 r=((this._bits[4] & 0xc0)>>6)|((this._bits[5] & 0x1f)<<2);
\r
910 b=((this._bits[5] & 0xf0)>>4)|((this._bits[6] & 0x07)<<4);
\r
911 l=((this._bits[6] & 0xfc)>>2)|((this._bits[4] & 0x01)<<6);
\r
920 return (b!=timing_pat && l!=timing_pat)?2:-2;
\r
921 }else if(l==timing_pat){
\r
922 return (b!=timing_pat && r!=timing_pat)?3:-2;
\r
924 }else if(b==timing_pat){
\r
926 return (t!=timing_pat && l!=timing_pat)?1:-2;
\r
927 }else if(l==timing_pat){
\r
928 return (t!=timing_pat && r!=timing_pat)?0:-2;
\r
934 * 格納しているマーカパターンをエンコードして、マーカデータを返します。
\r
937 * 成功すればマーカの方位を返却します。失敗すると-1を返します。
\r
940 public int encode(NyIdMarkerPattern o_out)
\r
942 final int d=getDirection();
\r
947 getRotatedBits(d,o_out.data);
\r
948 final int model=this._model;
\r
951 int control_bits=getControlValue(model,o_out.data);
\r
952 o_out.check=getCheckValue(model,o_out.data);
\r
953 o_out.ctrl_mask=control_bits%5;
\r
954 o_out.ctrl_domain=control_bits/5;
\r
955 if(o_out.ctrl_domain!=0 || o_out.ctrl_mask!=0){
\r
961 private void getRotatedBits(int i_direction,int[] o_out)
\r
963 int sl=i_direction*2;
\r
967 o_out[0]=this._bits[0];
\r
970 o_out[1]=((w1<<sl)|(w1>>sr))& 0xff;
\r
975 w1=this._bits[2]|(this._bits[3]<<8);
\r
976 w1=(w1<<sl)|(w1>>sr);
\r
977 o_out[2]=w1 & 0xff;
\r
978 o_out[3]=(w1>>8) & 0xff;
\r
987 w1=this._bits[4]|(this._bits[5]<<8)|(this._bits[6]<<16);
\r
988 w1=(w1<<sl)|(w1>>sr);
\r
989 o_out[4]=w1 & 0xff;
\r
990 o_out[5]=(w1>>8) & 0xff;
\r
991 o_out[6]=(w1>>16) & 0xff;
\r
996 //RECT4(Lv4以降はここの制限を変える)
\r
997 // shiftLeft(this._bits,7,3,i_direction*8);
\r
998 // if(this._model<4){
\r
1003 public void shiftLeft(int[] i_pack,int i_start,int i_length,int i_ls)
\r
1005 int[] work=this._work;
\r
1007 final int mod_shift=i_ls%8;
\r
1008 for(int i=i_length-1;i>=1;i--){
\r
1009 work[i]=(i_pack[i+i_start]<<mod_shift)|(0xff&(i_pack[i+i_start-1]>>(8-mod_shift)));
\r
1011 work[0]=(i_pack[i_start]<<mod_shift)|(0xff&(i_pack[i_start+i_length-1]>>(8-mod_shift)));
\r
1013 final int byte_shift=(i_ls/8)%i_length;
\r
1014 for(int i=i_length-1;i>=0;i--){
\r
1015 i_pack[(byte_shift+i)%i_length+i_start]=0xff & work[i];
\r
1021 * ラスタ画像の任意矩形から、NyARIdMarkerDataを抽出します。
\r
1024 public class NyIdMarkerPickup
\r
1026 private PerspectivePixelReader _perspective_reader;
\r
1027 private final PerspectivePixelReader.TThreshold __pickFromRaster_th=new PerspectivePixelReader.TThreshold();
\r
1028 private final MarkerPattEncoder __pickFromRaster_encoder=new MarkerPattEncoder();
\r
1031 public NyIdMarkerPickup()
\r
1033 this._perspective_reader=new PerspectivePixelReader();
\r
1037 * i_imageから、idマーカを読みだします。
\r
1038 * o_dataにはマーカデータ、o_paramにはまーかのパラメータを返却します。
\r
1044 * @throws NyARException
\r
1046 public boolean pickFromRaster(INyARRgbRaster image, NyARSquare i_square,NyIdMarkerPattern o_data,NyIdMarkerParam o_param)throws NyARException
\r
1050 if(!this._perspective_reader.setSourceSquare(i_square.imvertex)){
\r
1054 INyARRgbPixelReader reader=image.getRgbPixelReader();
\r
1055 NyARIntSize raster_size=image.getSize();
\r
1059 final PerspectivePixelReader.TThreshold th=this.__pickFromRaster_th;
\r
1060 final MarkerPattEncoder encoder=this.__pickFromRaster_encoder;
\r
1062 this._perspective_reader.detectThresholdValue(reader,raster_size,th);
\r
1064 if(!this._perspective_reader.readDataBits(reader,raster_size,th, encoder)){
\r
1067 final int d=encoder.encode(o_data);
\r
1071 o_param.direction=d;
\r
1072 o_param.threshold=th.th;
\r