private static int selectHistory(NyARSurfaceFeatures candidate, NyARFeatureCoordPtrList i_prev_log) { int j; for (int i = 0; i < i_prev_log.getLength(); i++) { NyARNftFsetFile.NyAR2FeatureCoord prev_item = i_prev_log.getItem(i); for (j = 0; j < candidate.getLength(); j++) { NyARSurfaceFeatureItem item = candidate.getItem(j); // 過去ログでも検出した形跡があったものを選択する。 if (prev_item == item.ref_feature) { return(j); } } } //残ってない if (candidate.getLength() == 0) { return(-1); } //適当に返す int k = (int)((double)candidate.getLength() * _rand.rand() / (RepeatedRandomizer.RAND_MAX + 1.0f)); for (int i = j = 0; i < candidate.getLength(); i++) { if (j == k) { return(i); } j++; } return(-1); }
/** * 射影変換行列ログから、候補点を計算して、メンバ変数posへ格納する。 * @param i_log * @return * 候補点の数 */ public int makeCandidatePos(NyARSurfaceFeatureItem i_cai, NyARSurfaceTransMatrixSetFifo i_log) { NyARDoublePoint2d tmp = this._tmp; NyARIntPoint2d[] p = this.pos; double x = i_cai.x; double y = i_cai.y; p[0].x = (int)x; p[0].y = (int)y; int num_of_log = i_log.num_of_item; if (num_of_log >= 3) { //過去の理想点を観察点に戻す i_log.items[1].calculate2dPos(i_cai.ref_feature.mx, i_cai.ref_feature.my, tmp); this._ref_df.ideal2Observ(tmp, tmp); p[1].x = (int)(2 * x - tmp.x); p[1].y = (int)(2 * y - tmp.y); double x1 = tmp.x; double y1 = tmp.y; i_log.items[2].calculate2dPos(i_cai.ref_feature.mx, i_cai.ref_feature.my, tmp); this._ref_df.ideal2Observ(tmp, tmp); p[2].x = (int)(3 * x - 3 * x1 + tmp.x); p[2].y = (int)(3 * y - 3 * y1 + tmp.y); return(3); } else if (num_of_log >= 2) { i_log.items[1].calculate2dPos(i_cai.ref_feature.mx, i_cai.ref_feature.my, tmp); this._ref_df.ideal2Observ(tmp, tmp); p[1].x = (int)(2 * x - tmp.x); p[1].y = (int)(2 * y - tmp.y); return(2); } return(1); }
private static int select2(NyARSurfaceFeatures candidate, int xsize, int ysize, NyARSurfaceFeatureItem i_pos0, NyARSurfaceFeatureItem i_pos1) { double dmax = 0.0f; int j = -1; for (int i = candidate.getLength() - 1; i >= 0; i--) { NyARSurfaceFeatureItem item = candidate.getItem(i); if (item.x < xsize / 8 || item.x > xsize * 7 / 8 || item.y < ysize / 8 || item.y > ysize * 7 / 8) { continue; } // なんだこれ。距離は間違いないが・・・。pos[0]とpos[1]の両方から一番離れた奴? double d = ((item.x - i_pos0.x) * (i_pos1.y - i_pos0.y) - (item.y - i_pos0.y) * (i_pos1.x - i_pos0.x)); d = d * d; if (d > dmax) { dmax = d; j = i; } } return(j); }
private static int select1(NyARSurfaceFeatures candidate, int xsize, int ysize, NyARSurfaceFeatureItem i_pos0) { double dmax = 0; int j = -1; for (int i = candidate.getLength() - 1; i >= 0; i--) { NyARSurfaceFeatureItem item = candidate.getItem(i); // スクリーンの場所でフィルタ if (item.x < xsize / 8 || item.x > xsize * 7 / 8 || item.y < ysize / 8 || item.y > ysize * 7 / 8) { continue; } // pos[0]との距離が市場の遠いのを選択 double d = (item.x - i_pos0.x) * (item.x - i_pos0.x) + (item.y - i_pos0.y) * (item.y - i_pos0.y); if (d > dmax) { dmax = d; j = i; } } return(j); }
private static int select0(NyARSurfaceFeatures candidate, int xsize, int ysize) { int j = -1; double dmax = 0.0f; for (int i = candidate.getLength() - 1; i >= 0; i--) { NyARSurfaceFeatureItem item = candidate.getItem(i); // スクリーンの場所でフィルター if (item.x < xsize / 8 || item.x > xsize * 7 / 8 || item.y < ysize / 8 || item.y > ysize * 7 / 8) { continue; } // 中心から一番距離のありそうなのを選択 double d = (item.x - xsize / 2) * (item.x - xsize / 2) + (item.y - ysize / 2) * (item.y - ysize / 2); if (d > dmax) { dmax = d; j = i; } } return(j); }
private static int select3(NyARSurfaceFeatures candidate, int xsize, int ysize, NyARSurfaceFeatureItem i_pos0, NyARSurfaceFeatureItem i_pos1, NyARSurfaceFeatureItem i_pos2) { double smax, s; SinCos p2sincos = new SinCos(); SinCos p3sincos = new SinCos(); SinCos p4sincos = new SinCos(); p2sincos.ar2GetVectorAngle(i_pos0, i_pos1); p3sincos.ar2GetVectorAngle(i_pos0, i_pos2); int j = -1; smax = 0.0f; for (int i = candidate.getLength() - 1; i >= 0; i--) { NyARSurfaceFeatureItem item = candidate.getItem(i); // スクリーンのry if (item.x < xsize / 8 || item.x > xsize * 7 / 8 || item.y < ysize / 8 || item.y > ysize * 7 / 8) { continue; } // 謎の選択ルール・・・。 // pos[3].x = item.x; // pos[3].y = item.y; p4sincos.ar2GetVectorAngle(i_pos0, item); if (((p3sincos.sin * p2sincos.cos - p3sincos.cos * p2sincos.sin) >= 0.0f) && ((p4sincos.sin * p2sincos.cos - p4sincos.cos * p2sincos.sin) >= 0.0f)) { if (p4sincos.sin * p3sincos.cos - p4sincos.cos * p3sincos.sin >= 0.0f) { s = ar2GetRegionArea(i_pos0, i_pos1, i_pos2, item); } else { s = ar2GetRegionArea(i_pos0, i_pos1, item, i_pos2); } } else if (((p4sincos.sin * p3sincos.cos - p4sincos.cos * p3sincos.sin) >= 0.0f) && ((p2sincos.sin * p3sincos.cos - p2sincos.cos * p3sincos.sin) >= 0.0f)) { if (p4sincos.sin * p2sincos.cos - p4sincos.cos * p2sincos.sin >= 0.0f) { s = ar2GetRegionArea(i_pos0, i_pos2, i_pos1, item); } else { s = ar2GetRegionArea(i_pos0, i_pos2, item, i_pos1); } } else if (((p2sincos.sin * p4sincos.cos - p2sincos.cos * p4sincos.sin) >= 0.0f) && ((p3sincos.sin * p4sincos.cos - p3sincos.cos * p4sincos.sin) >= 0.0f)) { if (p3sincos.sin * p2sincos.cos - p3sincos.cos * p2sincos.sin >= 0.0f) { s = ar2GetRegionArea(i_pos0, item, i_pos1, i_pos2); } else { s = ar2GetRegionArea(i_pos0, item, i_pos2, i_pos1); } } else { continue; } if (s > smax) { smax = s; j = i; } } return(j); }
/** * i_rasiterの画像から、i_surfaceにマッチするパターンを検出して、その理想座標と3次元座標セットを返す。 * 検出した頂点セットは、o_pos2dとo_pos3dへ最大i_num個出力する。 * @param i_raster * 現在の画像 * @param i_surface * 検出すべきサーフェイスセット * @param i_trans * 現在の姿勢変換行列 * @param o_pos2d * 出力パラメータ。画面上の理想点。 * オブジェクトの配列を指定すること。 * @param o_pos3d * 出力パラメータ。三次元サーフェイス座標。 * オブジェクトの配列を指定すること。 * @param i_num * 返却数。この数値は、コンストラクタに与えた最大数以下である必要がある。o_pos2dとo_pos3dは、この数値より大きい配列でなければならない。 * @return * 検出した頂点セットの数。 * @throws NyARException */ public int tracking(INyARGrayscaleRaster i_raster, NyARSurfaceDataSet i_surface, NyARDoubleMatrix44 i_trans, NyARDoublePoint2d[] o_pos2d, NyARDoublePoint3d[] o_pos3d, int i_num) { //テンプレートドライバの更新 INyARTemplateMatchingDriver tmd; if (this._last_raster != i_raster) { tmd = this._last_driver = new NyARTemplateMatchingDriver_INT1D(i_raster, 12, 12); this._last_raster = i_raster; } else { tmd = this._last_driver; } //射影変換行列の計算とログへの追加 NyARSurfaceTransMatrixSet tlog = this._ctrans_log.preAdd(); tlog.setValue(this._ref_cparam.getPerspectiveProjectionMatrix(), i_trans); //可視な候補を選択する。(一時リスト) this._feature_selector.extractVisibleFeatures(i_surface.fset, tlog, this._candidate, this._candidate2); PatchImagePositions pcpoints = this.__pcpoints; //load screen size. NyARIntSize s = this._ref_cparam.getScreenSize(); //頂点選択クラス類の初期化 NyARSurfaceFeatureIndexSelector index_selecter = this.__index_selecter; NyARSurfaceFeaturesPtr selected_features = this.__selected_features; selected_features.clear(); //最大返却数の決定 int max_feature = i_num > this.__selected_features.getArraySize() ? this.__selected_features.getArraySize() : i_num; int num = 0; NyARSurfaceFeatures current_candidate = this._candidate; for (int i = max_feature - 1; i >= 0; i--) { //高精度を優先して探索。なければ低精度に切り替える。切替は1度だけ。出力は座標集合。 int k = index_selecter.ar2SelectTemplate(current_candidate, this._prev_selected_features, selected_features, s); if (k < 0) { if (current_candidate == this._candidate2) { break; } current_candidate = this._candidate2; //未選択なら終了 k = index_selecter.ar2SelectTemplate(current_candidate, this._prev_selected_features, selected_features, s); if (k < 0) { break; } } //候補kを確保 NyARSurfaceFeatureItem cai = current_candidate.getItem(k); //可視な点について、トラッキングするためのパッチ画像を生成 NyARTemplatePatchImage template_ = this.__template_patch; template_.makeFromReferenceImage((int)(cai.x + 0.5), (int)(cai.y + 0.5), tlog.ctrans, this._ref_cparam.getDistortionFactor(), i_surface.iset.items[cai.scale]); //パッチ画像の内容をチェック? if (template_.vlen * template_.vlen >= (template_.xsize) * (template_.ysize) * AR2_DEFALUT_TRACKING_SD_THRESH * AR2_DEFALUT_TRACKING_SD_THRESH) { //射影変換行列ログから候補点を作る。 int number_of_point = pcpoints.makeCandidatePos(cai, this._ctrans_log); //画像からテンプレートを検索 double sim = tmd.ar2GetBestMatching(template_, pcpoints.pos, number_of_point, o_pos2d[num]); //類似値が一定以上なら、保存 if (sim > this.simThresh) { if (selected_features.push(cai) == null) { break;//最大値に達したら終わり } this._ref_cparam.getDistortionFactor().observ2Ideal(o_pos2d[num], o_pos2d[num]); o_pos3d[num].x = cai.ref_feature.mx; o_pos3d[num].y = cai.ref_feature.my; o_pos3d[num].z = 0; //選択した得量を記録 num++; } } //選択された候補を取り外す。 current_candidate.remove(k); } // 過去ログへ記録 this._prev_selected_features.clear(); for (int i = 0; i < selected_features.getLength(); i++) { this._prev_selected_features.push(selected_features.getItem(i).ref_feature); } return(num); }
public void extractVisibleFeatures( NyARNftFsetFile i_fset, NyARSurfaceTransMatrixSet i_ctrans, NyARSurfaceFeatures candidate, NyARSurfaceFeatures candidate2) { //get work objects NyARDoublePoint2d ide2d = this.__ide2d; NyARDoublePoint2d obs2d = this.__obs2d; NyARDoublePoint2d rideal2d = this.__rideal2d; // trans1.setCoefficient(i_cparam.getPerspectiveProjectionMatrix(), trans1); candidate.clear(); candidate2.clear(); int xsize = this._ref_size.w; int ysize = this._ref_size.h; INyARCameraDistortionFactor df = this._ref_dist_factor; for (int j = 0; j < i_fset.list.Length; j++) { NyARNftFsetFile.NyAR2FeaturePoints fpoint_ptr = i_fset.list[j]; for (int k = 0; k < fpoint_ptr.coord.Length; k++) { NyARNftFsetFile.NyAR2FeatureCoord coord_ptr = fpoint_ptr.coord[k]; //理想画面点を計算 i_ctrans.calculate2dPos(coord_ptr.mx, coord_ptr.my, ide2d); df.ideal2Observ(ide2d.x, ide2d.y, obs2d); //観察座標に変換後、画面内にあるか確認 if (obs2d.x < 0 || obs2d.x >= xsize) { continue; } if (obs2d.y < 0 || obs2d.y >= ysize) { continue; } //逆変換可能か確認 df.observ2Ideal(obs2d, rideal2d); if (ide2d.sqDist(rideal2d) > 1.0) { continue; } //原点からのベクトルを計算 //Z軸が+だとつかえないので判定? if (i_ctrans.calculateVd(coord_ptr.mx, coord_ptr.my) > -0.1) { continue; } // double vd0 = trans1.m00 * coord_ptr.mx+ trans1.m01 * coord_ptr.my+ trans1.m03; // double vd1 = trans1.m10 * coord_ptr.mx+ trans1.m11 * coord_ptr.my+ trans1.m13; // double vd2 = trans1.m20 * coord_ptr.mx+ trans1.m21 * coord_ptr.my+ trans1.m23; // if( (vd0*trans1.m02 + vd1*trans1.m12 + vd2*trans1.m22)/Math.sqrt( vd0*vd0 + vd1*vd1 + vd2*vd2 ) > -0.1 ){ // continue; // } //撮影箇所のdpiを計算(x,y方向で計算して、大・小の順番で格納?) double dpi = i_ctrans.ar2GetMinResolution(coord_ptr); //dpiによってコレクトする候補を分離 if (dpi <= fpoint_ptr.maxdpi && dpi >= fpoint_ptr.mindpi) { NyARSurfaceFeatureItem item = candidate.prePush(); if (item == null) { return; } item.ref_feature = coord_ptr; item.scale = fpoint_ptr.scale; item.x = obs2d.x; item.y = obs2d.y; } else if (dpi <= fpoint_ptr.maxdpi * 2 && dpi >= fpoint_ptr.mindpi / 2) { NyARSurfaceFeatureItem item = candidate2.prePush(); if (item == null) { return; } item.ref_feature = coord_ptr; item.scale = fpoint_ptr.scale; item.x = obs2d.x; item.y = obs2d.y; } } } return; }