Usa ARCore como entrada para modelos de aprendizaje automático

Puedes usar el feed de la cámara que captura ARCore en una canalización de aprendizaje automático para crear una experiencia de realidad aumentada inteligente. En la muestra del kit de AA de ARCore, se muestra cómo usar el kit de AA y la API de Google Cloud Vision para identificar objetos del mundo real. En el ejemplo, se usa un modelo de aprendizaje automático para clasificar objetos en la vista de la cámara y se le adjunta una etiqueta al objeto de la escena virtual.

La muestra del kit de AA de ARCore está escrita en Kotlin. También está disponible como la app de muestra ml_kotlin en el repositorio de GitHub del SDK de ARCore.

Usa la imagen de CPU de ARCore

ARCore captura al menos dos conjuntos de transmisiones de imágenes de forma predeterminada:

  • Un flujo de imágenes de CPU que se usa para el reconocimiento de atributos y el procesamiento de imágenes. De forma predeterminada, la imagen de la CPU tiene una resolución VGA (640 x 480). Si es necesario, ARCore se puede configurar para que use una transmisión de imágenes de mayor resolución.
  • Una transmisión de textura de GPU, que contiene una textura de alta resolución, por lo general, con una resolución de 1080p. Por lo general, se usa como una vista previa de la cámara orientada al usuario. Se almacena en la textura OpenGL especificada por Session.setCameraTextureName().
  • Cualquier transmisión adicional especificada por SharedCamera.setAppSurfaces().

Consideraciones sobre el tamaño de imagen de la CPU

No se incurre en costos adicionales si se usa la transmisión de CPU de tamaño VGA predeterminado porque ARCore la usa para comprender el mundo. Solicitar una transmisión con una resolución diferente puede ser costoso, ya que se deberá capturar una transmisión adicional. Ten en cuenta que una resolución más alta puede volverse costosa rápidamente para tu modelo: al duplicar el ancho y la altura de la imagen, se cuadruplica la cantidad de píxeles en ella.

Puede ser beneficioso reducir la escala de la imagen si el modelo aún puede tener un buen rendimiento en una imagen de menor resolución.

Configura una transmisión de imagen de CPU de alta resolución adicional

El rendimiento de tu modelo de AA puede depender de la resolución de la imagen que se usa como entrada. Para ajustar la resolución de las transmisiones, cambia el CameraConfig actual con Session.setCameraConfig() y selecciona una configuración válida de 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 la imagen de la CPU

Recupera la imagen de la CPU con Frame.acquireCameraImage(). Estas imágenes deben eliminarse en cuanto ya no sean necesarias.

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

Procesa la imagen de la CPU

Para procesar la imagen de la CPU, se pueden usar varias bibliotecas de aprendizaje automático.

Muestra resultados en tu escena de RA

Los modelos de reconocimiento de imágenes a menudo generan objetos detectados indicando un punto central o un polígono de límite que representa el objeto detectado.

Con el punto central o el centro del cuadro delimitador que se obtiene del modelo, es posible adjuntar un ancla al objeto detectado. Usa Frame.hitTest() para estimar la pose de un objeto en la escena virtual.

Convierte las coordenadas IMAGE_PIXELS en 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.

Usa estas coordenadas VIEW para realizar una prueba de posicionamiento y crear un ancla a partir del resultado:

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

Consideraciones de rendimiento

Sigue las siguientes recomendaciones para ahorrar energía de procesamiento y consumir menos energía:

  • No ejecutes tu modelo de AA en cada fotograma entrante. Considera ejecutar la detección de objetos a una velocidad de fotogramas baja.
  • Considera un modelo de inferencia de AA en línea para reducir la complejidad computacional.

Próximos pasos