/** * コンストラクタです。 * 入力画像のサイズを指定して、インスタンスを生成します。 * @param i_size * 入力画像のサイズ */ public NyARSquareContourDetector_Rle(NyARIntSize i_size) { this.setupImageDriver(i_size); //ラベリングのサイズを指定したいときはsetAreaRangeを使ってね。 this._coord = new NyARIntCoordinates((i_size.w + i_size.h) * 2); return; }
public override bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord) { Debug.Assert(i_t <= i_entry_x); int[] buf = (int[])this._ref_raster.getBuffer(); 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 width = this._ref_raster.getWidth(); //クリップ領域の上端に接しているポイントを得る。 NyARIntPoint2d[] coord = o_coord.items; int max_coord = o_coord.items.Length; coord[0].x = i_entry_x; coord[0].y = i_entry_y; int coord_num = 1; int dir = 5; int c = i_entry_x; int r = i_entry_y; for (;;) { dir = (dir + 5) % 8; //dirの正規化 //ここは頑張ればもっと最適化できると思うよ。 //4隅以外の境界接地の場合に、境界チェックを省略するとかね。 if (c > i_l && c < i_r && r > i_t && r < i_b) { for (;;) //gotoのエミュレート用のfor文 //境界に接していないとき(暗点判定) { if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir]) * width + (c + xdir[dir])] <= i_th) { 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 >= i_l && x <= i_r && y >= i_t && y <= i_b) { if (buf[(y) * width + (x)] <= i_th) { break; } } dir++; //倍長テーブルを参照するので問題なし } if (i == 8) { //8方向全て調べたけどラベルが無いよ? throw new NyARException(); // return(-1); } } // xcoordとycoordをc,rにも保存 c = c + xdir[dir]; r = r + ydir[dir]; coord[coord_num].x = c; coord[coord_num].y = r; //終了条件判定 if (c == i_entry_x && r == i_entry_y) { //開始点と同じピクセルに到達したら、終点の可能性がある。 coord_num++; //末端のチェック if (coord_num == max_coord) { //輪郭bufが末端に達した return(false); } //末端候補の次のピクセルを調べる dir = (dir + 5) % 8; //dirの正規化 int i; for (i = 0; i < 8; i++) { int x = c + xdir[dir]; int y = r + ydir[dir]; //境界チェック if (x >= i_l && x <= i_r && y >= i_t && y <= i_b) { if (buf[(y) * width + (x)] <= i_th) { break; } } dir++; //倍長テーブルを参照するので問題なし } if (i == 8) { //8方向全て調べたけどラベルが無いよ? throw new NyARException(); } //得たピクセルが、[1]と同じならば、末端である。 c = c + xdir[dir]; r = r + ydir[dir]; if (coord[1].x == c && coord[1].y == r) { //終点に達している。 o_coord.length = coord_num; break; } else { //終点ではない。 coord[coord_num].x = c; coord[coord_num].y = r; } } coord_num++; //末端のチェック if (coord_num == max_coord) { //輪郭が末端に達した return(false); } } return(true); }
public abstract bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord);
/** * この関数は、ラスタの指定点を基点に、画像の特定の範囲内から輪郭線を抽出します。 * 開始点は、輪郭の一部である必要があります。 * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。 * @param i_raster * 輪郭線を抽出するラスタを指定します。 * @param i_area * 輪郭線の抽出範囲を指定する矩形。i_rasterのサイズ内である必要があります。 * @param i_th * 輪郭とみなす暗点の敷居値を指定します。 * @param i_entry_x * 輪郭抽出の開始点です。 * @param i_entry_y * 輪郭抽出の開始点です。 * @param o_coord * 輪郭点を格納するオブジェクトを指定します。 * @return * 輪郭線がo_coordの長さを超えた場合、falseを返します。 * @ */ public bool getContour(INyARGrayscaleRaster i_raster, NyARIntRect i_area, int i_th, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord) { //ラスタドライバの切り替え if (i_raster != this._ref_last_input_raster) { this._imdriver = (IRasterDriver)i_raster.createInterface(typeof(IRasterDriver)); this._ref_last_input_raster = i_raster; } return(this._imdriver.getContour(i_area.x, i_area.y, i_area.x + i_area.w - 1, i_area.h + i_area.y - 1, i_entry_x, i_entry_y, i_th, o_coord)); }
/** * この関数は、ラスタから矩形を検出して、自己コールバック関数{@link #onSquareDetect}で通知します。 * ARToolKitのarDetectMarker2を基にしています。 * @param i_raster * 検出元のラスタ画像 * 入力できるラスタの画素形式は、{@link NyARLabeling_Rle#labeling(NyARGrayscaleRaster, int)}と同じです。 * @param i_th * 画素の二値判定敷居値です。この値は、ラベリングと、輪郭線追跡時に使われます。 */ public void detectMarker(INyARGrayscaleRaster i_raster, int i_th, NyARSquareContourDetector.CbHandler i_cb) { NyARRleLabelFragmentInfoPtrStack flagment = this._labeling.label_stack; NyARLabelOverlapChecker <NyARRleLabelFragmentInfo> overlap = this._overlap_checker; flagment.clear(); //ラベルの生成エラーならここまで if (!this._labeling.labeling(i_raster, i_th)) { return; } int label_num = flagment.getLength(); // ラベル数が0ならここまで if (label_num < 1) { return; } //ラベルをソートしておく flagment.sortByArea(); //ラベルリストを取得 NyARRleLabelFragmentInfo[] labels = flagment.getArray(); NyARIntCoordinates coord = this._coord; int[] mkvertex = this.__detectMarker_mkvertex; //重なりチェッカの最大数を設定 overlap.setMaxLabels(label_num); for (int i = 0; i < label_num; i++) { NyARRleLabelFragmentInfo label_pt = labels[i]; int label_area = label_pt.area; // 既に検出された矩形との重なりを確認 if (!overlap.check(label_pt)) { // 重なっているようだ。 continue; } //輪郭を取得 if (!this._cpickup.getContour(i_raster, i_th, label_pt.entry_x, 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; }
/** * 継承クラスのコンストラクタから呼び出す。 * @param i_ref_raster * 基本画像 * @param i_ref_raster_distortion * 歪み解除オブジェクト(nullの場合歪み解除を省略) * @param i_ref_rob_raster * エッジ探索用のROB画像 * @param i_contour_pickup * 輪郭線取得クラス * @param */ public void initInstance(NyARGrayscaleRaster i_ref_raster,INyARCameraDistortionFactor i_ref_raster_distortion,NyARGrayscaleRaster i_ref_rob_raster,NyARContourPickup i_contour_pickup) { this._rob_resolution=i_ref_raster.getWidth()/i_ref_rob_raster.getWidth(); this._ref_rob_raster=i_ref_rob_raster; this._ref_base_raster=i_ref_raster; this._coord_buf = new NyARIntCoordinates((i_ref_raster.getWidth() + i_ref_raster.getHeight()) * 4); this._factor=i_ref_raster_distortion; this._tmp_coord_pos = VecLinearCoordinates.VecLinearCoordinatePoint.createArray(this._coord_buf.items.Length); this._cpickup = i_contour_pickup; return; }
/** * 内部関数です。 * この関数は、thisの二次元矩形情報プロパティを更新します。 * @param i_coord * @param i_vertex_index * @ */ protected internal void updateSquareInfo(NyARIntCoordinates i_coord, int[] i_vertex_index) { NyARMatchPattResult mr = this.__detectMarkerLite_mr; //輪郭座標から頂点リストに変換 NyARIntPoint2d[] vertex = this.__ref_vertex; //C言語ならポインタ扱いで実装 vertex[0] = i_coord.items[i_vertex_index[0]]; vertex[1] = i_coord.items[i_vertex_index[1]]; vertex[2] = i_coord.items[i_vertex_index[2]]; vertex[3] = i_coord.items[i_vertex_index[3]]; //画像を取得 if (!this._inst_patt.pickFromRaster(this._last_input_raster, vertex)) { return; } //取得パターンをカラー差分データに変換して評価する。 this._deviation_data.setRaster(this._inst_patt); if (!this._match_patt.evaluate(this._deviation_data, mr)) { return; } //現在の一致率より低ければ終了 if (this._confidence > mr.confidence) { return; } //一致率の高い矩形があれば、方位を考慮して頂点情報を作成 NyARSquare sq = this._square; this._confidence = mr.confidence; //directionを考慮して、squareを更新する。 for (int i = 0; i < 4; i++) { int idx = (i + 4 - mr.direction) % 4; this._coordline.coord2Line(i_vertex_index[idx], i_vertex_index[(idx + 1) % 4], i_coord, sq.line[i]); } //ちょっと、ひっくり返してみようか。 for (int i = 0; i < 4; i++) { //直線同士の交点計算 if (!sq.line[i].crossPos(sq.line[(i + 3) % 4], sq.sqvertex[i])) { throw new NyARException();//ここのエラー復帰するならダブルバッファにすればOK } } }
public override bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord) { Debug.Assert(i_t<=i_entry_x); int[] buf=(int[])this._ref_raster.getBuffer(); 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 width=this._ref_raster.getWidth(); //クリップ領域の上端に接しているポイントを得る。 NyARIntPoint2d[] coord=o_coord.items; int max_coord=o_coord.items.Length; coord[0].x = i_entry_x; coord[0].y = i_entry_y; int coord_num = 1; int dir = 5; int c = i_entry_x; int r = i_entry_y; for (;;) { dir = (dir + 5) % 8;//dirの正規化 //ここは頑張ればもっと最適化できると思うよ。 //4隅以外の境界接地の場合に、境界チェックを省略するとかね。 if(c>i_l && c<i_r && r>i_t && r<i_b){ for(;;){//gotoのエミュレート用のfor文 //境界に接していないとき(暗点判定) if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) { break; } dir++; if (buf[(r + ydir[dir])*width+(c + xdir[dir])] <= i_th) { 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>=i_l && x<=i_r && y>=i_t && y<=i_b){ if (buf[(y)*width+(x)] <= i_th) { break; } } dir++;//倍長テーブルを参照するので問題なし } if (i == 8) { //8方向全て調べたけどラベルが無いよ? throw new NyARException();// return(-1); } } // xcoordとycoordをc,rにも保存 c = c + xdir[dir]; r = r + ydir[dir]; coord[coord_num].x = c; coord[coord_num].y = r; //終了条件判定 if (c == i_entry_x && r == i_entry_y){ //開始点と同じピクセルに到達したら、終点の可能性がある。 coord_num++; //末端のチェック if (coord_num == max_coord) { //輪郭bufが末端に達した return false; } //末端候補の次のピクセルを調べる dir = (dir + 5) % 8;//dirの正規化 int i; for (i = 0; i < 8; i++){ int x=c + xdir[dir]; int y=r + ydir[dir]; //境界チェック if(x>=i_l && x<=i_r && y>=i_t && y<=i_b){ if (buf[(y)*width+(x)] <= i_th) { break; } } dir++;//倍長テーブルを参照するので問題なし } if (i == 8) { //8方向全て調べたけどラベルが無いよ? throw new NyARException(); } //得たピクセルが、[1]と同じならば、末端である。 c = c + xdir[dir]; r = r + ydir[dir]; if(coord[1].x ==c && coord[1].y ==r){ //終点に達している。 o_coord.length=coord_num; break; }else{ //終点ではない。 coord[coord_num].x = c; coord[coord_num].y = r; } } coord_num++; //末端のチェック if (coord_num == max_coord) { //輪郭が末端に達した return false; } } return true; }
/** * この関数は、ラスタの指定点を基点に、画像の特定の範囲内から輪郭線を抽出します。 * 開始点は、輪郭の一部である必要があります。 * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。 * @param i_raster * 輪郭線を抽出するラスタを指定します。 * @param i_area * 輪郭線の抽出範囲を指定する矩形。i_rasterのサイズ内である必要があります。 * @param i_th * 輪郭とみなす暗点の敷居値を指定します。 * @param i_entry_x * 輪郭抽出の開始点です。 * @param i_entry_y * 輪郭抽出の開始点です。 * @param o_coord * 輪郭点を格納するオブジェクトを指定します。 * @return * 輪郭線がo_coordの長さを超えた場合、falseを返します。 * @ */ public bool getContour(INyARGrayscaleRaster i_raster, NyARIntRect i_area, int i_th, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord) { //ラスタドライバの切り替え if (i_raster != this._ref_last_input_raster) { this._imdriver = (IRasterDriver)i_raster.createInterface(typeof(IRasterDriver)); this._ref_last_input_raster = i_raster; } return this._imdriver.getContour(i_area.x, i_area.y, i_area.x + i_area.w - 1, i_area.h + i_area.y - 1, i_entry_x, i_entry_y, i_th, o_coord); }
/** * 矩形が見付かるたびに呼び出されます。 * 発見した矩形のパターンを検査して、方位を考慮した頂点データを確保します。 */ public void detectMarkerCallback(NyARIntCoordinates i_coord, int[] i_vertex_index) { if (this._match_patt == null) { return; } //輪郭座標から頂点リストに変換 NyARIntPoint2d[] vertex = this.__ref_vertex; vertex[0] = i_coord.items[i_vertex_index[0]]; vertex[1] = i_coord.items[i_vertex_index[1]]; vertex[2] = i_coord.items[i_vertex_index[2]]; vertex[3] = i_coord.items[i_vertex_index[3]]; //画像を取得 if (!this._inst_patt.pickFromRaster(this._ref_raster, vertex)) { return; } //取得失敗 //取得パターンをカラー差分データに変換して評価する。 this._deviation_data.setRaster(this._inst_patt); //code_index,dir,c1にデータを得る。 NyARMatchPattResult mr = this.__detectMarkerLite_mr; int lcode_index = 0; int dir = 0; double c1 = 0; for (int i = 0; i < this._match_patt.Length; i++) { this._match_patt[i].evaluate(this._deviation_data, mr); double c2 = mr.confidence; if (c1 < c2) { lcode_index = i; c1 = c2; dir = mr.direction; } } //認識処理 if (this._target_id == -1) { // マーカ未認識 if (c1 < this.cf_threshold_new) { return; } // 現在は未認識 if (this.confidence > c1) { return; } // 一致度が低い。 //認識しているマーカIDを保存 this.code_index = lcode_index; } else { //現在はマーカ認識中 // 現在のマーカを認識したか? if (lcode_index != this._target_id) { // 認識中のマーカではないので無視 return; } //認識中の閾値より大きいか? if (c1 < this.cf_threshold_exist) { return; } //現在の候補よりも一致度は大きいか? if (this.confidence > c1) { return; } this.code_index = this._target_id; } //新しく認識、または継続認識中に更新があったときだけ、Square情報を更新する。 //ココから先はこの条件でしか実行されない。 //一致率の高い矩形があれば、方位を考慮して頂点情報を作成 this.confidence = c1; NyARSquare sq = this.square; //directionを考慮して、squareを更新する。 for (int i = 0; i < 4; i++) { int idx = (i + 4 - dir) % 4; this._coordline.coord2Line(i_vertex_index[idx], i_vertex_index[(idx + 1) % 4], i_coord, sq.line[i]); } for (int i = 0; i < 4; i++) { //直線同士の交点計算 if (!sq.line[i].crossPos(sq.line[(i + 3) % 4], sq.sqvertex[i])) { throw new NyARException();//ここのエラー復帰するならダブルバッファにすればOK } } }
/** * 矩形が見付かるたびに呼び出されます。 * 発見した矩形のパターンを検査して、方位を考慮した頂点データを確保します。 */ public void detectMarkerCallback(NyARIntCoordinates i_coord, int[] i_vertex_index) { //既に発見済なら終了 if (this.marker_data != null) { return; } //輪郭座標から頂点リストに変換 NyARIntPoint2d[] vertex = this.__ref_vertex; vertex[0] = i_coord.items[i_vertex_index[0]]; vertex[1] = i_coord.items[i_vertex_index[1]]; vertex[2] = i_coord.items[i_vertex_index[2]]; vertex[3] = i_coord.items[i_vertex_index[3]]; NyIdMarkerParam param = this._marker_param; NyIdMarkerPattern patt_data = this._marker_data; // 評価基準になるパターンをイメージから切り出す if (!this._id_pickup.pickFromRaster(this._ref_raster.getGsPixelDriver(), vertex, patt_data, param)) { return; } //エンコード if (!this._encoder.Encode(patt_data, this._data_temp)) { return; } //継続認識要求されている? if (this._prev_data == null) { //継続認識要求なし this._current_data.copyFrom(this._data_temp); } else { //継続認識要求あり if (!this._prev_data.isEqual((this._data_temp))) { return;//認識請求のあったIDと違う。 } } //新しく認識、または継続認識中に更新があったときだけ、Square情報を更新する。 //ココから先はこの条件でしか実行されない。 NyARSquare sq = this.square; //directionを考慮して、squareを更新する。 for (int i = 0; i < 4; i++) { int idx = (i + 4 - param.direction) % 4; this._coordline.coord2Line(i_vertex_index[idx], i_vertex_index[(idx + 1) % 4], i_coord, sq.line[i]); } for (int i = 0; i < 4; i++) { //直線同士の交点計算 if (!sq.line[i].crossPos(sq.line[(i + 3) % 4], sq.sqvertex[i])) { throw new NyARException();//ここのエラー復帰するならダブルバッファにすればOK } } this.threshold = param.threshold; this.marker_data = this._current_data;//みつかった。 }
public void detectMarkerCallback(NyARIntCoordinates i_coord, int[] i_vertex_index) { //とりあえずSquareスタックを予約 SquareStack.Item sq_tmp = this._sq_stack.prePush(); //確保できない(1つのdetectorが複数の候補を得る場合(同じARマーカが多くある場合など)に発生することがある。) if (sq_tmp == null) { return; } //観測座標点の記録 for (int i2 = 0; i2 < 4; i2++) { sq_tmp.ob_vertex[i2].setValue(i_coord.items[i_vertex_index[i2]]); } //頂点分布を計算 sq_tmp.vertex_area.setAreaRect(sq_tmp.ob_vertex, 4); //頂点座標の中心を計算 sq_tmp.center2d.setCenterPos(sq_tmp.ob_vertex, 4); //矩形面積 sq_tmp.rect_area = sq_tmp.vertex_area.w * sq_tmp.vertex_area.h; bool is_target_marker = false; for (;;) { //トラッキング対象か確認する。 if (this._ref_tracking_list.update(sq_tmp)) { //トラッキング対象ならブレーク is_target_marker = true; break; } //@todo 複数マーカ時に、トラッキング済のarmarkerを探索対象外に出来ない? //nyIdマーカの特定(IDマーカの特定はここで完結する。) if (this._ref_idmk_list.Count > 0) { if (this._ref_idmk_list.Update(this._ref_input_gs, sq_tmp)) { is_target_marker = true; break;//idマーカを特定 } } //PSARマーカの特定(IDマーカの特定はここで完結する。) if (this._ref_psmk_list.Count > 0) { if (this._ref_psmk_list.Update(this._ref_input_gs, sq_tmp)) { is_target_marker = true; break;//idマーカを特定 } } //ARマーカの特定 if (this._ref_armk_list.Count > 0) { //敷居値により1個のマーカに対して複数の候補が見つかることもある。 if (this._ref_armk_list.Update(this._ref_input_rfb, sq_tmp)) { is_target_marker = true; break; } } break; } //この矩形が検出対象なら、矩形情報を精密に再計算 if (is_target_marker) { //矩形は検出対象にマークされている。 for (int i2 = 0; i2 < 4; i2++) { this._coordline.coord2Line(i_vertex_index[i2], i_vertex_index[(i2 + 1) % 4], i_coord, sq_tmp.line[i2]); } for (int i2 = 0; i2 < 4; i2++) { //直線同士の交点計算 if (!sq_tmp.line[i2].crossPos(sq_tmp.line[(i2 + 3) % 4], sq_tmp.sqvertex[i2])) { throw new NyARException();//まずない。ありえない。 } } } else { //この矩形は検出対象にマークされなかったので、解除 this._sq_stack.pop(); } }
public override bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord) { Debug.Assert(i_t <= i_entry_x); INyARGsPixelDriver reader = this._ref_raster.getGsPixelDriver(); 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}; //クリップ領域の上端に接しているポイントを得る。 NyARIntPoint2d[] coord = o_coord.items; int max_coord = o_coord.items.Length; coord[0].x = i_entry_x; coord[0].y = i_entry_y; int coord_num = 1; int dir = 5; int c = i_entry_x; int r = i_entry_y; for (; ;) { dir = (dir + 5) % 8;//dirの正規化 //境界に接しているとき int i; for (i = 0; i < 8; i++) { int x = c + xdir[dir]; int y = r + ydir[dir]; //境界チェック if (x >= i_l && x <= i_r && y >= i_t && y <= i_b) { if (reader.getPixel(x, y) <= i_th) { break; } } dir++;//倍長テーブルを参照するので問題なし } if (i == 8) { //8方向全て調べたけどラベルが無いよ? throw new NyARException();// return(-1); } // xcoordとycoordをc,rにも保存 c = c + xdir[dir]; r = r + ydir[dir]; coord[coord_num].x = c; coord[coord_num].y = r; //終了条件判定 if (c == i_entry_x && r == i_entry_y) { //開始点と同じピクセルに到達したら、終点の可能性がある。 coord_num++; //末端のチェック if (coord_num == max_coord) { //輪郭bufが末端に達した return(false); } //末端候補の次のピクセルを調べる dir = (dir + 5) % 8;//dirの正規化 for (i = 0; i < 8; i++) { int x = c + xdir[dir]; int y = r + ydir[dir]; //境界チェック if (x >= i_l && x <= i_r && y >= i_t && y <= i_b) { if (reader.getPixel(x, y) <= i_th) { break; } } dir++;//倍長テーブルを参照するので問題なし } if (i == 8) { //8方向全て調べたけどラベルが無いよ? throw new NyARException(); } //得たピクセルが、[1]と同じならば、末端である。 c = c + xdir[dir]; r = r + ydir[dir]; if (coord[1].x == c && coord[1].y == r) { //終点に達している。 o_coord.length = coord_num; break; } else { //終点ではない。 coord[coord_num].x = c; coord[coord_num].y = r; } } coord_num++; //末端のチェック if (coord_num == max_coord) { //輪郭が末端に達した return(false); } } return(true); }
public override bool getContour(int i_l, int i_t, int i_r, int i_b, int i_entry_x, int i_entry_y, int i_th, NyARIntCoordinates o_coord) { Debug.Assert(i_t <= i_entry_x); INyARGsPixelDriver reader = this._ref_raster.getGsPixelDriver(); 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}; //クリップ領域の上端に接しているポイントを得る。 NyARIntPoint2d[] coord = o_coord.items; int max_coord = o_coord.items.Length; coord[0].x = i_entry_x; coord[0].y = i_entry_y; int coord_num = 1; int dir = 5; int c = i_entry_x; int r = i_entry_y; for (; ; ) { dir = (dir + 5) % 8;//dirの正規化 //境界に接しているとき int i; for (i = 0; i < 8; i++) { int x = c + xdir[dir]; int y = r + ydir[dir]; //境界チェック if (x >= i_l && x <= i_r && y >= i_t && y <= i_b) { if (reader.getPixel(x, y) <= i_th) { break; } } dir++;//倍長テーブルを参照するので問題なし } if (i == 8) { //8方向全て調べたけどラベルが無いよ? throw new NyARException();// return(-1); } // xcoordとycoordをc,rにも保存 c = c + xdir[dir]; r = r + ydir[dir]; coord[coord_num].x = c; coord[coord_num].y = r; //終了条件判定 if (c == i_entry_x && r == i_entry_y) { //開始点と同じピクセルに到達したら、終点の可能性がある。 coord_num++; //末端のチェック if (coord_num == max_coord) { //輪郭bufが末端に達した return false; } //末端候補の次のピクセルを調べる dir = (dir + 5) % 8;//dirの正規化 for (i = 0; i < 8; i++) { int x = c + xdir[dir]; int y = r + ydir[dir]; //境界チェック if (x >= i_l && x <= i_r && y >= i_t && y <= i_b) { if (reader.getPixel(x, y) <= i_th) { break; } } dir++;//倍長テーブルを参照するので問題なし } if (i == 8) { //8方向全て調べたけどラベルが無いよ? throw new NyARException(); } //得たピクセルが、[1]と同じならば、末端である。 c = c + xdir[dir]; r = r + ydir[dir]; if (coord[1].x == c && coord[1].y == r) { //終点に達している。 o_coord.length = coord_num; break; } else { //終点ではない。 coord[coord_num].x = c; coord[coord_num].y = r; } } coord_num++; //末端のチェック if (coord_num == max_coord) { //輪郭が末端に達した return false; } } return true; }
/** * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。 * 開始点は、輪郭の一部である必要があります。 * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。 * @param i_raster * 輪郭線を抽出するラスタを指定します。 * @param i_th * 輪郭とみなす暗点の敷居値を指定します。 * @param i_entry_x * 輪郭抽出の開始点です。 * @param i_entry_y * 輪郭抽出の開始点です。 * @param o_coord * 輪郭点を格納する配列を指定します。i_array_sizeよりも大きなサイズの配列が必要です。 * @return * 輪郭の抽出に成功するとtrueを返します。輪郭抽出に十分なバッファが無いと、falseになります。 * @ */ public bool getContour(INyARGrayscaleRaster i_raster, int i_th, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord) { NyARIntSize s = i_raster.getSize(); //ラスタドライバの切り替え if (i_raster != this._ref_last_input_raster) { this._imdriver = (IRasterDriver)i_raster.createInterface(typeof(IRasterDriver)); this._ref_last_input_raster = i_raster; } return(this._imdriver.getContour(0, 0, s.w - 1, s.h - 1, i_entry_x, i_entry_y, i_th, o_coord)); }
/** * この関数は、ラスタの指定点を基点に、輪郭線を抽出します。 * 開始点は、輪郭の一部である必要があります。 * 通常は、ラべリングの結果の上辺クリップとX軸エントリポイントを開始点として入力します。 * @param i_raster * 輪郭線を抽出するラスタを指定します。 * @param i_th * 輪郭とみなす暗点の敷居値を指定します。 * @param i_entry_x * 輪郭抽出の開始点です。 * @param i_entry_y * 輪郭抽出の開始点です。 * @param o_coord * 輪郭点を格納する配列を指定します。i_array_sizeよりも大きなサイズの配列が必要です。 * @return * 輪郭の抽出に成功するとtrueを返します。輪郭抽出に十分なバッファが無いと、falseになります。 * @ */ public bool getContour(INyARGrayscaleRaster i_raster, int i_th, int i_entry_x, int i_entry_y, NyARIntCoordinates o_coord) { NyARIntSize s = i_raster.getSize(); //ラスタドライバの切り替え if (i_raster != this._ref_last_input_raster) { this._imdriver = (IRasterDriver)i_raster.createInterface(typeof(IRasterDriver)); this._ref_last_input_raster = i_raster; } return this._imdriver.getContour(0, 0, s.w - 1, s.h - 1, i_entry_x, i_entry_y, i_th, o_coord); }
public void detectMarkerCallback(NyARIntCoordinates i_coord, int[] i_vertex_index) { this._parent.updateSquareInfo(i_coord, i_vertex_index); }
/** * 輪郭線を取得します。 * 取得アルゴリズムは、以下の通りです。 * 1.輪郭座標(n)の画素周辺の画素ベクトルを取得。 * 2.輪郭座標(n+1)周辺の画素ベクトルと比較。 * 3.差分が一定以下なら、座標と強度を保存 * 4.3点以上の集合になったら、最小二乗法で直線を計算。 * 5.直線の加重値を個々の画素ベクトルの和として返却。 */ public bool traceConture(NyARIntCoordinates i_coord, int i_pos_mag, int i_cell_size, VecLinearCoordinates o_coord) { VecLinearCoordinates.VecLinearCoordinatePoint[] pos = this._tmp_coord_pos; // ベクトル化 int MAX_COORD = o_coord.items.Length; int i_coordlen = i_coord.length; NyARIntPoint2d[] coord = i_coord.items; VecLinearCoordinates.VecLinearCoordinatePoint pos_ptr; //0個目のライン探索 int number_of_data = 0; int sq; long sq_sum=0; //0番目のピクセル pos[0].scalar=sq=this.getAreaVector33(coord[0].x * i_pos_mag, coord[0].y * i_pos_mag,i_cell_size, i_cell_size,pos[0]); sq_sum+=(int)sq; //[2]に0を保管 //1点目だけは前方と後方、両方に探索をかける。 //前方探索の終点 int coord_last_edge=i_coordlen; //後方探索 int sum=1; double ave_dx=pos[0].dx; double ave_dy=pos[0].dy; for (int i = i_coordlen-1; i >0; i--) { // ベクトル取得 pos_ptr=pos[sum]; pos_ptr.scalar=sq=this.getAreaVector33(coord[i].x * i_pos_mag,coord[i].y * i_pos_mag, i_cell_size, i_cell_size,pos_ptr); sq_sum += (int)sq; // 類似度判定 if(checkVecCos(pos[sum],pos[sum-1],ave_dx,ave_dy)) { //相関なし->前方探索へ。 ave_dx=pos_ptr.dx; ave_dy=pos_ptr.dy; coord_last_edge=i; break; } else { //相関あり- 点の蓄積 ave_dx+=pos_ptr.dx; ave_dy+=pos_ptr.dy; sum++; } } //前方探索 for (int i = 1; i<coord_last_edge; i++) { // ベクトル取得 pos_ptr=pos[sum]; pos_ptr.scalar=sq=this.getAreaVector33(coord[i].x * i_pos_mag,coord[i].y * i_pos_mag, i_cell_size, i_cell_size,pos_ptr); sq_sum += (int)sq; if(sq==0){ continue; } //if (pos_ptr.getAbsVecCos(pos[sum-1]) < NyARMath.COS_DEG_5 && pos_ptr.getAbsVecCos(ave_dx,ave_dy)<NyARMath.COS_DEG_20) { if (checkVecCos(pos[sum],pos[sum-1],ave_dx,ave_dy)) { //相関なし->新しい要素を作る。 if(this.leastSquaresWithNormalize(pos,sum,o_coord.items[number_of_data],sq_sum/(sum*5))){ number_of_data++; } ave_dx=pos_ptr.dx; ave_dy=pos_ptr.dy; //獲得した値を0へ移動 pos[0].setValue(pos[sum]); sq_sum=0; sum=1; } else { //相関あり- 点の蓄積 ave_dx+=pos_ptr.dx; ave_dy+=pos_ptr.dy; sum++; } // 輪郭中心を出すための計算 if (number_of_data == MAX_COORD) { // 輪郭ベクトルバッファの最大を超えたら失敗 return false; } } if(this.leastSquaresWithNormalize(pos,sum,o_coord.items[number_of_data],sq_sum/(sum*5))){ number_of_data++; } // ベクトル化2:最後尾と先頭の要素が似ていれば連結する。 // sq_distの合計を計算 o_coord.length = number_of_data; return true; }