ARCore が機械学習パイプラインでキャプチャするカメラフィードを使用して、インテリジェントな拡張現実体験を作成できます。 ARCore ML Kit サンプルは、ML Kit と Google 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 ライブラリを使用できます。
- ML Kit: ML Kit には、デバイス上のオブジェクト検出とトラッキング API が用意されています。この API には、大まかな分類器が組み込まれています。また、カスタム分類モデルを使用して、より狭い範囲のオブジェクトをカバーすることもできます。
InputImage.fromMediaImage
を使用して、CPU イメージをInputImage
に変換します。 - Firebase の機械学習: Firebase は、クラウドまたはデバイス上で動作する Machine Learning API を提供します。Android で Firebase Auth と Functions を使用して Cloud Vision で安全に画像にラベルを付ける方法に関する Firebase のドキュメントをご覧ください。
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 推論モデルについて考えてみましょう。
次のステップ
- ML エンジニアリングのベスト プラクティスについて学習する。
- 責任ある AI への取り組みについて確認する。
- TensorFlow による機械学習の基本コースを受講する。