คุณใช้ฟีดกล้องที่ 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 ได้
- ML Kit: ML Kit มี API การตรวจจับวัตถุและการติดตามในอุปกรณ์
โดยมาพร้อมกับตัวแยกประเภทแบบหยาบๆ ที่มีอยู่ใน API และยังสามารถใช้โมเดลการแยกประเภทที่กำหนดเองเพื่อให้ครอบคลุมโดเมนวัตถุที่แคบลง
ใช้
InputImage.fromMediaImage
เพื่อแปลงอิมเมจ CPU เป็นInputImage
- Firebase Machine Learning: Firebase มี Machine Learning API ที่ทำงานได้ทั้งในระบบคลาวด์หรือในอุปกรณ์ ดูเอกสารเกี่ยวกับ Firebase เกี่ยวกับการติดป้ายกำกับรูปภาพอย่างปลอดภัยด้วย Cloud Vision โดยใช้การตรวจสอบสิทธิ์และฟังก์ชันของ Firebase ใน Android
แสดงผลลัพธ์ในฉาก 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 ออนไลน์เพื่อลดความซับซ้อนในการคํานวณ
ขั้นตอนถัดไป
- ดูข้อมูลเกี่ยวกับแนวทางปฏิบัติแนะนำสำหรับวิศวกรรม ML
- ดูข้อมูลเกี่ยวกับแนวทางปฏิบัติเกี่ยวกับ AI อย่างมีความรับผิดชอบ
- ทำตามพื้นฐานของแมชชีนเลิร์นนิงด้วยหลักสูตร TensorFlow