Używanie nieprzetworzonej głębi w aplikacji na Androida

Interfejs Raw Depth API dostarcza dane o głębi zdjęcia z aparatu, które ma większą dokładność niż pełne dane Depth API, ale nie zawsze obejmuje każdy piksel. Nieprzetworzone obrazy głębi wraz z pasującymi do nich obrazami ufności mogą być dalej przetwarzane. Dzięki temu aplikacje mogą korzystać tylko z danych szczegółowych, które są dostosowane do danego przypadku użycia.

Zgodność urządzeń

Nieprzetworzona głębokość jest dostępna na wszystkich urządzeniach obsługujących Depth API. Interfejs Raw Depth API, podobnie jak Full Depth API, nie wymaga obsługiwanego sprzętowego czujnika głębokości, takiego jak czujnik czasu lotu. Zarówno interfejs Raw Depth API, jak i Full Depth API korzystają jednak z obsługiwanych czujników sprzętowych, które może posiadać urządzenie.

Porównanie interfejsu Raw Depth API z pełnym interfejsem Depth API

Interfejs Raw Depth API umożliwia szacowanie głębi z większą dokładnością, ale zdjęcia nieprzetworzone mogą nie zawierać szacunków dla wszystkich pikseli na zdjęciu z aparatu. Z kolei pełny interfejs Depth API podaje szacunkową głębię każdego piksela, ale dane dotyczące głębokości piksela mogą być mniej dokładne z powodu wygładzania i interpolacji szacowania głębi. Format i rozmiar obrazów głębi są takie same w obu interfejsach API. Różni się tylko treść.

W tabeli poniżej pokazujemy różnice między interfejsem Raw Depth API a pełnym interfejsem Depth API za pomocą zdjęcia krzesła i stół w kuchni.

API Akcje powrotne Zdjęcie z aparatu Obraz głębi Obraz pewności
Interfejs API Raw Depth
  • Nieprzetworzone zdjęcie z bardzo dokładnym oszacowaniem głębi dla niektórych (ale nie wszystkich) pikseli na zdjęciu.
  • Obraz pewności, który daje pewność przy każdym pikselu obrazu z nieprzetworzoną głębią. Piksele obrazu z aparatu, dla których nie określono szacowanej głębi, mają pewność o wartości 0.
Interfejs API Full Depth
  • Pojedyncze zdjęcie „wygładzone” z oszacowaną głębią dla każdego piksela.
  • Ten interfejs API nie dostarcza obrazu pewności.
Nie dotyczy

Obrazy potwierdzające pewność

Obrazy z nakładem ufności zwracane przez interfejs Raw Depth API – jaśniejsze piksele mają wyższe wartości ufności, przy czym białe piksele reprezentują pełną pewność, a czarne – brak pewności. Ogólnie obszary na zdjęciu z aparatu, które mają więcej tekstury, takie jak drzewo, mają większą pewność nieprzetworzonej głębi niż obszary, które tego nie robią, np. pusta ściana. Powierzchnie bez tekstury mają zwykle wartość zero.

Jeśli urządzenie docelowe ma obsługiwany sprzętowy czujnik głębokości, poziom ufności w obszarach wystarczająco blisko aparatu będzie prawdopodobnie wyższy, nawet na powierzchniach bez tekstur.

Koszt mocy obliczeniowej

Koszt mocy obliczeniowej interfejsu Raw Depth API to około połowy kosztów mocy obliczeniowej interfejsu Depth API.

Przypadki użycia

Za pomocą interfejsu Raw Depth API możesz uzyskiwać obrazy głębi, które dokładniej przedstawiają geometrię obiektów prezentowanych na scenie. Nieprzetworzone dane o głębi mogą być przydatne podczas tworzenia doświadczeń AR, w których zadania polegające na zrozumieniu geometrii wymagają większej dokładności i szczegółów szczegółowości. Przykłady użycia:

  • Rekonstrukcja 3D
  • Pomiary
  • Wykrywanie kształtów

Wymagania wstępne

Zanim przejdziesz dalej, upewnij się, że znasz podstawowe pojęcia związane z AR i wiesz, jak skonfigurować sesję ARCore.

Włącz głębię

W nowej sesji ARCore sprawdź, czy urządzenie użytkownika obsługuje Depth. Z powodu ograniczeń mocy obliczeniowej nie wszystkie urządzenia zgodne z ARCore obsługują interfejs Depth API. Aby oszczędzać zasoby, głębia jest domyślnie wyłączona w ARCore. Włącz tryb głębi, aby aplikacja używała interfejsu Depth API.

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

Pobierz najnowsze obrazy nieprzetworzone

Wywołaj frame.acquireRawDepthImage16Bits(), aby uzyskać najnowsze zdjęcie nieprzetworzone. Nie wszystkie piksele obrazu zwrócone przez interfejs Raw Depth API zawierają dane o głębi. Nie każda ramka ARCore będzie zawierać nowy obraz nieprzetworzonej głębi. Aby sprawdzić, czy obraz nieprzetworzonej głębi dla bieżącej klatki jest nowy, porównaj jego sygnaturę czasową z sygnaturą czasową poprzedniego zdjęcia nieprzetworzonej głębi. Jeśli sygnatury czasowe są różne, nieprzetworzony obraz głębi jest generowany na podstawie nowych danych o głębi. W przeciwnym razie zdjęcie głębi jest odzwierciedleniem poprzednich danych o głębokości.

Wywołaj frame.acquireRawDepthConfidenceImage(), aby uzyskać obraz ufności. Obraz ufności pozwala sprawdzić dokładność każdego piksela nieprzetworzonej głębi. Obrazy ufności są zwracane w formacie Y8. Każdy piksel jest 8-bitową nieoznaczoną liczbą całkowitą. Wartość 0 wskazuje najmniejszy poziom ufności, a 255 – najwyższy.

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

Co dalej?