ARCore als Eingabe für Modelle für maschinelles Lernen verwenden

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

Mit dem Kamerafeed, den ARCore in einer Pipeline für maschinelles Lernen aufzeichnet, können Sie ein intelligentes Augmented-Reality-Erlebnis schaffen. Im ARCore ML Kit-Beispiel wird gezeigt, wie Sie mit ML Kit und der Google Cloud Vision API reale Objekte identifizieren können. Im Beispiel wird ein Modell für maschinelles Lernen verwendet, um Objekte in der Kameraansicht zu klassifizieren und dem Objekt in der virtuellen Szene ein Label hinzuzufügen.

Das ARCore ML Kit-Beispiel ist die in Kotlin geschrieben wurden. Sie ist auch als ml_kotlin-Beispiel verfügbar. App im ARCore SDK GitHub-Repository

CPU-Image von ARCore verwenden

ARCore erfasst standardmäßig mindestens zwei Bildstreams:

  • Ein CPU-Bildstream, der für die Featureerkennung und Bildverarbeitung verwendet wird. Standardmäßig hat das CPU-Image eine Auflösung von VGA (640 x 480). ARCore kann bei Bedarf so konfiguriert werden, dass ein zusätzlicher Bildstream mit höherer Auflösung verwendet wird.
  • Ein GPU-Texturstream, der eine hochauflösende Textur enthält, normalerweise eine Auflösung von 1080p. Sie wird in der Regel als eine für den Nutzer sichtbare Kameravorschau verwendet. Sie wird in der OpenGL-Textur gespeichert, die durch Session.setCameraTextureName() angegeben wird.
  • Alle zusätzlichen Streams, die durch SharedCamera.setAppSurfaces() angegeben werden.

Überlegungen zur CPU-Image-Größe

Wenn der standardmäßige CPU-Stream in VGA-Größe verwendet wird, fallen keine zusätzlichen Kosten an, da ARCore diesen Stream zum besseren Verständnis nutzt. Das Anfordern eines Streams mit einer anderen Auflösung kann teuer sein, da ein zusätzlicher Stream aufgenommen werden muss. Beachten Sie, dass eine höhere Auflösung für Ihr Modell schnell teuer werden kann: Die Verdoppelung von Breite und Höhe des Bildes vervierfacht die Anzahl der Pixel im Bild.

Es kann vorteilhaft sein, das Bild zu verkleinern, sofern Ihr Modell auch bei Bildern mit geringerer Auflösung gut funktioniert.

Zusätzlichen CPU-Bildstream mit hoher Auflösung konfigurieren

Die Leistung Ihres ML-Modells kann von der Auflösung des als Eingabe verwendeten Bilds abhängen. Die Auflösung dieser Streams kann angepasst werden. Ändern Sie dazu den aktuellen CameraConfig mit Session.setCameraConfig() und wählen Sie eine gültige Konfiguration aus Session.getSupportedCameraConfigs() aus.

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-Image abrufen

Rufen Sie das CPU-Image mit Frame.acquireCameraImage() ab. Sie sollten diese Bilder entsorgen, sobald sie nicht mehr benötigt werden.

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-Image verarbeiten

Zur Verarbeitung des CPU-Images können verschiedene Bibliotheken für maschinelles Lernen verwendet werden.

Ergebnisse in AR-Szenen anzeigen

Bilderkennungsmodelle geben häufig erkannte Objekte aus, indem sie einen Mittelpunkt oder ein Begrenzungspolygon für das erkannte Objekt angeben.

Durch Verwenden des Mittelpunkts oder der Mitte des Begrenzungsrahmens, der vom Modell ausgegeben wird, ist es möglich, einen Anker an das erkannte Objekt anzuhängen. Mit Frame.hitTest() können Sie die Position eines Objekts in der virtuellen Szene schätzen.

IMAGE_PIXELS-Koordinaten in VIEW-Koordinaten umwandeln:

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.

Verwenden Sie diese VIEW-Koordinaten, um einen Treffertest durchzuführen und einen Anker aus dem Ergebnis zu erstellen:

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

Hinweise zur Leistung

Folgen Sie den folgenden Empfehlungen, um Rechenleistung zu sparen und Energie zu sparen:

  • Führen Sie Ihr ML-Modell nicht für jeden eingehenden Frame aus. Erwägen Sie stattdessen, die Objekterkennung mit einer niedrigen Framerate auszuführen.
  • Erwägen Sie ein Online-ML-Inferenzmodell, um die Rechenkomplexität zu reduzieren.

Nächste Schritte