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

Raw Depth API は、Full Depth API データよりも精度が高いカメラ画像の深度データを提供しますが、必ずしもすべてのピクセルを網羅しているわけではありません。未加工の奥行き画像とそれに対応する信頼度画像をさらに処理して、アプリは個々のユースケースに十分な精度を持つ奥行きデータのみを使用できます。

デバイスの互換性

Raw Depth は、Depth API をサポートするすべてのデバイスで使用できます。Raw Depth API は、完全な Depth API と同様に、飛行時間(ToF)センサーなどのサポートされているハードウェア奥行きセンサーを必要としません。ただし、Raw Depth API と完全な Depth API はどちらも、デバイスに搭載されているサポート対象のハードウェア センサーを利用します。

Raw Depth API と Full Depth API

Raw Depth API はより精度の高い深度推定を提供しますが、未加工の深度画像にはカメラ画像内のすべてのピクセルの深度推定値が含まれるとは限りません。一方、Full Depth API はすべてのピクセルの推定深度を提供しますが、深度推定の平滑化と補間により、ピクセルごとの深度データの精度は低くなる可能性があります。奥行き画像の形式とサイズはどちらの API でも同じです。内容が異なるだけです。

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

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

信頼度の画像

Raw Depth API から返される画像の信頼度は、明るいピクセルほど高くなり、白いピクセルは完全な信頼度を表し、黒いピクセルは信頼度なしを表します。一般に、カメラ画像の中で木など、テクスチャが多い領域は、空白の壁のような領域よりも、未加工の深度信頼度が高くなります。テクスチャのないサーフェスの信頼度は通常、0 になります。

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

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

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

ユースケース

Raw Depth API を使用すると、シーン内のオブジェクトのジオメトリをより詳しく表現する奥行きのある画像を取得できます。未加工の深度データは、ジオメトリを理解するためのタスクで奥行きの精度と詳細を高める必要がある AR エクスペリエンスを作成する際に役立ちます。ユースケースには、次のようなものがあります。

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

前提条件

AR の基礎的なコンセプトを理解しておいてください。 と ARCore セッションを構成する方法を確認してください。

奥行きを有効にする

新しい 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 フレームに新しい未加工の奥行き画像が含まれているわけでもありません。現在のフレームの未加工の奥行き画像が新しいかどうかを判断するには、そのタイムスタンプを以前の未加工の奥行き画像のタイムスタンプと比較します。タイムスタンプが異なる場合、未加工の奥行き画像は新しい奥行きデータに基づいて作成されます。それ以外の場合、奥行き画像は以前の奥行きデータを再投影したものです。

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 で、未加工の深度を使って独自のアプリを作成する方法を学習する。