package jp.nyatla.nyartoolkit.core.squaredetect; import jp.nyatla.nyartoolkit.NyARException; import jp.nyatla.nyartoolkit.core.labeling.artoolkit.NyARLabelingImage; import jp.nyatla.nyartoolkit.core.types.NyARIntCoordinates; import jp.nyatla.nyartoolkit.core.types.NyARIntPoint2d; /** * このクラスは、{@link NyARContourPickup}に、{@link NyARLabelingImage}の処理機能を追加したクラスです。 * <p>@bug * この輪郭線抽出は、特定のパターンで1ドット幅の輪郭を正しく抽出できません。ARToolKit互換の画像処理では * 問題になることは少ないので、大きな影響はありませんが、必要に応じて{@link NyARContourPickup}を参考に直してください。 * </p> */ public class NyARContourPickup_ARToolKit extends NyARContourPickup { /** * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。 * 開始点は、輪郭の一部である必要があります。 * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。 * @param i_raster * 輪郭線を抽出するラスタを指定します。 * @param i_entry_x * 輪郭抽出の開始点です。 * @param i_entry_y * 輪郭抽出の開始点です。 * @param o_coord * 輪郭点を格納するオブジェクトを指定します。 * @return * 輪郭線がo_coordの長さを超えた場合、falseを返します。 * @throws NyARException */ public boolean getContour(NyARLabelingImage i_raster,int i_entry_x,int i_entry_y,NyARIntCoordinates o_coord) throws NyARException { final int[] xdir = _getContour_xdir;// static int xdir[8] = { 0, 1, 1, 1, 0,-1,-1,-1}; final int[] ydir = _getContour_ydir;// static int ydir[8] = {-1,-1, 0, 1, 1, 1, 0,-1}; final int[] i_buf=(int[])i_raster.getBuffer(); final int width=i_raster.getWidth(); final int height=i_raster.getHeight(); final 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++){ final int x=c + xdir[dir]; final 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; } }