topical media & game development
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.