topical media & game development

talk show tell print

student-ar-org-libspark-flartoolkit-core-FLARSquareDetector.ax

student-ar-org-libspark-flartoolkit-core-FLARSquareDetector.ax [swf] flex


  /* 
   * PROJECT: FLARToolKit
   * --------------------------------------------------------------------------------
   * This work is based on the NyARToolKit developed by
   *   R.Iizuka (nyatla)
   * http://nyatla.jp/nyatoolkit/
   *
   * The FLARToolKit is ActionScript 3.0 version ARToolkit class library.
   * Copyright (C)2008 Saqoosha
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version 2
   * of the License, or (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   * 
   * You should have received a copy of the GNU General Public License
   * along with this framework; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   * 
   * For further information please contact.
   *        http://www.libspark.org/wiki/saqoosha/FLARToolKit
   *        <saq(at)saqoosha.net>
   * 
   */
  
  package org.libspark.flartoolkit.core {
          import org.libspark.flartoolkit.core.labeling.FLARLabelingImageBitmapData;
          import org.libspark.flartoolkit.core.labeling.FLARLabelingLabel;
          import org.libspark.flartoolkit.core.labeling.FLARLabelingLabelStack;
          import org.libspark.flartoolkit.core.labeling.FLARLabeling_BitmapData;
          import org.libspark.flartoolkit.core.labeling.IFLARLabeling;
          import org.libspark.flartoolkit.core.labeling.IFLARLabelingImage;
          import org.libspark.flartoolkit.core.param.FLARCameraDistortionFactor;
          import org.libspark.flartoolkit.core.raster.IFLARRaster;
          import org.libspark.flartoolkit.core.types.FLARIntSize;
          import org.libspark.flartoolkit.core.types.FLARLinear;
          import org.libspark.flartoolkit.utils.ArrayUtil;        
  
          
イメージから正方形候補を検出するクラス。 このクラスは、arDetectMarker2.cとの置き換えになります。

  
          public class @ax-student-ar-org-libspark-flartoolkit-core-FLARSquareDetector implements I@ax-student-ar-org-libspark-flartoolkit-core-FLARSquareDetector {
  
                  private static const VERTEX_FACTOR:Number = 1.0; // 線検出のファクタ
  
                  private static const AR_AREA_MAX:int = 100000; // #define AR_AREA_MAX 100000
  
                  private static const AR_AREA_MIN:int = 70; // #define AR_AREA_MIN 70
                  private var _width:int;
                  private var _height:int;
  
                  private var _labeling:IFLARLabeling;
  
                  private var _limage:IFLARLabelingImage;
  
                  private var _overlap_checker:OverlapChecker = new OverlapChecker();
                  private var _dist_factor_ref:FLARCameraDistortionFactor;
  
                  
最大i_squre_max個のマーカーを検出するクラスを作成する。
parameter: i_param

  
                  public function @ax-student-ar-org-libspark-flartoolkit-core-FLARSquareDetector(i_dist_factor_ref:FLARCameraDistortionFactor, i_size:FLARIntSize) {
                          this._width = i_size.w;
                          this._height = i_size.h;
                          this._dist_factor_ref = i_dist_factor_ref;
  //                        this._labeling = new FLARLabeling_ARToolKit();
                          this._labeling = new FLARLabeling_BitmapData();
  //                        this._limage = new FLARLabelingImage(this._width, this._height);
                          this._limage = new FLARLabelingImageBitmapData(this._width, this._height);
                          this._labeling.attachDestination(this._limage);
  
                          // 輪郭の最大長は画面に映りうる最大の長方形サイズ。
                          var number_of_coord:int = (this._width + this._height) * 2;
  
                          // 輪郭バッファは頂点変換をするので、輪郭バッファの2倍取る。
                          this._max_coord = number_of_coord;
                          this._xcoord = new Array(number_of_coord * 2);//new int[number_of_coord * 2];
                          this._ycoord = new Array(number_of_coord * 2);//new int[number_of_coord * 2];
                  }
  
                  private var _max_coord:int;
                  private var _xcoord:Array; // int[]
                  private var _ycoord:Array; // int[]
  
                  

parameter: i_coord_x int[]
parameter: i_coord_y int[]

  
                  private function normalizeCoord(i_coord_x:Array, i_coord_y:Array, i_index:int, i_coord_num:int):void {
                          // vertex1を境界にして、後方に配列を連結
                          ArrayUtil.copy(i_coord_x, 1, i_coord_x, i_coord_num, i_index);
                          ArrayUtil.copy(i_coord_y, 1, i_coord_y, i_coord_num, i_index);
  //                System.arraycopy(i_coord_x, 1, i_coord_x, i_coord_num, i_index);
  //                System.arraycopy(i_coord_y, 1, i_coord_y, i_coord_num, i_index);
                  }
  
                  //        private final int[] __detectMarker_mkvertex = new int[5];
                  private var __detectMarker_mkvertex:Array = new Array(5);
  
                  
ARMarkerInfo2 *arDetectMarker2( ARInt16 *limage, int label_num, int *label_ref,int *warea, double *wpos, int *wclip,int area_max, int area_min, double factor, int *marker_num ) 関数の代替品 ラベリング情報からマーカー一覧を作成してo_marker_listを更新します。 関数はo_marker_listに重なりを除外したマーカーリストを作成します。
parameter: i_raster 解析する2値ラスタイメージを指定します。
parameter: o_square_stack 抽出した正方形候補を格納するリスト @throws FLARException

  
                  public function detectMarker(i_raster:IFLARRaster, o_square_stack:FLARSquareStack):void {
                          const labeling_proc:IFLARLabeling = this._labeling;
                          const limage:IFLARLabelingImage = this._limage;
  
                          // 初期化
  
                          // マーカーホルダをリセット
                          o_square_stack.clear();
  
                          // ラベリング
                          labeling_proc.labeling(i_raster);
  
                          // ラベル数が0ならここまで
                          const label_num:int = limage.getLabelStack().getLength();
                          if (label_num < 1) {
                                  return;
                          }
  
                          const stack:FLARLabelingLabelStack = limage.getLabelStack();
                          const labels:Array = stack.getArray(); 
                          // FLARLabelingLabel[]
                  
                  
                          // ラベルを大きい順に整列
                          stack.sortByArea();
  
                          // デカいラベルを読み飛ばし
                          var i:int;
                          for (i = 0;i < label_num; i++) {
                                  // 検査対象内のラベルサイズになるまで無視
                                  if (labels[i].area <= AR_AREA_MAX) {
                                          break;
                                  }
                          }
  
                          const xsize:int = this._width;
                          const ysize:int = this._height;
                          const xcoord:Array = this._xcoord; // int[]
                          const ycoord:Array = this._ycoord; // int[]
                          const coord_max:int = this._max_coord;
                          const mkvertex:Array = this.__detectMarker_mkvertex; // int[]
                          const overlap:OverlapChecker = this._overlap_checker;
                          var coord_num:int;
                          var label_area:int;
                          var label_pt:FLARLabelingLabel;
  
                          //重なりチェッカの最大数を設定
                          overlap.reset(label_num);
  
                          var vertex1:int;
                          var square_ptr:FLARSquare;
                          for (;i < label_num; i++) {
                                  label_pt = labels[i];
                                  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;
                                  }
  
                                  // 輪郭を取得
                                  coord_num = limage.getContour(i, coord_max, xcoord, ycoord);
                                  if (coord_num == coord_max) {
                                          // 輪郭が大きすぎる。
                                          continue;
                                  }
                                  //頂点候補のインデクスを取得
                                  vertex1 = scanVertex(xcoord, ycoord, coord_num);
  
                                  // 頂点候補(vertex1)を先頭に並べなおした配列を作成する。
                                  normalizeCoord(xcoord, ycoord, vertex1, coord_num);
  
                                  // 領域を準備する。
                                  square_ptr = o_square_stack.prePush() as FLARSquare;
  
                                  // 頂点情報を取得
                                  if (!getSquareVertex(xcoord, ycoord, vertex1, coord_num, label_area, mkvertex)) {
                                          o_square_stack.pop();
                                          // 頂点の取得が出来なかったので破棄
                                          continue;
                                  }
  
                                  if (!getSquareLine(mkvertex, xcoord, ycoord, square_ptr)) {
                                          // 矩形が成立しなかった。
                                          o_square_stack.pop();
                                          continue;
                                  }
                                  // 検出済の矩形の属したラベルを重なりチェックに追加する。
                                  overlap.push(label_pt);
                                  
                                  // 後から参照できるように
                                  square_ptr.label = label_pt;
                          }        
                          return;
                  }
  
                  
辺からの対角線が最長になる点を対角線候補として返す。
parameter: i_xcoord int[]
parameter: i_ycoord int[]
parameter: i_coord_num int @return

  
                  private function scanVertex(i_xcoord:Array, i_ycoord:Array, i_coord_num:int):int {
                          const sx:int = i_xcoord[0];
                          const sy:int = i_ycoord[0];
                          var d:int = 0;
                          var w:int;
                          var x:int;
                          var y:int;
                          var ret:int = 0;
                          var i:int;
                          for (i = 1; i < i_coord_num; i++) {
                                  x = i_xcoord[i] - sx;
                                  y = i_ycoord[i] - sy;
                                  w = x * x + y * y;
                                  if (w > d) {
                                          d = w;
                                          ret = i;
                                  }
                          // ここでうまく終了条件入れられないかな。
                          }
                          return ret;
                  }
  
                  private const __getSquareVertex_wv1:FLARVertexCounter = new FLARVertexCounter();
  
                  private const __getSquareVertex_wv2:FLARVertexCounter = new FLARVertexCounter();
  
                  
static int arDetectMarker2_check_square( int area, ARMarkerInfo2 *marker_info2, double factor ) 関数の代替関数 OPTIMIZED STEP [450->415] o_squareに頂点情報をセットします。
parameter: i_x_coord int[]
parameter: i_y_coord int[]
parameter: i_vertex1_index
parameter: i_coord_num
parameter: i_area
parameter: o_vertex int[] 要素数はint[4]である事 @return

  
                  private function getSquareVertex(i_x_coord:Array, i_y_coord:Array, i_vertex1_index:int, i_coord_num:int, i_area:int, o_vertex:Array):Boolean {
                          const wv1:FLARVertexCounter = this.__getSquareVertex_wv1;
                          const wv2:FLARVertexCounter = this.__getSquareVertex_wv2;
                          const end_of_coord:int = i_vertex1_index + i_coord_num - 1;
                          const sx:int = i_x_coord[i_vertex1_index];
                          // sx = marker_info2->x_coord[0];
                          const sy:int = i_y_coord[i_vertex1_index];
                          // sy = marker_info2->y_coord[0];
                          var dmax:int = 0;
                          var v1:int = i_vertex1_index;
                          var d:int;
                          var i:int;
                          for (i = 1 + i_vertex1_index; i < end_of_coord; i++) {
                                  // for(i=1;i<marker_info2->coord_num-1;i++)
                                  // {
                                  d = (i_x_coord[i] - sx) * (i_x_coord[i] - sx) + (i_y_coord[i] - sy) * (i_y_coord[i] - sy);
                                  if (d > dmax) {
                                          dmax = d;
                                          v1 = i;
                                  }
                          }
                          const thresh:Number = (i_area / 0.75) * 0.01 * VERTEX_FACTOR;
  
                          o_vertex[0] = i_vertex1_index;
  
                          if (!wv1.getVertex(i_x_coord, i_y_coord, i_vertex1_index, v1, thresh)) { 
                                  // if(get_vertex(marker_info2->x_coord,marker_info2->y_coord,0,v1,thresh,wv1,&wvnum1)<
                                  // 0 ) {
                                  return false;
                          }
                          if (!wv2.getVertex(i_x_coord, i_y_coord, v1, end_of_coord, thresh)) {
                                  // if(get_vertex(marker_info2->x_coord,marker_info2->y_coord,v1,marker_info2->coord_num-1,thresh,wv2,&wvnum2)
                                  // < 0) {
                                  return false;
                          }
  
                          var v2:int;
                          if (wv1.number_of_vertex == 1 && wv2.number_of_vertex == 1) {
                                  // if(wvnum1 == 1 && wvnum2== 1) {
                                  o_vertex[1] = wv1.vertex[0];
                                  o_vertex[2] = v1;
                                  o_vertex[3] = wv2.vertex[0];
                          } else if (wv1.number_of_vertex > 1 && wv2.number_of_vertex == 0) {
                                  // }else if( wvnum1 > 1 && wvnum2== 0) {
                                  //頂点位置を、起点から対角点の間の1/2にあると予想して、検索する。
                                  v2 = (v1 - i_vertex1_index) / 2 + i_vertex1_index;
                                  if (!wv1.getVertex(i_x_coord, i_y_coord, i_vertex1_index, v2, thresh)) {
                                          return false;
                                  }
                                  if (!wv2.getVertex(i_x_coord, i_y_coord, v2, v1, thresh)) {
                                          return false;
                                  }
                                  if (wv1.number_of_vertex == 1 && wv2.number_of_vertex == 1) {
                                          o_vertex[1] = wv1.vertex[0];
                                          o_vertex[2] = wv2.vertex[0];
                                          o_vertex[3] = v1;
                                  } else {
                                          return false;
                                  }
                          } else if (wv1.number_of_vertex == 0 && wv2.number_of_vertex > 1) {
                                  //v2 = (v1-i_vertex1_index+ end_of_coord-i_vertex1_index) / 2+i_vertex1_index;
                                  v2 = (v1 + end_of_coord) / 2;
  
                                  if (!wv1.getVertex(i_x_coord, i_y_coord, v1, v2, thresh)) {
                                          return false;
                                  }
                                  if (!wv2.getVertex(i_x_coord, i_y_coord, v2, end_of_coord, thresh)) {
                                          return false;
                                  }
                                  if (wv1.number_of_vertex == 1 && wv2.number_of_vertex == 1) {
                                          o_vertex[1] = v1;
                                          o_vertex[2] = wv1.vertex[0];
                                          o_vertex[3] = wv2.vertex[0];
                                  } else {
                                          return false;
                                  }
                          } else {
                                  return false;
                          }
                          o_vertex[4] = end_of_coord;
                          return true;
                  }
  
                  private const __getSquareLine_input:FLARMat = new FLARMat(1, 2);
  
                  private const __getSquareLine_evec:FLARMat = new FLARMat(2, 2);
  
                  private const __getSquareLine_ev:FLARVec = new FLARVec(2);
  
                  private const __getSquareLine_mean:FLARVec = new FLARVec(2);
  
                  
arGetLine(int x_coord[], int y_coord[], int coord_num,int vertex[], double line[4][3], double v[4][2]) arGetLine2(int x_coord[], int y_coord[], int coord_num,int vertex[], double line[4][3], double v[4][2], double *dist_factor) の2関数の合成品です。 マーカーのvertex,lineを計算して、結果をo_squareに保管します。 Optimize:STEP[424->391]
parameter: i_mkvertex int[]
parameter: i_xcoord int[]
parameter: i_ycoord int[]
parameter: o_square @return @throws FLARException

  
                  private function getSquareLine(i_mkvertex:Array, i_xcoord:Array, i_ycoord:Array, o_square:FLARSquare):Boolean {
                          const l_line:Array = o_square.line; // FLARLinear[]
                          const ev:FLARVec = this.__getSquareLine_ev; // matrixPCAの戻り値を受け取る
                          const mean:FLARVec = this.__getSquareLine_mean; // matrixPCAの戻り値を受け取る
                          const mean_array:Array = mean.getArray(); // double[]
                          const dist_factor:FLARCameraDistortionFactor = this._dist_factor_ref;  
                          const input:FLARMat = this.__getSquareLine_input;
                          // 次処理で初期化される。
                          const evec:FLARMat = this.__getSquareLine_evec;
                          // アウトパラメータを受け取るから初期化不要//new FLARMat(2,2);
                          const evec_array:Array = evec.getArray(); // double[][]
                          
                          var i:int;
                          var w1:Number;
                          var st:int;
                          var ed:int;
                          var n:int;
                          var l_line_i:FLARLinear;
                          for (i = 0; i < 4; i++) {
                                  w1 = (i_mkvertex[i + 1] - i_mkvertex[i] + 1) * 0.05 + 0.5;
                                  st = (i_mkvertex[i] + w1);
                                  ed = (i_mkvertex[i + 1] - w1);
                                  n = ed - st + 1;
                                  if (n < 2) {
                                          // nが2以下でmatrix.PCAを計算することはできないので、エラー
                                          return false;
                                  }
                                  // pcaの準備
                                  input.realloc(n, 2);
                                  // バッチ取得
                                  dist_factor.observ2IdealBatch(i_xcoord, i_ycoord, st, n, input.getArray());
  
                                  // 主成分分析
                                  input.matrixPCA(evec, ev, mean);
                                  l_line_i = l_line[i];
                                  l_line_i.run = evec_array[0][1];
                                  // line[i][0] = evec->m[1];
                                  l_line_i.rise = -evec_array[0][0];
                                  // line[i][1] = -evec->m[0];
                                  l_line_i.intercept = -(l_line_i.run * mean_array[0] + l_line_i.rise * mean_array[1]);// line[i][2] = -(line[i][0]*mean->v[0] + line[i][1]*mean->v[1]);
                          }
  
                          const l_sqvertex:Array = o_square.sqvertex; 
                          // FLARDoublePoint2d[]
                          const l_imvertex:Array = o_square.imvertex; 
                          // FLARIntPoint[]
                          
                          var l_line_2:FLARLinear;
                          for (i = 0; i < 4; i++) {
                                  l_line_i = l_line[i];
                                  l_line_2 = l_line[(i + 3) % 4];
                                  w1 = l_line_2.run * l_line_i.rise - l_line_i.run * l_line_2.rise;
                                  if (w1 == 0.0) {
                                          return false;
                                  }
                                  l_sqvertex[i].x = (l_line_2.rise * l_line_i.intercept - l_line_i.rise * l_line_2.intercept) / w1;
                                  l_sqvertex[i].y = (l_line_i.run * l_line_2.intercept - l_line_2.run * l_line_i.intercept) / w1;
                                  // 頂点インデクスから頂点座標を得て保存
                                  l_imvertex[i].x = i_xcoord[i_mkvertex[i]];
                                  l_imvertex[i].y = i_ycoord[i_mkvertex[i]];
                          }
                          return true;
                  }
          }
  }
  
  import org.libspark.flartoolkit.core.labeling.FLARLabelingLabel;
  
  
get_vertex関数を切り離すためのクラス

  
  class FLARVertexCounter {
  
          public const vertex:Array = new Array(10); // = new int[10];// 5まで削れる
  
          public var number_of_vertex:int;
  
          private var thresh:Number;
  
          private var x_coord:Array; // int[]
  
          private var y_coord:Array; // int[]
  
          

parameter: i_x_coord int[]
parameter: i_y_coord int[]
parameter: st
parameter: ed
parameter: i_thresh

  
          public function getVertex(i_x_coord:Array, i_y_coord:Array, st:int, ed:int, i_thresh:Number):Boolean {
                  this.number_of_vertex = 0;
                  this.thresh = i_thresh;
                  this.x_coord = i_x_coord;
                  this.y_coord = i_y_coord;
                  return get_vertex(st, ed);
          }
  
          
static int get_vertex( int x_coord[], int y_coord[], int st, int ed,double thresh, int vertex[], int *vnum) 関数の代替関数
parameter: x_coord
parameter: y_coord
parameter: st
parameter: ed
parameter: thresh @return

  
          private function get_vertex(st:int, ed:int):Boolean {
                  var v1:int = 0;
                  const lx_coord:Array = this.x_coord; // int[]
                  const ly_coord:Array = this.y_coord; // int[]
                  const a:Number = ly_coord[ed] - ly_coord[st];
                  const b:Number = lx_coord[st] - lx_coord[ed];
                  const c:Number = lx_coord[ed] * ly_coord[st] - ly_coord[ed] * lx_coord[st];
                  var dmax:Number = 0;
                  
                  var i:int;
                  var d:Number;
                  for (i = st + 1; i < ed; i++) {
                          d = a * lx_coord[i] + b * ly_coord[i] + c;
                          if (d * d > dmax) {
                                  dmax = d * d;
                                  v1 = i;
                          }
                  }
                  if (dmax / (a * a + b * b) > thresh) {
                          if (!get_vertex(st, v1)) {
                                  return false;
                          }
                          if (number_of_vertex > 5) {
                                  return false;
                          }
                          vertex[number_of_vertex] = v1;
                          // vertex[(*vnum)] = v1;
                          number_of_vertex++;
                          // (*vnum)++;
  
                          if (!get_vertex(v1, ed)) {
                                  return false;
                          }
                  }
                  return true;
          }
  }
  
  
ラベル同士の重なり(内包関係)を調べるクラスです。 ラベルリストに内包するラベルを蓄積し、それにターゲットのラベルが内包されているか を確認します。

  
  class OverlapChecker {
  
          private var _labels:Array = new Array(32); // new FLARLabelingLabel[32];
  
          private var _length:int;
  
          
最大i_max_label個のラベルを蓄積できるようにオブジェクトをリセットする
parameter: i_max_label

  
          public function reset(i_max_label:int):void {
                  if (i_max_label > this._labels.length) {
  //                        this._labels = new FLARLabelingLabel[i_max_label];
                          this._labels = new Array(i_max_label);
                          var n:int = i_max_label;
                          while (n--) {
                                  this._labels[n] = new FLARLabelingLabel();
                          }
                  }
                  this._length = 0;
          }
  
          
チェック対象のラベルを追加する。
parameter: i_label_ref

  
          public function push(i_label_ref:FLARLabelingLabel):void {
                  this._labels[this._length] = i_label_ref;
                  this._length++;
          }
  
          
現在リストにあるラベルと重なっているかを返す。
parameter: i_label
returns: 何れかのラベルの内側にあるならばfalse,独立したラベルである可能性が高ければtrueです.

  
          public function check(i_label:FLARLabelingLabel):Boolean {
                  // 重なり処理かな?
                  const label_pt:Array = this._labels; // FLARLabelingLabel[]
                  const px1:int = int(i_label.pos_x);
                  const py1:int = int(i_label.pos_y);
                  
                  var i:int;
                  var px2:int;
                  var py2:int;
                  var d:int;
                  for (i = this._length - 1;i >= 0; i--) {
                          px2 = int(label_pt[i].pos_x);
                          py2 = int(label_pt[i].pos_y);
                          d = (px1 - px2) * (px1 - px2) + (py1 - py2) * (py1 - py2);
                          if (d < label_pt[i].area / 4) {
                                  // 対象外
                                  return false;
                          }
                  }
                  // 対象
                  return true;
          }
  }


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.