/** * RealityTargetに一致するID値を特定します。 * 複数のパターンにヒットしたときは、一番初めにヒットした項目を返します。 * @param i_target * Realityが検出したターゲット。 * Unknownターゲットを指定すること。 * @param i_rtsorce * i_targetを検出したRealitySourceインスタンス。 * @param o_result * 返却値を格納するインスタンスを設定します。 * 返却値がtrueの場合のみ、内容が更新されています。 * @return * 特定に成功すると、trueを返します。 * @throws NyARException */ public bool identifyId(NyARRealityTarget i_target, NyARRealitySource i_rtsorce, IdentifyIdResult o_result) { //NyARDoublePoint2d[] i_vertex,NyARRgbRaster i_raster,SelectResult o_result return(this.identifyId( ((NyARRectTargetStatus)(i_target._ref_tracktarget._ref_status)).vertex, i_rtsorce.refRgbSource(), o_result)); }
//メインループ処理 public void MainLoop() { //RealitySourceにデータが処理する。 if (!this._reality_source.isReady()) { return; } // 背景を書く try{ lock (this){ // 背景サーフェイスを直接描画 Surface dest_surface = this._device.GetBackBuffer(0, 0, BackBufferType.Mono); Rectangle src_dest_rect = new Rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); this._device.StretchRectangle((Surface)this._surface, src_dest_rect, dest_surface, src_dest_rect, TextureFilter.None); // 3Dオブジェクトの描画はここから this._device.BeginScene(); this._device.Clear(ClearFlags.ZBuffer, Color.DarkBlue, 1.0f, 0); //ターゲットリストを走査して、画面に内容を反映 NyARRealityTargetList tl = this._reality.refTargetList(); for (int i = tl.getLength() - 1; i >= 0; i--) { NyARRealityTarget t = tl.getItem(i); switch (t.getTargetType()) { case NyARRealityTarget.RT_KNOWN: //立方体を20mm上(マーカーの上)にずらしておく Matrix mat = new Matrix(); this._reality.getD3dModelViewMatrix(t.refTransformMatrix(), ref mat); Matrix transform_mat2 = Matrix.Translation(0, 0, 20.0f); transform_mat2 = transform_mat2 * mat; this._device.SetTransform(TransformType.World, transform_mat2); this._cube.draw(this._device); break; case NyARRealityTarget.RT_UNKNOWN: // break; } } // 描画はここまで this._device.EndScene(); // 実際のディスプレイに描画 this._device.Present(); } Thread.Sleep(1); // タスク実行権限を一旦渡す }catch (Exception e) { System.Console.WriteLine(e.StackTrace); } return; }
/* 非同期イベントハンドラ * CaptureDeviceからのイベントをハンドリングして、バッファとテクスチャを更新する。 */ public void onSample(WmCapture i_sender, INySample i_sample) { int w = SCREEN_WIDTH; int h = SCREEN_HEIGHT; int s = w * h; Thread.Sleep(0); lock (this) { //カメラ映像をARのバッファにコピー this._reality_source.setWMCaptureSample(i_sample.GetData(), i_sender.vertical_flip); this._reality.progress(this._reality_source); //テクスチャ内容を更新 this._back_ground.CopyFromRaster((DsRGB565Raster)this._reality_source.refRgbSource()); //UnknownTargetを1個取得して、遷移を試す。 NyARRealityTarget t = this._reality.selectSingleUnknownTarget(); if (t == null) { return; } //ターゲットに一致するデータを検索 ARTKMarkerTable.GetBestMatchTargetResult r = new ARTKMarkerTable.GetBestMatchTargetResult(); if (this._mklib.getBestMatchTarget(t, this._reality_source, r)) { if (r.confidence < 0.5) { //一致率が低すぎる。 return; } //既に認識しているターゲットの内側のものでないか確認する?(この処理をすれば、二重認識は無くなる。) //一致度を確認して、80%以上ならKnownターゲットへ遷移 if (!this._reality.changeTargetToKnown(t, r.artk_direction, r.marker_width)) { //遷移の成功チェック return;//失敗 } //遷移に成功したので、tagにResult情報をコピーしておく。(後で表示に使う) t.tag = r; } else { //一致しないので、このターゲットは捨てる。 this._reality.changeTargetToDead(t, 10); } } return; }
/* 非同期イベントハンドラ * CaptureDeviceからのイベントをハンドリングして、バッファとテクスチャを更新する。 */ public void OnBuffer(CaptureDevice i_sender, double i_sample_time, IntPtr i_buffer, int i_buffer_len) { int w = i_sender.video_width; int h = i_sender.video_height; int s = w * (i_sender.video_bit_count / 8); lock (this) { //カメラ映像をARのバッファにコピー this._reality_source.setDShowImage(i_buffer, i_buffer_len, i_sender.video_vertical_flip); this._reality.progress(this._reality_source); //テクスチャ内容を更新 this._surface.setRaster(this._reality_source.refRgbSource()); //UnknownTargetを1個取得して、遷移を試す。 NyARRealityTarget t = this._reality.selectSingleUnknownTarget(); if (t == null) { return; } //ターゲットに一致するデータを検索 ARTKMarkerTable.GetBestMatchTargetResult r = new ARTKMarkerTable.GetBestMatchTargetResult(); if (this._mklib.getBestMatchTarget(t, this._reality_source, r)) { if (r.confidence < 0.6) { //一致率が低すぎる。 return; } //既に認識しているターゲットの内側のものでないか確認する?(この処理をすれば、二重認識は無くなる。) //一致度を確認して、80%以上ならKnownターゲットへ遷移 if (!this._reality.changeTargetToKnown(t, r.artk_direction, r.marker_width)) { //遷移の成功チェック return; //失敗 } //遷移に成功したので、tagにResult情報をコピーしておく。(後で表示に使う) t.tag = r; } else { //一致しないので、このターゲットは捨てる。 this._reality.changeTargetToDead(t, 15); } } return; }
//メインループ処理 public void MainLoop() { //ARの計算 lock (this) { // 背景サーフェイスを直接描画 Surface dest_surface = this._device.GetBackBuffer(0, 0, BackBufferType.Mono); Rectangle src_dest_rect = new Rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); this._device.StretchRectangle((Surface)this._surface, src_dest_rect, dest_surface, src_dest_rect, TextureFilter.None); // 3Dオブジェクトの描画はここから this._device.BeginScene(); this._device.Clear(ClearFlags.ZBuffer, Color.DarkBlue, 1.0f, 0); //ターゲットリストを走査して、画面に内容を反映 NyARRealityTargetList tl = this._reality.refTargetList(); for (int i = tl.getLength() - 1; i >= 0; i--) { NyARRealityTarget t = tl.getItem(i); switch (t.getTargetType()) { case NyARRealityTarget.RT_KNOWN: //立方体を20mm上(マーカーの上)にずらしておく Matrix mat = new Matrix(); this._reality.getD3dModelViewMatrix(t.refTransformMatrix(), ref mat); Matrix transform_mat2 = Matrix.Translation(0, 0, 20.0f); transform_mat2 = transform_mat2 * mat; this._device.SetTransform(TransformType.World, transform_mat2); this._cube.draw(this._device); break; case NyARRealityTarget.RT_UNKNOWN: //NyARDoublePoint2d[] p = t.refTargetVertex(); //NyARGLDrawUtil.beginScreenCoordinateSystem(this._gl, SCREEN_X, SCREEN_Y, true); //NyARGLDrawUtil.endScreenCoordinateSystem(this._gl); break; } } // 描画はここまで this._device.EndScene(); // 実際のディスプレイに描画 this._device.Present(); } return; }
//メインループ処理 public void MainLoop() { //ARの計算 lock (this) { Device dev = this._d3dmgr.d3d_device; // 背景サーフェイスを直接描画 // 3Dオブジェクトの描画はここから dev.Clear(ClearFlags.ZBuffer, Color.DarkBlue, 1.0f, 0); dev.BeginScene(); this._back_ground.drawBackGround(this._d3dmgr.d3d_device); //ターゲットリストを走査して、画面に内容を反映 NyARRealityTargetList tl = this._reality.refTargetList(); for (int i = tl.getLength() - 1; i >= 0; i--) { NyARRealityTarget t = tl.getItem(i); switch (t.getTargetType()) { case NyARRealityTarget.RT_KNOWN: //立方体を20mm上(マーカーの上)にずらしておく Matrix mat = new Matrix(); this._reality.getD3dModelViewMatrix(t.refTransformMatrix(), ref mat); Matrix transform_mat2 = Matrix.Translation(0, 0, 20.0f); transform_mat2 = transform_mat2 * mat; dev.SetTransform(TransformType.World, transform_mat2); this._d3dcube.draw(dev); break; case NyARRealityTarget.RT_UNKNOWN: //NyARDoublePoint2d[] p = t.refTargetVertex(); //NyARGLDrawUtil.beginScreenCoordinateSystem(this._gl, SCREEN_X, SCREEN_Y, true); //NyARGLDrawUtil.endScreenCoordinateSystem(this._gl); break; } } // 描画はここまで dev.EndScene(); // 実際のディスプレイに描画 dev.Present(); } return; }
/* 非同期イベントハンドラ * CaptureDeviceからのイベントをハンドリングして、バッファとテクスチャを更新する。 */ public void OnBuffer(CaptureDevice i_sender, double i_sample_time, IntPtr i_buffer, int i_buffer_len) { try { lock (this) { this._reality_source.setDShowImage(i_buffer, i_buffer_len, i_sender.video_vertical_flip); this._reality.progress(this._reality_source); //テクスチャ内容を更新 this._surface.setRaster(this._reality_source.refRgbSource()); //UnknownTargetを1個取得して、遷移を試す。 NyARRealityTarget t = this._reality.selectSingleUnknownTarget(); if (t == null) { return; } //ターゲットに一致するデータを検索 RawbitSerialIdTable.IdentifyIdResult r = new RawbitSerialIdTable.IdentifyIdResult(); if (this._mklib.identifyId(t, this._reality_source, r)) { //テーブルにターゲットが見つかったので遷移する。 if (!this._reality.changeTargetToKnown(t, r.artk_direction, r.marker_width)) { //遷移の成功チェック return; //失敗 } //遷移に成功したので、tagにユーザ定義情報を書きこむ。 long l = new long(); l = r.id; t.tag = l; } else { //一致しないので、このターゲットは捨てる。(15フレーム無視) this._reality.changeTargetToDead(t, 15); } } } catch (Exception e) { System.Console.WriteLine(e.StackTrace); } return; }
public void Test() { try { NyARParam param = NyARParam.createFromARParamFile(new StreamReader(PARAM_FILE)); param.changeScreenSize(320, 240); NyARReality reality = new NyARReality(param.getScreenSize(), 10, 1000, param.getPerspectiveProjectionMatrix(), null, 10, 10); NyARRealitySource reality_in = new NyARRealitySource_Reference(320, 240, null, 2, 100, NyARBufferType.BYTE1D_B8G8R8X8_32); //試験イメージの読み出し(320x240 BGRAのRAWデータ) StreamReader sr = new StreamReader(DATA_FILE); BinaryReader bs = new BinaryReader(sr.BaseStream); byte[] raw = bs.ReadBytes(320 * 240 * 4); Array.Copy(raw, (byte[])reality_in.refRgbSource().getBuffer(), raw.Length); Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < 1000; i++) { reality.progress(reality_in); } sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds + "[ms]"); Console.WriteLine(reality.getNumberOfKnown()); Console.WriteLine(reality.getNumberOfUnknown()); Console.WriteLine(reality.getNumberOfDead()); NyARRealityTarget[] rt = new NyARRealityTarget[10]; reality.selectUnKnownTargets(rt); reality.changeTargetToKnown(rt[0], 2, 80); Console.WriteLine(rt[0]._transform_matrix.m00 + "," + rt[0]._transform_matrix.m01 + "," + rt[0]._transform_matrix.m02 + "," + rt[0]._transform_matrix.m03); Console.WriteLine(rt[0]._transform_matrix.m10 + "," + rt[0]._transform_matrix.m11 + "," + rt[0]._transform_matrix.m12 + "," + rt[0]._transform_matrix.m13); Console.WriteLine(rt[0]._transform_matrix.m20 + "," + rt[0]._transform_matrix.m21 + "," + rt[0]._transform_matrix.m22 + "," + rt[0]._transform_matrix.m23); Console.WriteLine(rt[0]._transform_matrix.m30 + "," + rt[0]._transform_matrix.m31 + "," + rt[0]._transform_matrix.m32 + "," + rt[0]._transform_matrix.m33); } catch (Exception e) { Console.WriteLine(e.StackTrace); } return; }
/** * RealityTargetに最も一致するパターンをテーブルから検索して、メタデータを返します。 * @param i_target * Realityが検出したターゲット。 * Unknownターゲットを指定すること。 * @param i_rtsorce * i_targetを検出したRealitySourceインスタンス。 * @param o_result * 返却値を格納するインスタンスを設定します。 * 返却値がtrueの場合のみ、内容が更新されています。 * @return * 特定に成功すると、trueを返します。 * @throws NyARException */ public bool getBestMatchTarget(NyARRealityTarget i_target, NyARRealitySource i_rtsorce, GetBestMatchTargetResult o_result) { //パターン抽出 NyARMatchPattResult tmp_patt_result = this.__tmp_patt_result; NyARPerspectiveRasterReader r = i_rtsorce.refPerspectiveRasterReader(); r.read4Point(i_rtsorce.refRgbSource(), i_target.refTargetVertex(), this._edge_x, this._edge_y, this._sample_per_pix, this._tmp_raster); //比較パターン生成 this._deviation_data.setRaster(this._tmp_raster); int ret = -1; int dir = -1; double cf = Double.MinValue; for (int i = this._table.getLength() - 1; i >= 0; i--) { this._match_patt.setARCode(this._table.getItem(i).code); this._match_patt.evaluate(this._deviation_data, tmp_patt_result); if (cf < tmp_patt_result.confidence) { ret = i; cf = tmp_patt_result.confidence; dir = tmp_patt_result.direction; } } if (ret < 0) { return(false); } //戻り値を設定 MarkerTable.SerialTableRow row = this._table.getItem(ret); o_result.artk_direction = dir; o_result.confidence = cf; o_result.idtag = row.idtag; o_result.marker_height = row.marker_height; o_result.marker_width = row.marker_width; o_result.name = row.name; return(true); }
/** * i_targetの大きさを推定して、{@link UnknownRectInfo}に結果を保存します。この関数は{@link UnknownRectInfo}の状態を変化させるだけです。 * @param i_target * 大きさを推定するターゲット。 * @param io_result * 入出力パラメータ。前段までの推定結果と現在の推定値をマージして返します。 * はじめてターゲットの推定をするときは、リセットした{@link UnknownRectInfo}を入力してください。 * @return * 認識状況を返します。 * @throws NyARException */ public void detectCardDirection(NyARRealityTarget i_target, UnknownRectInfo io_result) { //成功点数が20点を超えたら推定完了。 if (io_result._success_point > 20) { io_result.last_status = ESTIMATE_COMPLETE; return; } //10回失敗したら推定失敗 if (io_result._failed > 10) { io_result.last_status = FAILED_ESTIMATE; return; } NyARDoublePoint2d[] pos = i_target.refTargetVertex(); //正面から一回認識させてほしい。 for (int i = 0; i < 4; i++) { //正面判定。辺のなす角が90、または-90度の10度以内であること。 if (getAbsSin(pos[0 + i], pos[(1 + i) % 4], pos[(2 + i) % 4]) < 0.984) { io_result.last_status = MORE_FRONT_CENTER; return; } } //線の長さを4本計算 double d1 = Math.Sqrt(pos[0].sqDist(pos[1])); double d2 = Math.Sqrt(pos[1].sqDist(pos[2])); double d3 = Math.Sqrt(pos[2].sqDist(pos[3])); double d4 = Math.Sqrt(pos[3].sqDist(pos[0])); //現在の比率を計算 double t, t2, t3; t = d1 + d3 * 0.5; t2 = d2 + d4 * 0.5; t3 = t / t2; t3 = t3 < 1?1 / t3:t3; if (io_result._target_serial == NyARRealityTarget.INVALID_REALITY_TARGET_ID) { //サイクルをリセット io_result._target_serial = i_target.getSerialId(); io_result.rate = t3; io_result._success_point = 0; io_result._failed = 0; io_result.artk_direction = t < t2?1:0; } else { if (io_result._target_serial != i_target.getSerialId()) { //ターゲットが一致しない。 io_result.last_status = FAILED_TARGET_MISSMATCH; return; } if (t3 / io_result.rate > 0.98 && t3 / io_result.rate < 1.02) { io_result.rate = (io_result.rate + t3) * 0.5; io_result._success_point++; } else { io_result._failed++; } } //推定中 io_result.last_status = ESTIMATE_NOW; return; }
/** * このターゲットについて、非同期に認識依頼を出します。このプログラムはサンプルなので、別スレッドでIDマーカ判定をして、 * 三秒後に適当なサイズとDirectionを返却するだけです。 * @param i_target * @return * @throws NyARException */ public void requestAsyncMarkerDetect(NyARReality i_reality, NyARRealitySource i_source, NyARRealityTarget i_target) { //ターゲットから画像データなどを取得するときは、スレッドからではなく、ここで同期して取得してコピーしてからスレッドに引き渡します。 //100x100の領域を切りだして、Rasterを作る。 NyARRgbRaster raster = new NyARRgbRaster(100, 100, NyARBufferType.INT1D_X8R8G8B8_32); i_reality.getRgbPatt2d(i_source, i_target.refTargetVertex(), 1, raster); //コピーしたラスタとターゲットのIDをスレッドへ引き渡す。 Thread t = new Thread(new AsyncThread(this, i_target.getSerialId(), raster).run); t.Start(); return; }