Usa ARCore come input per i modelli di machine learning

Puoi utilizzare il feed della videocamera acquisito da ARCore in una pipeline di machine learning per creare un'esperienza di realtà aumentata intelligente. L'esempio di ARCore ML Kit illustra come utilizzare ML Kit e l'API Google Cloud Vision per identificare oggetti reali. L'esempio utilizza un modello di machine learning per classificare gli oggetti nel campo visivo della videocamera e applica un'etichetta all'oggetto nella scena virtuale.

L'esempio di ARCore ML Kit è scritto in Kotlin. È anche disponibile come app di esempio ml_kotlin nel repository GitHub di ARCore SDK.

Utilizza l'immagine della CPU di ARCore

Per impostazione predefinita, ARCore acquisisce almeno due insiemi di stream di immagini:

  • Uno stream di immagini CPU utilizzato per il riconoscimento delle funzionalità e l'elaborazione di immagini. Per impostazione predefinita, l'immagine della CPU ha una risoluzione VGA (640 x 480). ARCore può essere configurato per utilizzare uno stream di immagini aggiuntivo a risoluzione più elevata, se necessario.
  • Uno stream di texture GPU, che contiene una texture ad alta risoluzione, generalmente a una risoluzione di 1080p. In genere viene utilizzata come anteprima della fotocamera rivolta all'utente. Questo viene memorizzato nella texture OpenGL specificata da Session.setCameraTextureName().
  • Eventuali stream aggiuntivi specificati da SharedCamera.setAppSurfaces().

Considerazioni sulle dimensioni delle immagini della CPU

Se viene utilizzato lo stream della CPU di dimensioni VGA predefinito non vengono addebitati costi aggiuntivi perché ARCore usa questo stream per la comprensione a livello mondiale. Richiedere uno stream con una risoluzione diversa può essere costoso, in quanto sarà necessario acquisire uno stream aggiuntivo. Tieni presente che una risoluzione più elevata può diventare rapidamente dispendiosa per il tuo modello: raddoppiando la larghezza e l'altezza dell'immagine, quadruplica la quantità di pixel nell'immagine.

Potrebbe essere vantaggioso ridimensionare l'immagine se il modello può comunque funzionare bene su un'immagine a risoluzione più bassa.

Configura un flusso di immagini della CPU ad alta risoluzione aggiuntivo

Le prestazioni del modello ML possono dipendere dalla risoluzione dell'immagine utilizzata come input. La risoluzione di questi stream può essere regolata cambiando l'attuale CameraConfig con Session.setCameraConfig(), selezionando una configurazione valida da 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)

Recupera l'immagine CPU

Recupera l'immagine CPU utilizzando Frame.acquireCameraImage(). Queste immagini devono essere eliminate non appena non sono più necessarie.

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

Elabora l'immagine CPU

Per elaborare l'immagine CPU, possono essere utilizzate varie librerie di machine learning.

Visualizza i risultati nella tua scena AR

I modelli di riconoscimento delle immagini spesso restituiscono gli oggetti rilevati indicando un punto centrale o un poligono di delimitazione che rappresenta l'oggetto rilevato.

Utilizzando il punto centrale o il centro del riquadro di delimitazione emesso dal modello, è possibile applicare un ancoraggio all'oggetto rilevato. Utilizza Frame.hitTest() per stimare la posizione di un oggetto nella scena virtuale.

Converti le coordinate IMAGE_PIXELS in coordinate 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.

Utilizza queste coordinate di VIEW per eseguire un hit test e creare un ancoraggio a partire dal risultato:

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

Considerazioni sul rendimento

Segui i seguenti consigli per risparmiare potenza di elaborazione e consumare meno energia:

  • Non eseguire il tuo modello ML su ogni frame in entrata. Valuta invece di eseguire il rilevamento degli oggetti a una frequenza fotogrammi bassa.
  • Considera un modello di inferenza ML online per ridurre la complessità di calcolo.

Passaggi successivi