Usar a profundidade bruta no app Android

A API Raw Depth fornece dados de profundidade para uma imagem de câmera com maior precisão do que os dados completos dessa API, mas nem sempre cobre todos os pixels. As imagens de profundidade bruta e as de confiança correspondentes também podem ser processadas, permitindo que os apps usem apenas os dados de profundidade com precisão suficiente para o caso de uso individual.

Compatibilidade do dispositivo

Esse recurso está disponível em todos os dispositivos com suporte à API Depth. A API Raw Depth, assim como a API Depth completa, não requer um sensor de profundidade de hardware compatível, como um sensor de tempo de voo (ToF). No entanto, tanto a API Raw Depth quanto a API Depth completa usam todos os sensores de hardware compatíveis que um dispositivo possa ter.

API Raw Depth x API Full Depth

A API Raw Depth fornece estimativas de profundidade com maior precisão, mas as imagens de profundidade brutas podem não incluir estimativas de profundidade para todos os pixels na imagem da câmera. Por outro lado, a API Depth completa oferece profundidade estimada para cada pixel, mas os dados de profundidade por pixel podem ser menos precisos devido à suavização e interpolação das estimativas de profundidade. O formato e o tamanho das imagens de profundidade são os mesmos nas duas APIs. Apenas o conteúdo é diferente.

A tabela a seguir ilustra as diferenças entre a API Raw Depth e a API Depth completa usando uma imagem de uma cadeira e de uma mesa na cozinha.

API Retorna Imagem da câmera Profundidade da imagem Imagem de confiança
API Raw Depth
  • Uma imagem de profundidade bruta que contém uma estimativa de profundidade muito precisa para alguns pixels, mas não todos.
  • Uma imagem de confiança que proporciona a confiança para cada pixel de imagem com profundidade bruta. Os pixels da imagem da câmera que não têm uma estimativa de profundidade têm uma confiança igual a zero.
API Full Depth
  • Uma única música imagem de profundidade que contém uma estimativa de profundidade para cada pixel.
  • Nenhuma imagem de confiança é fornecida com essa API.
N/A

Imagens de confiança

Em imagens confiáveis retornadas pela API Raw Depth, os pixels mais claros têm valores de confiança mais altos, sendo que os pixels brancos representam confiança total e os pixels pretos representam confiança total. Em geral, as regiões na imagem da câmera que têm mais textura, como uma árvore, terão maior confiança de profundidade bruta do que regiões que não têm, como uma parede em branco. Superfícies sem textura geralmente produzem uma confiança de zero.

Se o dispositivo de destino tiver um sensor de profundidade de hardware compatível, a confiança em áreas da imagem próximas o suficiente da câmera provavelmente será maior, mesmo em superfícies sem textura.

Custo do Compute

O custo de computação da API Raw Depth é cerca de metade do custo de computação da API Depth completa.

Casos de uso

Com a API Raw Depth, você pode acessar imagens de profundidade que oferecem uma representação mais detalhada da geometria dos objetos na cena. Os dados de profundidade brutos podem ser úteis na criação de experiências de RA em que o aumento da precisão e dos detalhes de profundidade são necessários para tarefas de compreensão de geometria. Estes são alguns exemplos de casos de uso:

  • Reconstrução 3D
  • Medição
  • Detecção de formas

Pré-requisitos

Entenda os conceitos fundamentais de RA. e como configurar uma sessão do ARCore antes de continuar.

Ativar profundidade

Em uma nova sessão do ARCore, confira se o dispositivo do usuário é compatível com a Profundidade. Nem todos os dispositivos compatíveis com ARCore têm suporte à API Depth devido a restrições de capacidade de processamento. Para economizar recursos, a profundidade é desativada por padrão no ARCore. Ative o modo de profundidade para que o app use a API Depth.

Java

Config config = session.getConfig();

// Check whether the user's device supports Depth.
if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {
  // Enable depth mode.
  config.setDepthMode(Config.DepthMode.AUTOMATIC);
}
session.configure(config);

Kotlin

if (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) {
  session.configure(session.config.apply { depthMode = Config.DepthMode.AUTOMATIC })
}

Consiga as imagens de confiança e profundidade brutas mais recentes

Chame frame.acquireRawDepthImage16Bits() para receber a imagem de profundidade bruta mais recente. Nem todos os pixels de imagem retornados pela API Raw Depth terão dados de profundidade, e nem todos os frames do ARCore terão uma nova imagem de profundidade bruta. Para determinar se a imagem de profundidade bruta do frame atual é nova, compare o carimbo de data/hora com o da imagem de profundidade bruta anterior. Se os carimbos de data/hora forem diferentes, a imagem de profundidade bruta será baseada nos novos dados de profundidade. Caso contrário, a imagem de profundidade será uma reprojeção dos dados de profundidade anteriores.

Chame frame.acquireRawDepthConfidenceImage() para conseguir a imagem de confiança. É possível usar a imagem de confiança para verificar a precisão de cada pixel de profundidade bruto. As imagens de confiança são retornadas no formato Y8. Cada pixel é um número inteiro não assinado de 8 bits. 0 indica a menor confiança, enquanto 255 indica mais.

Java

// Use try-with-resources, so that images are released automatically.
try (
// Depth image is in uint16, at GPU aspect ratio, in native orientation.
Image rawDepth = frame.acquireRawDepthImage16Bits();
    // Confidence image is in uint8, matching the depth image size.
    Image rawDepthConfidence = frame.acquireRawDepthConfidenceImage(); ) {
  // Compare timestamps to determine whether depth is is based on new
  // depth data, or is a reprojection based on device movement.
  boolean thisFrameHasNewDepthData = frame.getTimestamp() == rawDepth.getTimestamp();
  if (thisFrameHasNewDepthData) {
    ByteBuffer depthData = rawDepth.getPlanes()[0].getBuffer();
    ByteBuffer confidenceData = rawDepthConfidence.getPlanes()[0].getBuffer();
    int width = rawDepth.getWidth();
    int height = rawDepth.getHeight();
    someReconstructionPipeline.integrateNewImage(depthData, confidenceData, width, height);
  }
} catch (NotYetAvailableException e) {
  // Depth image is not (yet) available.
}

Kotlin

try {
  // Depth image is in uint16, at GPU aspect ratio, in native orientation.
  frame.acquireRawDepthImage16Bits().use { rawDepth ->
    // Confidence image is in uint8, matching the depth image size.
    frame.acquireRawDepthConfidenceImage().use { rawDepthConfidence ->
      // Compare timestamps to determine whether depth is is based on new
      // depth data, or is a reprojection based on device movement.
      val thisFrameHasNewDepthData = frame.timestamp == rawDepth.timestamp
      if (thisFrameHasNewDepthData) {
        val depthData = rawDepth.planes[0].buffer
        val confidenceData = rawDepthConfidence.planes[0].buffer
        val width = rawDepth.width
        val height = rawDepth.height
        someReconstructionPipeline.integrateNewImage(
          depthData,
          confidenceData,
          width = width,
          height = height
        )
      }
    }
  }
} catch (e: NotYetAvailableException) {
  // Depth image is not (yet) available.
}

O que vem em seguida?