Table of Contents

外部フレームデータソースの入力フレームデータ要件

外部フレームデータソースを正しく動作させるために、最も重要で、同時に最も扱いが難しい作業はデータの正しさを保証することです。この記事では、外部フレームデータソースの入力フレームデータ要件について説明します。

開始する前に

入力フレームデータの種類

Unity では、外部フレームデータソースは通常、2 つの異なる時点で異なるデータを受け取る必要があります。外部データの入力時刻とデータ特性に基づき、この 2 つのデータ群を次のように呼びます。

  1. カメラフレームデータ(camera frame data)
  2. レンダリングフレームデータ(rendering frame data)

外部フレームデータソースの種類によって、この 2 つのデータ群に対する要件は異なります。

  • 画像およびデバイスモーションデータ入力拡張: カメラフレームデータとレンダリングフレームデータの両方が必要
  • 画像入力拡張: カメラフレームデータのみが必要

カメラフレームデータ

データ要件:

  1. timestamp
  2. 物理カメラの生画像データ(raw camera image data)
  3. 内部パラメータ(intrinsics。画像サイズ、焦点距離、主点を含む。歪みがある場合は、歪みモデルと歪みパラメータも必要)
  4. 外部パラメータ(extrinsics。Tcw または Twc。物理カメラの、デバイス/頭部の pose origin に対する物理オフセットを表すキャリブレーション済み行列)
  5. トラッキング状態(tracking status)
  6. デバイス pose(device pose)

データ時刻:

  • 物理カメラ露光の中点

データの使用:

  • API 呼び出し時刻: 外部コードの設計に応じて変更できます。多くのデバイスで使用される一般的な方法は、3D engine のレンダリング更新内で問い合わせ、デバイスデータの timestamp に基づいてデータをさらに処理するかどうかを判断することです
  • API 呼び出しスレッド: 3D engine の game thread、または使用するすべての外部 API が thread-safe であれば任意の他のスレッド

Unity での API 呼び出し例は次のとおりです。

void TryInputCameraFrameData()
{
    double timestamp;

    if (timestamp == curTimestamp) { return; }
    curTimestamp = timestamp;

    PixelFormat format;
    Vector2Int size;
    Vector2Int pixelSize;
    int bufferSize;

    var bufferO = TryAcquireBuffer(bufferSize);
    if (bufferO.OnNone) { return; }
    var buffer = bufferO.Value;

    IntPtr imageData;
    buffer.tryCopyFrom(imageData, 0, 0, bufferSize);

    var historicalHeadPose = new Pose();
    MotionTrackingStatus trackingStatus = (MotionTrackingStatus)(-1);

    using (buffer)
    using (var image = Image.create(buffer, format, size.x, size.y, pixelSize.x, pixelSize.y))
    {
        HandleCameraFrameData(deviceCamera, timestamp, image, cameraParameters, historicalHeadPose, trackingStatus);
    }
}

frame data をレンダリングする

データ要件:

  1. Timestamp
  2. Tracking status
  3. Device pose

データ時刻:

  • 画面に表示される時刻。TimeWarp は含まれません。同じ時刻の device pose データは、たとえば device SDK など外部側で、現在のフレームをレンダリングするために仮想カメラの transform を設定する目的で使用されます。
注記

TimeWarp(Reprojection または ATW/PTW と呼ばれることもあります)は、VR/AR ヘッドセットでよく使われる遅延低減技術です。レンダリング完了後、最新の頭部 pose に基づいて画像を再度ワープし、レンダリング中に発生した頭部の動きを補正します。EasyAR が必要とするのは、レンダリング開始時に仮想カメラを設定するために使用された pose に対応する時刻であり、TimeWarp 後に実際に画面へ表示される時刻ではありません。

データの使用:

  • API 呼び出し時刻: 3D engine の各レンダリングフレーム
  • API 呼び出しスレッド: 3D engine の game thread

Unity での API 呼び出し例は次のとおりです。

private void InputRenderFrameMotionData()
{
    double timestamp = 0e-9;
    var headPose = new Pose();
    MotionTrackingStatus trackingStatus = (MotionTrackingStatus)(-1);
    HandleRenderFrameData(timestamp, headPose, trackingStatus);
}

データ要件の詳細

物理カメラ画像データ:

  • 画像座標系: センサーが水平のときに取得したデータも水平である必要があります。データは左上隅を origin とし、row-major 順で保存する必要があります。画像は反転または上下逆にしてはいけません。
  • 画像 FPS: 通常の 30 または 60 fps のデータはいずれも使用できます。高 fps が特別な影響を持つ場合、妥当なアルゴリズム効果を得るための最小許容フレームレートは 2 です。2 より高い fps の使用を推奨し、通常は元データのフレームレートをそのまま使用できます。
  • 画像サイズ: より良い計算結果を得るには、長辺が 960 以上である必要があります。通常、データ経路内で時間のかかる画像スケーリングを行うことは推奨されません。フルサイズデータのコピー時間が許容できないほど長くなっていない限り、元データを直接使用することを推奨します。画像解像度は 640*480 未満にできません。
  • ピクセル形式: トラッキング効果を優先し、性能も総合的に考慮すると、通常の優先順は YUV > RGB > RGBA > Gray(YUV の Y 成分)です。YUV データを使用する場合は、データのパッキングや padding の詳細を含む完全なデータ定義が必要です。単一チャネル画像と比べると、カラー画像を使用した方が Mega の効果は良くなりますが、他の機能への影響は大きくありません。
  • データアクセス: データポインタまたは同等の実装。データ経路内で不要なコピーを可能な限りなくすことが望ましいです。HandleRenderFrameData では、EasyAR がデータを 1 部コピーし、その後非同期で使用します。この同期呼び出しが完了すると、画像データは使用されなくなります。データの所有権に注意してください。

タイムスタンプ:

  • すべてのタイムスタンプはクロック同期されている必要があり、可能であればハードウェア同期が望ましいです。データ単位は秒ですが、精度はナノ秒または可能な限り高い精度に達する必要があります。

トラッキング状態:

  • トラッキング状態はデバイスによって定義され、トラッキングロスト、つまり VIO が利用不可の状態を含む必要があります。より多くのレベルがある場合はさらに望ましいです。

デバイス pose:

  • すべての pose(3D エンジン内の仮想カメラの transform を含む)は同じ原点を使用する必要があります。
  • すべての pose および extrinsics は同じ座標軸システムを使用する必要があります。
  • Unity では、pose データの座標軸システムの種類は Unity 座標軸システムまたは EasyAR 座標軸システムである必要があります。input extension が EasyAR によって実装され、別の座標軸システム定義を使用する場合は、明確な座標軸システム定義、または Unity 座標軸システムや EasyAR 座標軸システムへ変換する方法を提供してください。
  • Unity では、Unity XR framework を使用する場合、XROrigin.TrackingOriginMode.Device モードに対応していれば十分です。

Intrinsics:

  • すべての値は画像データと一致している必要があります。必要に応じて、EasyAR に入力する前に intrinsics をスケーリングしてください。
  • input extension が EasyAR によって実装される場合、intrinsics が毎フレーム変化するかどうかを説明してください。これは、対応する API を 1 回呼び出すべきか、毎フレーム呼び出すべきかの違いになります。

Extrinsics:

  • ヘッドセットでは実データを提供する必要があります。
  • これはキャリブレーション行列であり、物理カメラの device/head の pose 原点に対する物理的なオフセットを表します。デバイスの pose と物理カメラの pose が同じであれば、単位行列である必要があります。
  • Apple Vision Pro の対応インターフェイスは CameraFrame.Sample.Parameters.extrinsics です。そのデータ定義はインターフェイスに必要なデータと異なり、EasyAR 内部では変換後に使用される点に注意してください。
  • Unity では、extrinsics の座標軸システムの種類は Unity 座標軸システムまたは EasyAR 座標軸システムである必要があります。input extension が EasyAR によって実装され、別の座標軸システム定義を使用する場合は、明確な座標軸システム定義、または Unity 座標軸システムや EasyAR 座標軸システムへ変換する方法を提供してください。
  • ヘッドセットデバイスには通常、原点、向き、左右手系表現などの定義が異なる複数の座標系が存在します。Extrinsics は同一座標系の下で計算する必要があります。このインターフェイスのデータは、同一座標系内の座標変換を必要とし、定義の異なる 2 つの座標系間の変換行列ではありません。

パフォーマンス:

  • データは最適な効率で提供される必要があります。多くの実装では API 呼び出しはレンダリング過程で発生するため、下位層で時間のかかる処理が必要な場合でも、API 呼び出しをブロックしない、またはこれらの API を適切な方法で使用することを推奨します。
  • input extension が EasyAR によって実装される場合、時間のかかるすべての API 呼び出しについて説明してください。

マルチカメラ:

  • 少なくとも 1 台のカメラデータが必要です。このカメラは RGB カメラ、VST カメラ、ローカライズカメラなどのいずれでも構いません。ヘッドセットで 1 台のカメラデータのみを入力する場合、通常は中央または目の近くにある RGB カメラまたは VST カメラの使用が推奨されます。
  • マルチカメラを使用すると EasyAR アルゴリズムの効果を高められます。利用可能なすべてのカメラのある時点のカメラフレームデータは、同じ時刻に同時入力する必要があります。

マルチカメラは現在まだ完全にはサポートされていません。詳細は EasyAR へお問い合わせください。

次のステップ

関連トピック

  • EasyAR 座標系
  • 画像入力拡張サンプル Workflow_FrameSource_ExternalImageStream