/** * コンストラクタです。 * 入力画像のサイズを指定して、インスタンスを生成します。 * @param i_size * 入力画像のサイズ */ public NyARSquareContourDetector_ARToolKit(NyARIntSize i_size) { this._width = i_size.w; this._height = i_size.h; this._labeling = new NyARLabeling_ARToolKit(); this._limage = new NyARLabelingImage(this._width, this._height); // 輪郭の最大長は画面に映りうる最大の長方形サイズ。 int number_of_coord = (this._width + this._height) * 2; // 輪郭バッファは頂点変換をするので、輪郭バッファの2倍取る。 this._coord = new NyARIntCoordinates(number_of_coord); return; }
/** * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。 * 開始点は、輪郭の一部である必要があります。 * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。 * @param i_raster * 輪郭線を抽出するラスタを指定します。 * @param i_entry_x * 輪郭抽出の開始点です。 * @param i_entry_y * 輪郭抽出の開始点です。 * @param o_coord * 輪郭点を格納するオブジェクトを指定します。 * @return * 輪郭線がo_coordの長さを超えた場合、falseを返します。 * @ */ public bool getContour(NyARLabelingImage i_raster, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord) { int[] xdir = _getContour_xdir; // static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1}; int[] ydir = _getContour_ydir; // static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1}; int[] i_buf = (int[])i_raster.getBuffer(); int width = i_raster.getWidth(); int height = i_raster.getHeight(); NyARIntPoint2d[] coord = o_coord.items; int i_array_size = o_coord.items.Length; //クリップ領域の上端に接しているポイントを得る。 int sx = i_entry_x; int sy = i_entry_y; int coord_num = 1; coord[0].x = sx; coord[0].y = sy; int dir = 5; int c = coord[0].x; int r = coord[0].y; for (; ;) { dir = (dir + 5) % 8;//dirの正規化 //ここは頑張ればもっと最適化できると思うよ。 //4隅以外の境界接地の場合に、境界チェックを省略するとかね。 if (c >= 1 && c < width - 1 && r >= 1 && r < height - 1) { for (; ;) {//gotoのエミュレート用のfor文 //境界に接していないとき if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } //8方向全て調べたけどラベルが無いよ? throw new NyARException(); } } else { //境界に接しているとき int i; for (i = 0; i < 8; i++) { int x = c + xdir[dir]; int y = r + ydir[dir]; //境界チェック if (x >= 0 && x < width && y >= 0 && y < height) { if (i_buf[(y) * width + (x)] > 0) { break; } } dir++;//倍長テーブルを参照するので問題なし } if (i == 8) { //8方向全て調べたけどラベルが無いよ? throw new NyARException();// return(-1); } } dir = dir % 8;//dirの正規化 // xcoordとycoordをc,rにも保存 c = c + xdir[dir]; r = r + ydir[dir]; coord[coord_num].x = c; coord[coord_num].y = r; // 終了条件判定 if (c == sx && r == sy) { coord_num++; break; } coord_num++; if (coord_num == i_array_size) { //輪郭が末端に達した return(false); } } o_coord.length = coord_num; return(true); }
/** * この関数は、ラスタから矩形を検出して、自己コールバック関数{@link #onSquareDetect}で通知します。 * 実装クラスでは、矩形検出処理をして、結果を通知する処理を実装してください。 * @param i_raster * 検出元のラスタ画像 * @ */ public void detectMarker(NyARBinRaster i_raster, NyARSquareContourDetector.CbHandler i_cb) { NyARLabelingImage limage = this._limage; // ラベル数が0ならここまで int label_num = this._labeling.labeling(i_raster, this._limage); if (label_num < 1) { return; } NyARLabelingLabelStack stack = limage.getLabelStack(); //ラベルをソートしておく stack.sortByArea(); // NyARLabelingLabel[] labels = stack.getArray(); // デカいラベルを読み飛ばし int i; for (i = 0; i < label_num; i++) { // 検査対象内のラベルサイズになるまで無視 if (labels[i].area <= AR_AREA_MAX) { break; } } int xsize = this._width; int ysize = this._height; NyARIntCoordinates coord = this._coord; int[] mkvertex = this.__detectMarker_mkvertex; NyARLabelOverlapChecker <NyARLabelingLabel> overlap = this._overlap_checker; //重なりチェッカの最大数を設定 overlap.setMaxLabels(label_num); for (; i < label_num; i++) { NyARLabelingLabel label_pt = labels[i]; int label_area = label_pt.area; // 検査対象サイズよりも小さくなったら終了 if (label_area < AR_AREA_MIN) { break; } // クリップ領域が画面の枠に接していれば除外 if (label_pt.clip_l == 1 || label_pt.clip_r == xsize - 2) {// if(wclip[i*4+0] == 1 || wclip[i*4+1] ==xsize-2){ continue; } if (label_pt.clip_t == 1 || label_pt.clip_b == ysize - 2) {// if( wclip[i*4+2] == 1 || wclip[i*4+3] ==ysize-2){ continue; } // 既に検出された矩形との重なりを確認 if (!overlap.check(label_pt)) { // 重なっているようだ。 continue; } // 輪郭を取得 if (!this._cpickup.getContour(limage, limage.getTopClipTangentX(label_pt), label_pt.clip_t, coord)) { continue; } //輪郭線をチェックして、矩形かどうかを判定。矩形ならばmkvertexに取得 if (!this._coord2vertex.getVertexIndexes(coord, label_area, mkvertex)) { // 頂点の取得が出来なかった continue; } //矩形を発見したことをコールバック関数で通知 i_cb.detectMarkerCallback(coord, mkvertex); // 検出済の矩形の属したラベルを重なりチェックに追加する。 overlap.push(label_pt); } return; }
/** * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。 * 開始点は、輪郭の一部である必要があります。 * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。 * @param i_raster * 輪郭線を抽出するラスタを指定します。 * @param i_entry_x * 輪郭抽出の開始点です。 * @param i_entry_y * 輪郭抽出の開始点です。 * @param o_coord * 輪郭点を格納するオブジェクトを指定します。 * @return * 輪郭線がo_coordの長さを超えた場合、falseを返します。 * @ */ public bool getContour(NyARLabelingImage i_raster, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord) { int[] xdir = _getContour_xdir;// static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1}; int[] ydir = _getContour_ydir;// static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1}; int[] i_buf = (int[])i_raster.getBuffer(); int width = i_raster.getWidth(); int height = i_raster.getHeight(); NyARIntPoint2d[] coord = o_coord.items; int i_array_size = o_coord.items.Length; //クリップ領域の上端に接しているポイントを得る。 int sx = i_entry_x; int sy = i_entry_y; int coord_num = 1; coord[0].x = sx; coord[0].y = sy; int dir = 5; int c = coord[0].x; int r = coord[0].y; for (; ; ) { dir = (dir + 5) % 8;//dirの正規化 //ここは頑張ればもっと最適化できると思うよ。 //4隅以外の境界接地の場合に、境界チェックを省略するとかね。 if (c >= 1 && c < width - 1 && r >= 1 && r < height - 1) { for (; ; ) {//gotoのエミュレート用のfor文 //境界に接していないとき if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } dir++; if (i_buf[(r + ydir[dir]) * width + (c + xdir[dir])] > 0) { break; } //8方向全て調べたけどラベルが無いよ? throw new NyARException(); } } else { //境界に接しているとき int i; for (i = 0; i < 8; i++) { int x = c + xdir[dir]; int y = r + ydir[dir]; //境界チェック if (x >= 0 && x < width && y >= 0 && y < height) { if (i_buf[(y) * width + (x)] > 0) { break; } } dir++;//倍長テーブルを参照するので問題なし } if (i == 8) { //8方向全て調べたけどラベルが無いよ? throw new NyARException();// return(-1); } } dir = dir % 8;//dirの正規化 // xcoordとycoordをc,rにも保存 c = c + xdir[dir]; r = r + ydir[dir]; coord[coord_num].x = c; coord[coord_num].y = r; // 終了条件判定 if (c == sx && r == sy) { coord_num++; break; } coord_num++; if (coord_num == i_array_size) { //輪郭が末端に達した return false; } } o_coord.length = coord_num; return true; }