1 package jp.nyatla.nyartoolkit.sandbox.qrcode;
\r
3 import jp.nyatla.nyartoolkit.NyARException;
\r
4 import jp.nyatla.nyartoolkit.core.labeling.artoolkit.NyARLabelingImage;
\r
5 import jp.nyatla.nyartoolkit.core.labeling.artoolkit.NyARLabelingLabel;
\r
6 import jp.nyatla.nyartoolkit.core.labeling.artoolkit.NyARLabelingLabelStack;
\r
7 import jp.nyatla.nyartoolkit.core.labeling.artoolkit.NyARLabeling_ARToolKit;
\r
8 import jp.nyatla.nyartoolkit.core.param.NyARCameraDistortionFactor;
\r
9 import jp.nyatla.nyartoolkit.core.raster.NyARBinRaster;
\r
10 import jp.nyatla.nyartoolkit.core.squaredetect.NyARContourPickup;
\r
11 import jp.nyatla.nyartoolkit.core.squaredetect.NyARSquareContourDetector;
\r
12 import jp.nyatla.nyartoolkit.core.squaredetect.NyARSquare;
\r
13 import jp.nyatla.nyartoolkit.core.squaredetect.NyARSquareStack;
\r
14 import jp.nyatla.nyartoolkit.core.squaredetect.NyARCoord2Linear;
\r
15 import jp.nyatla.nyartoolkit.core.types.*;
\r
17 public class NyARQrCodeDetector extends NyARSquareContourDetector
\r
19 private NyARQrCodeSymbolBinder _binder;
\r
21 private static final int AR_AREA_MAX = 10000;
\r
23 private static final int AR_AREA_MIN = 50;
\r
25 private final int _width;
\r
27 private final int _height;
\r
29 private final NyARLabeling_ARToolKit _labeling;
\r
31 private final NyARLabelingImage _limage;
\r
33 private final NyARCoord2Linear _sqconvertor;
\r
34 private final NyARContourPickup _cpickup=new NyARContourPickup();
\r
37 * 最大i_squre_max個のマーカーを検出するクラスを作成する。
\r
41 public NyARQrCodeDetector(NyARCameraDistortionFactor i_dist_factor_ref, NyARIntSize i_size) throws NyARException
\r
43 this._width = i_size.w;
\r
44 this._height = i_size.h;
\r
45 this._labeling = new NyARLabeling_ARToolKit();
\r
46 this._limage = new NyARLabelingImage(this._width, this._height);
\r
47 this._binder=new NyARQrCodeSymbolBinder(i_dist_factor_ref);
\r
48 this._sqconvertor=new NyARCoord2Linear(i_size,i_dist_factor_ref);
\r
50 // 輪郭の最大長はMAX_COORD_NUMの2倍に制限
\r
51 int number_of_coord = MAX_COORD_NUM* 2;
\r
53 // 輪郭バッファはnumber_of_coordの2倍
\r
54 this._max_coord = number_of_coord;
\r
55 this._xcoord = new int[number_of_coord * 2];
\r
56 this._ycoord = new int[number_of_coord * 2];
\r
60 private final int _max_coord;
\r
62 private final int[] _xcoord;
\r
64 private final int[] _ycoord;
\r
68 * ARMarkerInfo2 *arDetectMarker2( ARInt16 *limage, int label_num, int *label_ref,int *warea, double *wpos, int *wclip,int area_max, int area_min, double
\r
69 * factor, int *marker_num ) 関数の代替品 ラベリング情報からマーカー一覧を作成してo_marker_listを更新します。 関数はo_marker_listに重なりを除外したマーカーリストを作成します。
\r
72 * 解析する2値ラスタイメージを指定します。
\r
73 * @param o_square_stack
\r
75 * @throws NyARException
\r
77 public final void detectMarker(NyARBinRaster i_raster, NyARSquareStack o_square_stack) throws NyARException
\r
79 final NyARLabelingImage limage = this._limage;
\r
84 o_square_stack.clear();
\r
87 this._labeling.labeling(i_raster,limage);
\r
90 final int label_num = limage.getLabelStack().getLength();
\r
91 if (label_num < 1) {
\r
95 final NyARLabelingLabelStack stack = limage.getLabelStack();
\r
99 final NyARLabelingLabel[] labels = stack.getArray();
\r
102 for (i = 0; i < label_num; i++) {
\r
103 // 検査対象内のラベルサイズになるまで無視
\r
104 if (labels[i].area <= AR_AREA_MAX) {
\r
109 final int xsize = this._width;
\r
110 final int ysize = this._height;
\r
111 final int[] xcoord = this._xcoord;
\r
112 final int[] ycoord = this._ycoord;
\r
113 final int coord_max = this._max_coord;
\r
114 final int[] buf = (int[]) limage.getBuffer();
\r
115 final int[] indextable = limage.getIndexArray();
\r
118 NyARLabelingLabel label_pt;
\r
119 NyARSquareStack wk_stack=new NyARSquareStack(10);
\r
122 for (; i < label_num; i++) {
\r
123 label_pt = labels[i];
\r
124 label_area = label_pt.area;
\r
125 // 検査対象サイズよりも小さくなったら終了
\r
126 if (label_area < AR_AREA_MIN) {
\r
129 // クリップ領域が画面の枠に接していれば除外
\r
130 if (label_pt.clip_l == 1 || label_pt.clip_r == xsize - 2) {// if(wclip[i*4+0] == 1 || wclip[i*4+1] ==xsize-2){
\r
133 if (label_pt.clip_t == 1 || label_pt.clip_b == ysize - 2) {// if( wclip[i*4+2] == 1 || wclip[i*4+3] ==ysize-2){
\r
137 if (!hasQrEdgeFeature(buf, indextable, label_pt)) {
\r
141 final int coord_num = _cpickup.getContour(limage,limage.getTopClipTangentX(label_pt),label_pt.clip_t, coord_max, xcoord, ycoord);
\r
142 if (coord_num == coord_max) {
\r
147 final int vertex1 = NyARCoord2Linear.normalizeCoord(xcoord, ycoord, coord_num);
\r
150 NyARSquare square_ptr = o_square_stack.prePush();
\r
151 if(!this._sqconvertor.coordToSquare(xcoord,ycoord,vertex1,coord_num,label_area,square_ptr)){
\r
152 o_square_stack.pop();// 頂点の取得が出来なかったので破棄
\r
157 bindQrcodeEdge(wk_stack,o_square_stack);
\r
165 * @param i_square_stack
\r
167 public void bindQrcodeEdge(NyARSquareStack i_square_stack,NyARSquareStack o_square_stack) throws NyARException
\r
169 NyARSquare[] group=new NyARSquare[3];
\r
170 int number_of_edge=i_square_stack.getLength();
\r
171 if(number_of_edge<3){
\r
174 NyARSquare[] sa=i_square_stack.getArray();
\r
175 for(int i=0;i<number_of_edge-2;i++)
\r
178 for(int i2=i+1;i2<number_of_edge-1;i2++)
\r
181 for(int i3=i2+1;i3<number_of_edge;i3++){
\r
184 NyARSquare new_square=(NyARSquare)o_square_stack.prePush();
\r
185 if(!this._binder.composeSquare(group,new_square)){
\r
186 o_square_stack.pop();
\r
193 private static int MAX_COORD_NUM=(320+240)*2;//サイズの1/2の長方形の編程度が目安(VGAなら(320+240)*2)
\r
196 * QRコードのシンボル特徴を持つラベルであるかを調べる
\r
198 * @param index_table
\r
202 private boolean hasQrEdgeFeature(int[] buf, int[] index_table, NyARLabelingLabel i_label)
\r
206 int i_label_id = i_label.id;
\r
208 final int clip_l = i_label.clip_l;
\r
209 final int clip_b = i_label.clip_b;
\r
210 final int clip_r = i_label.clip_r;
\r
211 final int clip_t = i_label.clip_t;
\r
215 limage_j_ptr = clip_t*this._width;
\r
216 for (int i = clip_l; i <= clip_r; i++) {// for( i = clip[0]; i <=clip[1]; i++, p1++ ) {
\r
217 w = buf[limage_j_ptr+i];
\r
218 if (w > 0 && index_table[w - 1] == i_label_id) {
\r
224 limage_j_ptr = clip_b*this._width;
\r
225 for (int i = clip_r; i >= clip_l; i--) {// for( i = clip[0]; i <=clip[1]; i++, p1++ ) {
\r
226 w = buf[limage_j_ptr+i];
\r
227 if (w > 0 && index_table[w - 1] == i_label_id) {
\r
232 final int cx = (clip_l + clip_r) / 2;
\r
233 final int cy = (clip_t + clip_b) / 2;
\r
234 // 横断チェック(中心から線を引いて、010になるかしらべる)
\r
235 if (!checkDiagonalLine(buf, cx, cy, bx, clip_b)) {
\r
238 if (!checkDiagonalLine(buf, tx, clip_t, cx, cy)) {
\r
245 * シンボルのパターン特徴を調べる関数
\r
246 * 対角線の一部が010になってるか調べる。
\r
255 private boolean checkDiagonalLine(int[] buf, int i_px1, int i_py1, int i_px2, int i_py2)
\r
257 int sub_y = i_py2 - i_py1;
\r
258 int sub_x = i_px2 - i_px1;
\r
261 for (; i < sub_y; i++) {
\r
262 int yp = i_py1 + i;
\r
263 int xp = i_px1 + i * sub_x / sub_y;
\r
264 if (buf[yp*this._width+xp] == 0 && buf[yp*this._width+(xp-1)] == 0 && buf[yp*this._width+(xp+1)] == 0) {
\r
273 for (; i < sub_y; i++) {
\r
274 int yp = i_py1 + i;
\r
275 int xp = i_px1 + i * sub_x / sub_y;
\r
276 if (buf[yp*this._width+xp] != 0 && buf[yp*this._width+(xp-1)] != 0 && buf[yp*this._width+(xp+1)] != 0) {
\r
285 for (; i < sub_y; i++) {
\r
286 int yp = i_py1 + i;
\r
287 int xp = i_px1 + i * sub_x / sub_y;
\r
288 if (buf[yp*this._width+xp] == 0 && buf[yp*this._width+(xp-1)] == 0 && buf[yp*this._width+(xp+1)] == 0) {
\r