機械学習モデルの入力として ARCore を使用する

ARCore が機械学習パイプラインでキャプチャするカメラフィードを使用して、インテリジェントな拡張現実体験を作成できます。 ARCore ML Kit サンプルは、ML KitGoogle Cloud Vision API を使用して実世界のオブジェクトを識別する方法を示しています。 このサンプルでは、機械学習モデルを使用してカメラのビュー内のオブジェクトを分類し、仮想シーン内のオブジェクトにラベルを付加します。

ARCore ML Kit サンプルは Kotlin で記述されています。また、ARCore SDK GitHub リポジトリで ml_kotlin サンプルアプリとしても利用できます。

ARCore の CPU イメージを使用する

ARCore はデフォルトで、少なくとも 2 セットの画像ストリームをキャプチャします。

  • 特徴認識と画像処理に使用される CPU 画像ストリーム。デフォルトでは、CPU イメージの解像度は VGA(640x480)です。ARCore は、必要に応じて追加の高解像度の画像ストリームを使用するように設定できます。
  • GPU テクスチャ ストリーム。高解像度のテクスチャを含み、通常は解像度が 1080p です。これは通常、ユーザー向けのカメラ プレビューとして使用されます。これは、Session.setCameraTextureName() で指定された OpenGL テクスチャに保存されます。
  • SharedCamera.setAppSurfaces() によって指定された追加のストリーム。

CPU イメージサイズに関する考慮事項

デフォルトの VGA サイズの CPU ストリームを使用すると、追加の費用は発生しません。ARCore はこのストリームをあらゆる事柄を把握するために使用するからです。解像度の異なるストリームをリクエストすると、追加のストリームをキャプチャすることになるため、コストがかかる可能性があります。解像度を高くすると、すぐにモデルにとって費用が高額になる可能性があります。画像の幅と高さを 2 倍にすると、画像のピクセル量が 4 倍になります。

低解像度の画像でもモデルがうまく機能する場合は、画像を縮小するほうが良い場合があります。

追加の高解像度 CPU 画像ストリームを構成する

ML モデルのパフォーマンスは、入力として使用される画像の解像度によって異なる場合があります。これらのストリームの解像度を調整するには、Session.setCameraConfig() を使用して現在の CameraConfig を変更し、Session.getSupportedCameraConfigs() から有効な設定を選択します。

Java

CameraConfigFilter cameraConfigFilter =
    new CameraConfigFilter(session)
        // World-facing cameras only.
        .setFacingDirection(CameraConfig.FacingDirection.BACK);
List<CameraConfig> supportedCameraConfigs =
    session.getSupportedCameraConfigs(cameraConfigFilter);

// Select an acceptable configuration from supportedCameraConfigs.
CameraConfig cameraConfig = selectCameraConfig(supportedCameraConfigs);
session.setCameraConfig(cameraConfig);

Kotlin

val cameraConfigFilter =
  CameraConfigFilter(session)
    // World-facing cameras only.
    .setFacingDirection(CameraConfig.FacingDirection.BACK)
val supportedCameraConfigs = session.getSupportedCameraConfigs(cameraConfigFilter)

// Select an acceptable configuration from supportedCameraConfigs.
val cameraConfig = selectCameraConfig(supportedCameraConfigs)
session.setCameraConfig(cameraConfig)

CPU イメージを取得する

Frame.acquireCameraImage() を使用して CPU イメージを取得します。これらの画像は、不要になったらすぐに廃棄する必要があります。

Java

Image cameraImage = null;
try {
  cameraImage = frame.acquireCameraImage();
  // Process `cameraImage` using your ML inference model.
} catch (NotYetAvailableException e) {
  // NotYetAvailableException is an exception that can be expected when the camera is not ready
  // yet. The image may become available on a next frame.
} catch (RuntimeException e) {
  // A different exception occurred, e.g. DeadlineExceededException, ResourceExhaustedException.
  // Handle this error appropriately.
  handleAcquireCameraImageFailure(e);
} finally {
  if (cameraImage != null) {
    cameraImage.close();
  }
}

Kotlin

// NotYetAvailableException is an exception that can be expected when the camera is not ready yet.
// Map it to `null` instead, but continue to propagate other errors.
fun Frame.tryAcquireCameraImage() =
  try {
    acquireCameraImage()
  } catch (e: NotYetAvailableException) {
    null
  } catch (e: RuntimeException) {
    // A different exception occurred, e.g. DeadlineExceededException, ResourceExhaustedException.
    // Handle this error appropriately.
    handleAcquireCameraImageFailure(e)
  }

// The `use` block ensures the camera image is disposed of after use.
frame.tryAcquireCameraImage()?.use { image ->
  // Process `image` using your ML inference model.
}

CPU イメージを処理する

CPU イメージの処理には、さまざまな ML ライブラリを使用できます。

AR シーンに結果を表示する

画像認識モデルでは、多くの場合、検出された物体を表す中心点や境界ポリゴンを指定して、検出された物体を出力します。

モデルから出力された境界ボックスの中心点を使用して、検出されたオブジェクトにアンカーを適用できます。Frame.hitTest() を使用して、仮想シーン内のオブジェクトのポーズを推定します。

IMAGE_PIXELS 座標を VIEW 座標に変換します。

Java

// Suppose `mlResult` contains an (x, y) of a given point on the CPU image.
float[] cpuCoordinates = new float[] {mlResult.getX(), mlResult.getY()};
float[] viewCoordinates = new float[2];
frame.transformCoordinates2d(
    Coordinates2d.IMAGE_PIXELS, cpuCoordinates, Coordinates2d.VIEW, viewCoordinates);
// `viewCoordinates` now contains coordinates suitable for hit testing.

Kotlin

// Suppose `mlResult` contains an (x, y) of a given point on the CPU image.
val cpuCoordinates = floatArrayOf(mlResult.x, mlResult.y)
val viewCoordinates = FloatArray(2)
frame.transformCoordinates2d(
  Coordinates2d.IMAGE_PIXELS,
  cpuCoordinates,
  Coordinates2d.VIEW,
  viewCoordinates
)
// `viewCoordinates` now contains coordinates suitable for hit testing.

次の VIEW 座標を使用してヒットテストを実施し、その結果からアンカーを作成します。

Java

List<HitResult> hits = frame.hitTest(viewCoordinates[0], viewCoordinates[1]);
HitResult depthPointResult = null;
for (HitResult hit : hits) {
  if (hit.getTrackable() instanceof DepthPoint) {
    depthPointResult = hit;
    break;
  }
}
if (depthPointResult != null) {
  Anchor anchor = depthPointResult.getTrackable().createAnchor(depthPointResult.getHitPose());
  // This anchor will be attached to the scene with stable tracking.
  // It can be used as a position for a virtual object, with a rotation prependicular to the
  // estimated surface normal.
}

Kotlin

val hits = frame.hitTest(viewCoordinates[0], viewCoordinates[1])
val depthPointResult = hits.filter { it.trackable is DepthPoint }.firstOrNull()
if (depthPointResult != null) {
  val anchor = depthPointResult.trackable.createAnchor(depthPointResult.hitPose)
  // This anchor will be attached to the scene with stable tracking.
  // It can be used as a position for a virtual object, with a rotation prependicular to the
  // estimated surface normal.
}

パフォーマンスに関する注意事項

処理能力を節約し、エネルギー消費量を抑えるには、次の推奨事項に従ってください。

  • 受信フレームごとに ML モデルを実行するのではなく、代わりに、低いフレームレートでオブジェクト検出を実行することを検討してください。
  • 計算の複雑さを軽減するために、オンライン ML 推論モデルについて考えてみましょう。

次のステップ