Makine Öğrenimi modelleri için giriş olarak ARCore'u kullanma

ARCore'un makine öğrenimi ardışık düzeninde yakaladığı kamera feed'ini kullanarak akıllı bir artırılmış gerçeklik deneyimi oluşturabilirsiniz. ARCore ML Kit örneği, gerçek dünyadaki nesneleri tanımlamak için ML Kit ve Google Cloud Vision API'nin nasıl kullanılacağını gösterir. Örnek, kameranın gördüğü nesneleri sınıflandırmak için bir makine öğrenimi modeli kullanır ve sanal sahnedeki nesneye bir etiket ekler.

ARCore ML Kit örneği: bir hikaye anlatacağım. Ayrıca ml_kotlin örneği olarak da kullanılabilir. ARCore SDK'sındaki uygulama GitHub deposu.

ARCore'un CPU görüntüsünü kullan

ARCore, varsayılan olarak en az iki görüntü akışı grubunu yakalar:

  • Özellik tanıma ve görüntü işleme için kullanılan CPU görüntü akışı. CPU görüntüsü, varsayılan olarak VGA (640x480) çözünürlüğüne sahiptir. Gerekirse ARCore, daha yüksek çözünürlüklü ek bir görüntü akışı kullanacak şekilde yapılandırılabilir.
  • Genellikle 1080p çözünürlükte yüksek çözünürlüklü bir doku içeren GPU doku akışı. Bu, genellikle kullanıcıya yönelik kamera önizlemesi olarak kullanılır. Bu değer, Session.setCameraTextureName() tarafından belirtilen OpenGL dokusunda depolanır.
  • SharedCamera.setAppSurfaces() tarafından belirtilen tüm ek akışlar.

CPU resim boyutuyla ilgili dikkat edilmesi gereken noktalar

ARCore, içeriği anlamak için bu akışı kullandığından, varsayılan VGA boyutundaki CPU akışı kullanılırsa ek ücret alınmaz. Ek bir akışın yakalanması gerekeceğinden, farklı çözünürlükte bir yayın isteğinde bulunmak pahalı olabilir. Daha yüksek bir çözünürlüğün modeliniz için kısa sürede pahalıya gelebileceğini unutmayın: Resmin genişliğini ve yüksekliğini iki katına çıkarmak, resimdeki piksel miktarını dörde katlar.

Modeliniz daha düşük çözünürlüklü bir resimde de iyi performans gösterebiliyorsa resmin ölçeğini küçültmek avantajlı olabilir.

Ek bir yüksek çözünürlüklü CPU resim akışı yapılandırın

ML modelinizin performansı, giriş olarak kullanılan görüntünün çözünürlüğüne bağlı olabilir. Bu akışların çözünürlüğü, Session.setCameraConfig() aracılığıyla mevcut CameraConfig değiştirilip Session.getSupportedCameraConfigs() içinden geçerli bir yapılandırma seçilerek ayarlanabilir.

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 görüntüsünü al

Frame.acquireCameraImage() kullanarak CPU görüntüsünü alın. Bu görüntüler, artık ihtiyaç duyulmaz hale gelir gelmez imha edilmelidir.

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 görüntüsünü işle

CPU görüntüsünü işlemek için çeşitli makine öğrenimi kitaplıkları kullanılabilir.

Sonuçları artırılmış gerçeklik (AR) sahnenizde gösterin

Görüntü tanıma modelleri genellikle bir merkez noktası veya algılanan nesneyi temsil eden sınırlayıcı bir poligon belirterek algılanan nesnelerin çıktısını verir.

Modelden çıkan sınırlayıcı kutunun merkez noktası veya merkezi kullanılarak, algılanan nesneye bir bağlayıcı eklenebilir. Sanal sahnedeki bir nesnenin duruşunu tahmin etmek için Frame.hitTest() aracını kullanın.

IMAGE_PIXELS koordinatlarını VIEW koordinatlarına dönüştürün:

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.

İsabet testi yapmak ve sonuçtan bir çapa oluşturmak için şu VIEW koordinatlarını kullanın:

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

Performansla ilgili konular

İşlem gücünden tasarruf etmek ve daha az enerji tüketmek için aşağıdaki önerileri uygulayın:

  • ML modelinizi gelen her karede çalıştırmayın. Bunun yerine, nesne algılamayı düşük kare hızında çalıştırmayı düşünebilirsiniz.
  • İşlemsel karmaşıklığı azaltmak için online makine öğrenimi çıkarım modeli kullanmayı düşünün.

Sonraki adımlar