ใช้ ARCore เป็นอินพุตสำหรับโมเดลแมชชีนเลิร์นนิง

คุณใช้ฟีดกล้องที่ ARCore บันทึกในไปป์ไลน์แมชชีนเลิร์นนิงเพื่อสร้างประสบการณ์ Augmented Reality อัจฉริยะได้ ตัวอย่าง ARCore ML Kit จะสาธิตวิธีใช้ ML Kit และ Google Cloud Vision API เพื่อระบุวัตถุในโลกจริง ตัวอย่างนี้ใช้โมเดลแมชชีนเลิร์นนิงเพื่อแยกประเภทวัตถุในมุมมองของกล้อง และติดป้ายกำกับไว้ที่วัตถุในฉากเสมือนจริง

ตัวอย่าง ARCore ML Kit เขียนด้วย Kotlin นอกจากนี้ยังพร้อมใช้งานเป็นแอปตัวอย่าง ml_kotlin ในที่เก็บ ARCore SDK ของ GitHub ด้วย

ใช้รูปภาพ CPU ของ ARCore

ARCore จะบันทึกสตรีมรูปภาพอย่างน้อย 2 ชุดโดยค่าเริ่มต้นดังนี้

  • สตรีมรูปภาพ CPU ที่ใช้สำหรับการจดจำฟีเจอร์และการประมวลผลรูปภาพ โดยค่าเริ่มต้น ภาพ CPU จะมีความละเอียดเป็น VGA (640x480) หากจำเป็น สามารถกำหนดค่า ARCore ให้ใช้สตรีมรูปภาพความละเอียดสูงขึ้นอีก
  • สตรีมพื้นผิวของ GPU ที่มีพื้นผิวความละเอียดสูง โดยปกติจะมีความละเอียดที่ 1080p ซึ่งมักจะใช้เป็นการแสดงตัวอย่างจากกล้องที่ผู้ใช้เห็น ซึ่งจัดเก็บไว้ในพื้นผิว OpenGL ที่ระบุโดย Session.setCameraTextureName()
  • สตรีมเพิ่มเติมที่ระบุโดย SharedCamera.setAppSurfaces()

ข้อควรพิจารณาเกี่ยวกับขนาดอิมเมจ CPU

ไม่มีค่าใช้จ่ายเพิ่มเติมหากใช้สตรีม CPU ขนาด VGA เริ่มต้น เนื่องจาก ARCore ใช้สตรีมนี้เพื่อทำความเข้าใจผู้คนทั่วโลก การขอสตรีมที่มีความละเอียดอื่นอาจมีค่าใช้จ่ายสูง เนื่องจากต้องบันทึกสตรีมเพิ่มเติม โปรดทราบว่าความละเอียดที่สูงขึ้นอาจทำให้โมเดลของคุณมีค่าใช้จ่ายสูงขึ้นอย่างรวดเร็ว กล่าวคือ การเพิ่มความกว้างและความสูงเป็น 2 เท่าจะเพิ่มจำนวนพิกเซลในรูปภาพถึง 4 เท่า

การลดลดขนาดรูปภาพอาจเป็นข้อดี หากโมเดลของคุณยังสามารถทำงานได้ดีกับรูปภาพที่มีความละเอียดต่ำ

กำหนดค่าสตรีมรูปภาพ CPU ความละเอียดสูงเพิ่มเติม

ประสิทธิภาพของโมเดล ML อาจขึ้นอยู่กับความละเอียดของรูปภาพที่ใช้เป็นอินพุต คุณปรับความละเอียดของสตรีมเหล่านี้ได้โดยเปลี่ยน CameraConfig ปัจจุบันโดยใช้ Session.setCameraConfig() แล้วเลือกการกำหนดค่าที่ถูกต้องจาก 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)

ดึงข้อมูลอิมเมจ CPU

ดึงข้อมูลอิมเมจ CPU โดยใช้ Frame.acquireCameraImage() คุณควรทิ้งรูปภาพเหล่านี้ทันทีที่ไม่จำเป็นต้องใช้แล้ว

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

คุณใช้ไลบรารีแมชชีนเลิร์นนิงหลายรายการเพื่อประมวลผลอิมเมจ CPU ได้

แสดงผลลัพธ์ในฉาก AR ของคุณ

โมเดลการจดจำภาพมักจะแสดงวัตถุที่ตรวจพบโดยการระบุจุดศูนย์กลางหรือรูปหลายเหลี่ยมล้อมรอบที่แสดงถึงวัตถุที่ตรวจพบ

เมื่อใช้จุดกึ่งกลางหรือกึ่งกลางของกรอบล้อมรอบที่เป็นเอาต์พุตจากโมเดล คุณจะสามารถแนบ Anchor กับวัตถุที่ตรวจพบได้ ใช้ Frame.hitTest() เพื่อประมาณท่าทางของวัตถุในฉากเสมือนจริง

แปลงพิกัดIMAGE_PIXELSเป็นพิกัด 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.

ใช้พิกัด VIEW เหล่านี้ในการทดสอบ Hit และสร้าง Anchor จากผลลัพธ์

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

ข้อพิจารณาด้านประสิทธิภาพ

ทำตามคำแนะนำต่อไปนี้เพื่อประหยัดพลังงานในการประมวลผลและใช้พลังงานน้อยลง

  • อย่าเรียกใช้โมเดล ML บนทุกเฟรมที่เข้ามาใหม่ ลองเรียกใช้การตรวจจับวัตถุที่อัตราเฟรมต่ำแทน
  • ลองใช้โมเดลการอนุมาน ML ออนไลน์เพื่อลดความซับซ้อนในการคํานวณ

ขั้นตอนถัดไป