Utiliser ARCore en tant qu'entrée pour les modèles de machine learning

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">

Vous pouvez utiliser le flux de caméra enregistré par ARCore dans un pipeline de machine learning pour créer une expérience de réalité augmentée intelligente. L'exemple ML Kit ARCore montre comment identifier des objets réels à l'aide de ML Kit et de l'API Google Cloud Vision. L'exemple utilise un modèle de machine learning pour classer les objets dans le champ de la caméra et associe une étiquette à l'objet dans la scène virtuelle.

L'exemple ARCore ML Kit est écrit en Kotlin. Il est également disponible dans l'exemple ml_kotlin. dans le SDK ARCore dépôt GitHub.

Utiliser l'image de processeur d'ARCore

ARCore capture au moins deux ensembles de flux d'images par défaut:

  • Flux d'images du processeur utilisé pour la reconnaissance des caractéristiques et le traitement des images. Par défaut, la résolution de l'image du processeur est VGA (640 x 480). ARCore peut être configuré pour utiliser un autre flux d'images de plus haute résolution, si nécessaire.
  • Un flux de texture GPU, qui contient une texture haute résolution, généralement à une résolution de 1080p. Il s'agit généralement d'un aperçu de l'appareil photo visible par l'utilisateur. Il est stocké dans la texture OpenGL spécifiée par Session.setCameraTextureName().
  • Tout flux supplémentaire spécifié par SharedCamera.setAppSurfaces().

Remarques concernant la taille d'image du processeur

Si le flux de processeur par défaut de taille VGA est utilisé, aucun coût supplémentaire n'est facturé, car ARCore l'utilise pour la compréhension du monde. Demander un flux avec une résolution différente peut s'avérer coûteux, car un flux supplémentaire devra être capturé. N'oubliez pas qu'une résolution plus élevée peut rapidement coûter cher pour votre modèle: lorsque vous doublez la largeur et la hauteur de l'image, vous pouvez multiplier par quatre le nombre de pixels dans l'image.

Il peut être avantageux de réduire la taille de l'image si votre modèle peut tout de même fonctionner correctement sur une image de résolution inférieure.

Configurer un autre flux d'images haute résolution pour le processeur

Les performances de votre modèle de ML peuvent dépendre de la résolution de l'image utilisée comme entrée. La résolution de ces flux peut être ajustée en modifiant la CameraConfig actuelle à l'aide de Session.setCameraConfig(), en sélectionnant une configuration valide dans 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)

Récupérer l'image du processeur

Récupérez l'image de processeur à l'aide de Frame.acquireCameraImage(). Ces images doivent être supprimées dès qu'elles ne sont plus nécessaires.

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.
}

Traiter l'image du processeur

Diverses bibliothèques de machine learning peuvent être utilisées pour traiter l'image du processeur.

Afficher les résultats dans votre scène de RA

Les modèles de reconnaissance d'image génèrent souvent des résultats pour les objets détectés en indiquant un point central ou un polygone de délimitation représentant l'objet détecté.

En utilisant le point central ou le centre du cadre de délimitation généré par le modèle, il est possible d'associer une ancre à l'objet détecté. Utilisez Frame.hitTest() pour estimer la position d'un objet dans la scène virtuelle.

Convertissez des coordonnées IMAGE_PIXELS en coordonnées 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.

Utilisez ces coordonnées VIEW pour effectuer un test de positionnement et créer une ancre à partir du résultat:

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.
}

Considérations sur les performances

Suivez les recommandations suivantes pour économiser la puissance de traitement et l'énergie:

  • N'exécutez pas votre modèle de ML sur chaque frame entrant. Envisagez plutôt d'exécuter la détection d'objets à une fréquence d'images faible.
  • Envisagez d'utiliser un modèle d'inférence ML en ligne pour réduire la complexité des calculs.

Étapes suivantes