Sử dụng ARCore làm đầu vào cho các mô hình Học máy

Bạn có thể sử dụng nguồn cấp dữ liệu máy ảnh mà ARCore thu được trong đường dẫn máy học để tạo ra trải nghiệm thực tế tăng cường thông minh. Mẫu ARCore ML Kit trình bày cách sử dụng ML KitAPI Google Cloud Vision để xác định các đối tượng trong thế giới thực. Mẫu sử dụng mô hình học máy để phân loại các đối tượng trong chế độ xem của máy ảnh và gắn nhãn cho đối tượng trong cảnh ảo.

Mẫu ARCore ML Kit được viết bằng Kotlin. Nó cũng có sẵn dưới dạng ứng dụng mẫu ml_kotlin trong kho lưu trữ ARCore SDK GitHub.

Sử dụng hình ảnh CPU của ARCore

ARCore chụp ít nhất hai bộ luồng hình ảnh theo mặc định:

  • Luồng hình ảnh CPU được sử dụng để nhận dạng tính năng và xử lý hình ảnh. Theo mặc định, hình ảnh CPU có độ phân giải là VGA (640x480). ARCore có thể được định cấu hình để sử dụng luồng hình ảnh có độ phân giải cao hơn, nếu được yêu cầu.
  • Luồng kết cấu GPU , chứa kết cấu có độ phân giải cao, thường ở độ phân giải 1080p. Điều này thường được sử dụng làm bản xem trước máy ảnh trực diện người dùng. Điều này được lưu trữ trong kết cấu OpenGL được chỉ định bởi Session.setCameraTextureName() .
  • Bất kỳ luồng bổ sung nào được SharedCamera.setAppSurfaces() chỉ định.

Cân nhắc kích thước hình ảnh CPU

Không có chi phí bổ sung nào được phát sinh nếu sử dụng luồng CPU có kích thước VGA mặc định vì ARCore sử dụng luồng này để hiểu thế giới. Yêu cầu một luồng có độ phân giải khác có thể tốn kém, vì một luồng bổ sung sẽ cần được ghi lại. Hãy nhớ rằng độ phân giải cao hơn có thể nhanh chóng trở nên đắt đỏ đối với mô hình của bạn: tăng gấp đôi chiều rộng và chiều cao của hình ảnh sẽ làm tăng gấp bốn lần số lượng pixel trong hình ảnh.

Có thể có lợi khi giảm tỷ lệ hình ảnh, nếu mô hình của bạn vẫn có thể hoạt động tốt trên hình ảnh có độ phân giải thấp hơn.

Định cấu hình luồng hình ảnh CPU có độ phân giải cao bổ sung

Hiệu suất của mô hình ML của bạn có thể phụ thuộc vào độ phân giải của hình ảnh được sử dụng làm đầu vào. Độ phân giải của các luồng này có thể được điều chỉnh bằng cách thay đổi CameraConfig hiện tại bằng Session.setCameraConfig() , chọn cấu hình hợp lệ từ 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)

Lấy hình ảnh CPU

Lấy hình ảnh CPU bằng Frame.acquireCameraImage() . Những hình ảnh này nên được xử lý ngay khi chúng không còn cần thiết nữa.

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

Xử lý hình ảnh CPU

Để xử lý hình ảnh CPU, có thể sử dụng nhiều thư viện học máy khác nhau.

Hiển thị kết quả trong cảnh AR của bạn

Các mô hình nhận dạng hình ảnh thường xuất ra các đối tượng được phát hiện bằng cách chỉ ra một điểm trung tâm hoặc một đa giác giới hạn đại diện cho đối tượng được phát hiện.

Sử dụng điểm chính giữa hoặc tâm của hộp giới hạn được xuất ra từ mô hình, bạn có thể gắn một mỏ neo vào đối tượng được phát hiện. Sử dụng Frame.hitTest() để ước tính tư thế của một đối tượng trong cảnh ảo.

Chuyển đổi tọa độ IMAGE_PIXELS tọa độ 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.

Sử dụng các tọa độ VIEW này để tiến hành kiểm tra lượt truy cập và tạo neo từ kết quả:

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

Cân nhắc về hiệu suất

Thực hiện theo các khuyến nghị sau để tiết kiệm năng lượng xử lý và tiêu thụ ít năng lượng hơn:

  • Không chạy mô hình ML của bạn trên mọi khung hình đến. Thay vào đó, hãy cân nhắc chạy tính năng phát hiện đối tượng ở tốc độ khung hình thấp.
  • Hãy xem xét một mô hình suy luận ML trực tuyến để giảm độ phức tạp tính toán.

Bước tiếp theo