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 inteligente de realidad aumentada. La muestra del Kit de AA de ARCore demuestra cómo usar el Kit de AA y la API de Google Cloud Vision para identificar objetos del mundo real. En este 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 en la escena virtual.

La muestra del ML Kit de ARCore es escritas en Kotlin. También está disponible como el ejemplo ml_kotlin. app en el SDK de ARCore Repositorio de GitHub.

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 funciones y el procesamiento de imágenes De forma predeterminada, la imagen de la CPU tiene una resolución de VGA (640 x 480). Se puede configurar ARCore para usar una transmisión de imágenes adicional de mayor resolución, si es necesario.
  • Flujo de texturas de GPU, que contiene una textura de alta resolución, generalmente en una resolución de 1080p. Por lo general, se usa como una vista previa de la cámara para el usuario. Esto se almacena en la textura de OpenGL que especifica Session.setCameraTextureName().
  • Cualquier transmisión adicional especificada por SharedCamera.setAppSurfaces()

Consideraciones sobre el tamaño de la imagen de la CPU

No se generan costos adicionales si se usa la transmisión de CPU predeterminada con tamaño VGA, ya que ARCore usa esta transmisión para la comprensión del 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 resultar costosa para tu modelo en poco tiempo: duplicar el ancho y la altura de la imagen cuadruplica su cantidad de píxeles.

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.

Cómo configurar una transmisión de imágenes adicional de alta resolución de la CPU

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 estas 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 CPU

Recupera la imagen de CPU con Frame.acquireCameraImage(). Debes desechar estas imágenes cuando 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 los resultados en tu escena de RA

Los modelos de reconocimiento de imágenes a menudo muestran 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 genera el modelo, es posible fijar 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. En su lugar, considera ejecutar la detección de objetos con una velocidad de fotogramas baja.
  • Considerar un modelo de inferencia de AA en línea para reducir la complejidad computacional.

Próximos pasos