Android アプリで Raw Depth を使用する

Raw Depth API は、フル Depth API データよりも精度が高いカメラ画像の深度データを提供しますが、必ずしもすべてのピクセルをカバーしているわけではありません。元の奥行き画像を照合する信頼度画像とともにさらに処理できるため、アプリは個々のユースケースに対して十分な精度がある奥行きデータのみを使用できます。

デバイスの互換性

Raw Depth は、Depth API をサポートするすべてのデバイスで利用できます。Raw Depth API は、完全な Depth API と同様に、Time-of-Flight(ToF)センサーなど、サポートされているハードウェア深度センサーを必要としません。ただし、Raw Depth API と完全な Depth API はどちらも、デバイスでサポートされている任意のハードウェア センサーを利用します。

Raw Depth API と Full Depth API の比較

Raw Depth API を使用すると、より正確に奥行きを推定できます。ただし、未加工の奥行きの画像には、カメラ画像内のすべてのピクセルの奥行きの推定が含まれない場合があります。これに対して、完全な Depth API はピクセルごとに推定深度を提供しますが、ピクセルごとの深度データは、深度推定値の平滑化と補間によって精度が低くなる場合があります。奥行きのある画像の形式とサイズは両方の API で同じです。異なるのはコンテンツだけです。

次の表は、Raw Depth API と Full Depth API の違いを、キッチンの椅子とテーブルの画像を使用して示したものです。

API 戻り値 カメラ画像 奥行きのある画像 信頼度の画像
Raw Depth API
  • カメラ画像内のすべてのピクセルではなく、一部のピクセルの非常に正確な深度推定値を含む未加工の深度画像。
  • すべての奥行きの未加工画像ピクセルごとに信頼度を与える信頼度の画像。深度を推定できないカメラ画像のピクセルの信頼度は 0 です。
Full Depth API
  • 各ピクセルの奥行きの推定値を含む、単一の「平滑化された」奥行き画像。
  • この API では信頼度の画像は提供されません。
該当しない

信頼度の画像

Raw Depth API から返される信頼度の画像では、明るいピクセルほど信頼値が高く、白いピクセルは完全な信頼度を表し、黒いピクセルは信頼度が低いことを示します。一般に、カメラ画像で木のようにテクスチャの多い領域は、何もない領域(何もない壁など)よりも生の奥行きの信頼度が高くなります。通常、テクスチャのないサーフェスの信頼度は 0 になります。

対象デバイスがサポートされているハードウェア深度センサーを搭載している場合は、テクスチャのない表面であっても、カメラに十分近い画像領域の信頼度が高くなります。

コンピューティングの費用

Raw Depth API のコンピューティング費用は、完全な Depth API のコンピューティング費用の約半分です。

ユースケース

Raw Depth API を使用すると、シーン内のオブジェクトのジオメトリをより詳細に表現した深度画像を取得できます。未加工の深度データは、ジオメトリを理解するタスクに深度の精度とディテールの向上が求められる AR エクスペリエンスを作成する際に有用です。次のような用途があります。

  • 3D 再構築
  • 測定
  • 形状検出

前提条件

続行する前に、AR の基本的なコンセプトARCore セッションを構成する方法を理解しておいてください。

Depth を有効にする

新しい ARCore セッションで、ユーザーのデバイスが Depth に対応しているかどうかを確認します。処理能力の制約により、すべての ARCore 対応デバイスが Depth API をサポートしているわけではありません。リソースを節約するため、ARCore では奥行きがデフォルトで無効になっています。アプリで Depth API を使用するには、深度モードを有効にします。

Java

Config config = session.getConfig();

// Check whether the user's device supports Depth.
if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {
  // Enable depth mode.
  config.setDepthMode(Config.DepthMode.AUTOMATIC);
}
session.configure(config);

Kotlin

if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {
  session.configure(session.config.apply { depthMode = Config.DepthMode.AUTOMATIC })
}

深度と信頼度に関する最新の未加工の画像を取得

frame.acquireRawDepthImage16Bits() を呼び出して、最新の未加工深度画像を取得します。Raw Depth API を介して返されたすべての画像ピクセルに深度データが含まれるわけではなく、すべての ARCore フレームに新しい RAW 深度画像が含まれるとは限りません。現在のフレームの RAW 深度画像が新しいかどうかを判断するには、そのタイムスタンプを以前の RAW 深度画像のタイムスタンプと比較します。タイムスタンプが異なる場合、元の奥行きの画像は新しい奥行きデータに基づいています。それ以外の場合、奥行き画像は以前の奥行きデータを再投影したものです。

frame.acquireRawDepthConfidenceImage() を呼び出して信頼度の画像を取得します。信頼度の画像を使用して、各元の奥行きピクセルの精度を確認できます。信頼度の画像は Y8 形式で返されます。各ピクセルは 8 ビット符号なし整数です。0 は最も低い信頼度を示し、255 は最大の信頼度を示します。

Java

// Use try-with-resources, so that images are released automatically.
try (
// Depth image is in uint16, at GPU aspect ratio, in native orientation.
Image rawDepth = frame.acquireRawDepthImage16Bits();
    // Confidence image is in uint8, matching the depth image size.
    Image rawDepthConfidence = frame.acquireRawDepthConfidenceImage(); ) {
  // Compare timestamps to determine whether depth is is based on new
  // depth data, or is a reprojection based on device movement.
  boolean thisFrameHasNewDepthData = frame.getTimestamp() == rawDepth.getTimestamp();
  if (thisFrameHasNewDepthData) {
    ByteBuffer depthData = rawDepth.getPlanes()[0].getBuffer();
    ByteBuffer confidenceData = rawDepthConfidence.getPlanes()[0].getBuffer();
    int width = rawDepth.getWidth();
    int height = rawDepth.getHeight();
    someReconstructionPipeline.integrateNewImage(depthData, confidenceData, width, height);
  }
} catch (NotYetAvailableException e) {
  // Depth image is not (yet) available.
}

Kotlin

try {
  // Depth image is in uint16, at GPU aspect ratio, in native orientation.
  frame.acquireRawDepthImage16Bits().use { rawDepth ->
    // Confidence image is in uint8, matching the depth image size.
    frame.acquireRawDepthConfidenceImage().use { rawDepthConfidence ->
      // Compare timestamps to determine whether depth is is based on new
      // depth data, or is a reprojection based on device movement.
      val thisFrameHasNewDepthData = frame.timestamp == rawDepth.timestamp
      if (thisFrameHasNewDepthData) {
        val depthData = rawDepth.planes[0].buffer
        val confidenceData = rawDepthConfidence.planes[0].buffer
        val width = rawDepth.width
        val height = rawDepth.height
        someReconstructionPipeline.integrateNewImage(
          depthData,
          confidenceData,
          width = width,
          height = height
        )
      }
    }
  }
} catch (e: NotYetAvailableException) {
  // Depth image is not (yet) available.
}

次のステップ

  • Raw Depth の Codelab を参照して、Raw Depth を使用して独自のアプリを作成する方法を学習する。