1 package jp.nyatla.nyartoolkit.sandbox.qrcode;
\r
3 import jp.nyatla.nyartoolkit.core.*;
\r
4 import jp.nyatla.nyartoolkit.core.squaredetect.NyARSquare;
\r
5 import jp.nyatla.nyartoolkit.core.types.*;
\r
6 import jp.nyatla.nyartoolkit.core.param.*;
\r
8 * QRコードのシンボルを結びつける偉いクラス
\r
10 * 1.3シンボルの位置関係から中間のシンボルを探す。
\r
12 * 3.残りの2シンボル間の最短距離の頂点セットを見つけて、それぞれの内角点を探す
\r
13 * 4.3個の内角点が決まったら、各シンボルごとに外角点(反対側の頂点)を特定する。
\r
14 * 5.対角のシンボルの外角頂点から伸びる線分を合成して、矩形を決める。
\r
15 * 6.矩形が決まったら、方程式を解いて交点を出して、頂点にする。
\r
16 * 7.交点と中央のシンボルの位置関係から、正しい計算が行われたかを判定(まだ実装してない)
\r
19 * この方法は浅い角度でシンボル集合を見たときに、1や3の手順が高い確率で失敗する。
\r
20 * その場合計算が途中で破綻するのでわかる(はず)
\r
21 * 他の方法もあるけど、それはまた今度。
\r
23 public class NyARQrCodeSymbolBinder
\r
25 private NyARCameraDistortionFactor _distfactor;
\r
27 public NyARQrCodeSymbolBinder(NyARCameraDistortionFactor i_ref_distortion)
\r
29 this._distfactor=i_ref_distortion;
\r
33 * 最小の三角形を構成する頂点セットを得る
\r
39 private static void getMinimumTriangleVertex(NyARSquare[] i_sqare,int[] o_vertex_id)
\r
41 //辺の長さが最小になる頂点の組合せを探す
\r
44 int dmax=0x7fffffff;
\r
45 final NyARIntPoint2d[] vertex0=i_sqare[0].imvertex;
\r
46 final NyARIntPoint2d[] vertex1=i_sqare[1].imvertex;
\r
47 final NyARIntPoint2d[] vertex2=i_sqare[2].imvertex;
\r
48 for(int i=0;i<4;i++)
\r
50 for(int i2=0;i2<4;i2++)
\r
52 for(int i3=0;i3<4;i3++){
\r
53 x=vertex0[i].x-vertex2[i3].x;
\r
54 y=vertex0[i].y-vertex2[i3].y;
\r
56 x=vertex1[i2].x-vertex2[i3].x;
\r
57 y=vertex1[i2].y-vertex2[i3].y;
\r
59 x=vertex1[i2].x-vertex0[i].x;
\r
60 y=vertex1[i2].y-vertex0[i].y;
\r
74 * 2矩形の頂点距離が最低の組合せを探す
\r
76 * @param o_vertex_id
\r
78 private static void getMinimumLineVertex(NyARIntPoint2d[] i_sqare0,NyARIntPoint2d[] i_sqare1,int[] o_vertex_id)
\r
80 //辺の長さが最小になる頂点の組合せを探す
\r
83 int dmax=0x7fffffff;
\r
84 for(int i=0;i<4;i++)
\r
86 for(int i2=0;i2<4;i2++)
\r
88 x=i_sqare1[i2].x-i_sqare0[i].x;
\r
89 y=i_sqare1[i2].y-i_sqare0[i].y;
\r
105 private void getSymbolGroupCenter(NyARSquare[] i_sqare,NyARIntPoint2d i_center)
\r
110 for(int i=0;i<3;i++)
\r
112 final NyARIntPoint2d[] sq_ptr=i_sqare[i].imvertex;
\r
129 * @param i_vertex_id
\r
133 private static int getKeySymble(NyARSquare[] i_sqare,NyARIntPoint2d i_center,int[] i_vertex_id)
\r
136 final int cx=i_center.x;
\r
137 final int cy=i_center.y;
\r
138 //前段で探した頂点候補のうち、最も重心に近いものが中心シンボルの内対角点
\r
139 int key_symble_idx=0;
\r
140 int x=i_sqare[0].imvertex[i_vertex_id[0]].x-cx;
\r
141 int y=i_sqare[0].imvertex[i_vertex_id[0]].y-cy;
\r
143 for(int i=1;i<3;i++){
\r
144 x=i_sqare[i].imvertex[i_vertex_id[i]].x-cx;
\r
145 y=i_sqare[i].imvertex[i_vertex_id[i]].y-cy;
\r
146 final int d=x*x+y*y;
\r
152 return key_symble_idx;
\r
154 private NyARDoublePoint2d __bindSquare_ideal_vertex=new NyARDoublePoint2d();
\r
156 * 2つの対角にある矩形から、それらを対角とする矩形を作る。
\r
162 private void bindSquare(NyARSquare i_sq1,int i_lv1,NyARSquare i_sq2,int i_lv2,NyARSquare o_qr_square)
\r
165 o_qr_square.line[0].copyFrom(i_sq1.line[(i_lv1+3)%4]);
\r
166 o_qr_square.line[1].copyFrom(i_sq1.line[(i_lv1+0)%4]);
\r
167 o_qr_square.line[2].copyFrom(i_sq2.line[(i_lv2+3)%4]);
\r
168 o_qr_square.line[3].copyFrom(i_sq2.line[(i_lv2+0)%4]);
\r
170 final NyARDoublePoint2d[] l_sqvertex = o_qr_square.sqvertex;
\r
171 final NyARIntPoint2d[] imvertex_ptr = o_qr_square.imvertex;
\r
173 final NyARLinear[] l_line = o_qr_square.line;
\r
174 final NyARDoublePoint2d ideal_vertex=this.__bindSquare_ideal_vertex;
\r
175 for (int i = 0; i < 4; i++) {
\r
176 final NyARLinear l_line_i = l_line[i];
\r
177 final NyARLinear l_line_2 = l_line[(i + 3) % 4];
\r
178 final double w1 = l_line_2.dy * l_line_i.dx - l_line_i.dy * l_line_2.dx;
\r
182 l_sqvertex[i].x = (l_line_2.dx * l_line_i.c - l_line_i.dx * l_line_2.c) / w1;
\r
183 l_sqvertex[i].y = (l_line_i.dy * l_line_2.c - l_line_2.dy * l_line_i.c) / w1;
\r
184 _distfactor.ideal2Observ(l_sqvertex[i], ideal_vertex);
\r
185 //Ideal→observに変換して、画面上の座標とする。
\r
186 imvertex_ptr[i].x=(int)l_sqvertex[i].x;
\r
187 imvertex_ptr[i].y=(int)l_sqvertex[i].y;
\r
189 // Graphics g=this.bimg.getGraphics();
\r
190 // g.setColor(Color.red);
\r
191 // int[] x=new int[4];
\r
192 // int[] y=new int[4];
\r
193 // for(int i=0;i<4;i++){
\r
194 // x[i]=(int)l_sqvertex[i].x;
\r
195 // y[i]=(int)l_sqvertex[i].y;
\r
197 // g.drawPolygon(x,y,4);
\r
199 //基準点はVertexをそのまま採用
\r
200 //2個の想定点は座標を逆変換して設定
\r
203 * directionはキーシンボルのインデックスでARToolKitの頂点座標じゃないので注意すること。
\r
208 public boolean composeSquare(NyARSquare[] i_sq,NyARSquare o_sq)
\r
210 int[] minimum_triangle_vertex=new int[3];
\r
211 int[] minimum_line_vertex=new int[2];
\r
213 NyARIntPoint2d center=new NyARIntPoint2d();
\r
215 //辺の長さが最小になる頂点の組合せを探す
\r
216 getMinimumTriangleVertex(i_sq,minimum_triangle_vertex);
\r
219 getSymbolGroupCenter(i_sq,center);
\r
221 //キーシンボルのインデクス番号を得る
\r
222 int key_simble_idx=getKeySymble(i_sq,center,minimum_triangle_vertex);
\r
224 //対角シンボルのインデックス番号を決める
\r
225 int symbol_e1_idx=(key_simble_idx+1)%3;
\r
226 int symbol_e2_idx=(key_simble_idx+2)%3;
\r
228 //対角シンボル間で最短距離を取る頂点ペアを取る
\r
229 //(角度を低くするとエラーが出やすい。対角線との類似性を確認する方法のほうがいい。多分)
\r
230 getMinimumLineVertex(i_sq[symbol_e1_idx].imvertex,i_sq[symbol_e2_idx].imvertex,minimum_line_vertex);
\r
233 int lv1=(minimum_line_vertex[0]+2)%4;
\r
234 int lv2=(minimum_line_vertex[1]+2)%4;
\r
235 int kv =(minimum_triangle_vertex[key_simble_idx]+2)%4;
\r
237 bindSquare(i_sq[symbol_e1_idx],lv1,i_sq[symbol_e2_idx],lv2,o_sq);
\r
240 int direction=getDirection(o_sq,i_sq[key_simble_idx].imvertex[kv],center);
\r
244 o_sq.direction=direction;
\r
249 * この関数はあんまり頂点ズレがひどいと失敗する
\r
255 private int getDirection(NyARSquare i_square,NyARIntPoint2d i_vertex,NyARIntPoint2d i_center)
\r
257 //開始点(中央シンボル)までの頂点のシフト数を決める
\r
259 x=i_square.imvertex[0].x-i_vertex.x;
\r
260 y=i_square.imvertex[0].y-i_vertex.y;
\r
262 x=i_square.imvertex[2].x-i_vertex.x;
\r
263 y=i_square.imvertex[2].y-i_vertex.y;
\r
274 //小さい方の対角線が64(8x8)より大きくずれてたら認識ミスとみなす
\r
278 //シンボルがどの象限にあるか確認する
\r
279 x=i_vertex.x=i_center.x;
\r
280 y=i_vertex.y=i_center.y;
\r
283 dir=2;//dir=y<0?1:2;
\r
285 dir=4;//dir=y<0?3:4;
\r
287 return (dir+shift)%4;
\r