เมื่อคุณส่งภาพไปยัง ML Kit เครื่องมือจะตรวจจับวัตถุได้สูงสุด 5 รายการในภาพ พร้อมด้วยตำแหน่งของแต่ละวัตถุในภาพ เมื่อตรวจหาวัตถุในสตรีมวิดีโอ วัตถุแต่ละชิ้นจะมีรหัสที่ไม่ซ้ำกันซึ่งคุณใช้เพื่อติดตามวัตถุจากเฟรมหนึ่งไปยังอีกเฟรมหนึ่งได้
คุณสามารถใช้โมเดลการจัดประเภทรูปภาพที่กำหนดเองเพื่อแยกประเภทออบเจ็กต์ที่ตรวจพบ โปรดดูโมเดลที่กำหนดเองที่มี ML Kit เพื่อดูคำแนะนำเกี่ยวกับข้อกำหนดความเข้ากันได้ของโมเดล ตำแหน่งที่ฝึกโมเดลก่อนการฝึก และวิธีฝึกโมเดลของคุณเอง
คุณสามารถผสานรวมรูปแบบที่กำหนดเองได้ 2 วิธี คุณจะรวมโมเดลเข้าด้วยกันได้โดยใส่โมเดลไว้ในโฟลเดอร์เนื้อหาของแอป หรือจะดาวน์โหลดแบบไดนามิกจาก Firebase ก็ได้ ตารางต่อไปนี้จะเปรียบเทียบตัวเลือกทั้งสอง
โมเดลที่ให้มาด้วย | โมเดลที่โฮสต์ |
---|---|
รูปแบบนี้เป็นส่วนหนึ่งของ APK ของแอป ซึ่งจะเพิ่มขนาด | โมเดลนี้ไม่ได้เป็นส่วนหนึ่งของ APK ของคุณ โดยโฮสต์โดยการอัปโหลดไปยัง Firebase Machine Learning |
โมเดลนี้จะพร้อมใช้งานทันทีแม้ว่าอุปกรณ์ Android จะออฟไลน์อยู่ | มีการดาวน์โหลดโมเดลตามคำขอ |
ไม่จำเป็นต้องใช้โปรเจ็กต์ Firebase | ต้องมีโปรเจ็กต์ Firebase |
คุณต้องเผยแพร่แอปอีกครั้งเพื่ออัปเดตโมเดล | พุชการอัปเดตโมเดลโดยไม่ต้องเผยแพร่แอปอีกครั้ง |
ไม่มีการทดสอบ A/B ในตัว | การทดสอบ A/B ง่ายๆ ด้วยการกำหนดค่าระยะไกลของ Firebase |
ลองเลย
- โปรดดูแอป Vision Quickstart สำหรับตัวอย่างการใช้งานโมเดลแพ็กเกจและแอป Automl Quickstart สำหรับตัวอย่างการใช้งานโมเดลที่โฮสต์
- ดูแอปโชว์เคสดีไซน์ Material สำหรับการติดตั้งใช้งาน API นี้ตั้งแต่ต้นจนจบ
ก่อนเริ่มต้น
ในไฟล์
build.gradle
ระดับโปรเจ็กต์ ให้ตรวจสอบว่าได้ใส่ที่เก็บ Maven ของ Google ไว้ทั้งในส่วนbuildscript
และallprojects
เพิ่มทรัพยากร Dependency สำหรับไลบรารี Android ของ ML Kit ลงในไฟล์ Gradle ระดับแอปของโมดูล ซึ่งโดยปกติจะอยู่ที่
app/build.gradle
สำหรับการรวมโมเดลกับแอป ให้ทำดังนี้
dependencies { // ... // Object detection & tracking feature with custom bundled model implementation 'com.google.mlkit:object-detection-custom:17.0.2' }
หากต้องการดาวน์โหลดโมเดลแบบไดนามิกจาก Firebase ให้เพิ่มการอ้างอิง
linkFirebase
ดังนี้dependencies { // ... // Object detection & tracking feature with model downloaded // from firebase implementation 'com.google.mlkit:object-detection-custom:17.0.2' implementation 'com.google.mlkit:linkfirebase:17.0.0' }
หากต้องการดาวน์โหลดโมเดล ให้ตรวจสอบว่าคุณเพิ่ม Firebase ลงในโปรเจ็กต์ Android หากยังไม่ได้ทำ ขั้นตอนนี้ไม่จำเป็นเมื่อรวมโมเดลเข้าด้วยกัน
1. โหลดโมเดล
กำหนดค่าต้นทางของโมเดลในเครื่อง
วิธีรวมโมเดลเข้ากับแอป
คัดลอกไฟล์โมเดล (โดยปกติจะลงท้ายด้วย
.tflite
หรือ.lite
) ไปยังโฟลเดอร์assets/
ของแอป (คุณอาจต้องสร้างโฟลเดอร์ก่อนโดยคลิกขวาที่โฟลเดอร์app/
แล้วคลิกใหม่ > โฟลเดอร์ > โฟลเดอร์ชิ้นงาน)จากนั้นเพิ่มข้อมูลต่อไปนี้ลงในไฟล์
build.gradle
ของแอปเพื่อให้มั่นใจว่า Gradle จะไม่บีบอัดไฟล์โมเดลเมื่อสร้างแอปandroid { // ... aaptOptions { noCompress "tflite" // or noCompress "lite" } }
ไฟล์โมเดลจะรวมอยู่ในแพ็กเกจแอปและพร้อมให้เล่นใน ML Kit เป็นเนื้อหาดิบ
สร้างออบเจ็กต์
LocalModel
โดยระบุเส้นทางไปยังไฟล์โมเดล:Kotlin
val localModel = LocalModel.Builder() .setAssetFilePath("model.tflite") // or .setAbsoluteFilePath(absolute file path to model file) // or .setUri(URI to model file) .build()
Java
LocalModel localModel = new LocalModel.Builder() .setAssetFilePath("model.tflite") // or .setAbsoluteFilePath(absolute file path to model file) // or .setUri(URI to model file) .build();
กำหนดค่าแหล่งที่มาของโมเดลที่โฮสต์ใน Firebase
หากต้องการใช้โมเดลที่โฮสต์จากระยะไกล ให้สร้างออบเจ็กต์ CustomRemoteModel
ด้วย FirebaseModelSource
โดยระบุชื่อที่คุณกำหนดโมเดลเมื่อคุณเผยแพร่:
Kotlin
// Specify the name you assigned in the Firebase console. val remoteModel = CustomRemoteModel .Builder(FirebaseModelSource.Builder("your_model_name").build()) .build()
Java
// Specify the name you assigned in the Firebase console. CustomRemoteModel remoteModel = new CustomRemoteModel .Builder(new FirebaseModelSource.Builder("your_model_name").build()) .build();
จากนั้นเริ่มงานดาวน์โหลดโมเดล โดยระบุเงื่อนไขที่ต้องการอนุญาตให้ดาวน์โหลด หากโมเดลไม่ได้อยู่ในอุปกรณ์ หรือหากมีโมเดลเวอร์ชันใหม่ งานจะดาวน์โหลดโมเดลแบบไม่พร้อมกันจาก Firebase
Kotlin
val downloadConditions = DownloadConditions.Builder() .requireWifi() .build() RemoteModelManager.getInstance().download(remoteModel, downloadConditions) .addOnSuccessListener { // Success. }
Java
DownloadConditions downloadConditions = new DownloadConditions.Builder() .requireWifi() .build(); RemoteModelManager.getInstance().download(remoteModel, downloadConditions) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(@NonNull Task task) { // Success. } });
แอปจำนวนมากเริ่มต้นงานดาวน์โหลดในโค้ดการเริ่มต้น แต่คุณสามารถเริ่มงานได้ทุกเมื่อก่อนที่จะต้องใช้โมเดล
2. กำหนดค่าตัวตรวจจับออบเจ็กต์
หลังจากกำหนดค่าแหล่งที่มาของโมเดล ให้กำหนดค่าตัวตรวจจับออบเจ็กต์สำหรับ Use Case ของคุณด้วยออบเจ็กต์ CustomObjectDetectorOptions
คุณสามารถเปลี่ยนการตั้งค่าต่อไปนี้
การตั้งค่าตัวตรวจจับออบเจ็กต์ | |
---|---|
โหมดการตรวจจับ |
STREAM_MODE (ค่าเริ่มต้น) | SINGLE_IMAGE_MODE
ใน ใน |
ตรวจหาและติดตามออบเจ็กต์หลายรายการ |
false (ค่าเริ่มต้น) | true
ไม่ว่าจะตรวจหาและติดตามออบเจ็กต์สูงสุด 5 รายการ หรือเฉพาะออบเจ็กต์ที่โดดเด่นที่สุด (ค่าเริ่มต้น) |
จำแนกประเภทวัตถุ |
false (ค่าเริ่มต้น) | true
กำหนดว่าจะแยกประเภทออบเจ็กต์ที่ตรวจพบโดยใช้โมเดลตัวแยกประเภทที่กำหนดเองที่มีให้หรือไม่ หากต้องการใช้โมเดลการจัดประเภทที่กำหนดเอง คุณต้องตั้งค่าเป็น |
เกณฑ์ความเชื่อมั่นในการแยกประเภท |
คะแนนความเชื่อมั่นขั้นต่ำของป้ายกำกับที่ตรวจพบ หากไม่ได้ตั้งค่า ระบบจะใช้เกณฑ์ของตัวแยกประเภทที่ระบุโดยข้อมูลเมตาของโมเดล หากโมเดลไม่มีข้อมูลเมตาหรือข้อมูลเมตาไม่ได้ระบุเกณฑ์ของตัวแยกประเภท ระบบจะใช้เกณฑ์เริ่มต้นที่ 0.0 |
จำนวนป้ายกำกับสูงสุดต่อออบเจ็กต์ |
จำนวนป้ายกำกับสูงสุดต่อออบเจ็กต์ที่ตัวตรวจจับจะส่งคืน หากไม่ได้ตั้งค่า ระบบจะใช้ค่าเริ่มต้น 10 |
API การตรวจจับและการติดตามวัตถุได้รับการเพิ่มประสิทธิภาพเพื่อการใช้งานหลักๆ 2 กรณีดังนี้
- การตรวจจับแบบเรียลไทม์และการติดตามวัตถุที่โดดเด่นที่สุดในช่องมองภาพของกล้อง
- การตรวจจับวัตถุหลายรายการจากภาพนิ่ง
หากต้องการกำหนดค่า API สำหรับ Use Case เหล่านี้ด้วยโมเดลที่มากับเครื่อง ให้ทำดังนี้
Kotlin
// Live detection and tracking val customObjectDetectorOptions = CustomObjectDetectorOptions.Builder(localModel) .setDetectorMode(CustomObjectDetectorOptions.STREAM_MODE) .enableClassification() .setClassificationConfidenceThreshold(0.5f) .setMaxPerObjectLabelCount(3) .build() // Multiple object detection in static images val customObjectDetectorOptions = CustomObjectDetectorOptions.Builder(localModel) .setDetectorMode(CustomObjectDetectorOptions.SINGLE_IMAGE_MODE) .enableMultipleObjects() .enableClassification() .setClassificationConfidenceThreshold(0.5f) .setMaxPerObjectLabelCount(3) .build() val objectDetector = ObjectDetection.getClient(customObjectDetectorOptions)
Java
// Live detection and tracking CustomObjectDetectorOptions customObjectDetectorOptions = new CustomObjectDetectorOptions.Builder(localModel) .setDetectorMode(CustomObjectDetectorOptions.STREAM_MODE) .enableClassification() .setClassificationConfidenceThreshold(0.5f) .setMaxPerObjectLabelCount(3) .build(); // Multiple object detection in static images CustomObjectDetectorOptions customObjectDetectorOptions = new CustomObjectDetectorOptions.Builder(localModel) .setDetectorMode(CustomObjectDetectorOptions.SINGLE_IMAGE_MODE) .enableMultipleObjects() .enableClassification() .setClassificationConfidenceThreshold(0.5f) .setMaxPerObjectLabelCount(3) .build(); ObjectDetector objectDetector = ObjectDetection.getClient(customObjectDetectorOptions);
หากคุณมีโมเดลที่โฮสต์จากระยะไกล คุณจะต้องตรวจสอบว่าโมเดลดังกล่าวได้รับการดาวน์โหลดแล้วก่อนที่จะเรียกใช้ คุณจะตรวจสอบสถานะของงานการดาวน์โหลดโมเดลได้โดยใช้เมธอด isModelDownloaded()
ของตัวจัดการโมเดล
แม้ว่าคุณจะต้องยืนยันสิ่งนี้ก่อนที่จะเรียกใช้ตัวตรวจจับเท่านั้น แต่ถ้าคุณมีทั้งโมเดลที่โฮสต์จากระยะไกลและโมเดลที่รวมในเครื่อง คุณอาจต้องทำการตรวจสอบนี้เมื่อเริ่มต้นตัวตรวจจับรูปภาพ นั่นคือ สร้างตัวตรวจจับจากโมเดลระยะไกลหากดาวน์โหลดไว้แล้ว และจากโมเดลในเครื่อง
Kotlin
RemoteModelManager.getInstance().isModelDownloaded(remoteModel) .addOnSuccessListener { isDownloaded -> val optionsBuilder = if (isDownloaded) { CustomObjectDetectorOptions.Builder(remoteModel) } else { CustomObjectDetectorOptions.Builder(localModel) } val customObjectDetectorOptions = optionsBuilder .setDetectorMode(CustomObjectDetectorOptions.SINGLE_IMAGE_MODE) .enableClassification() .setClassificationConfidenceThreshold(0.5f) .setMaxPerObjectLabelCount(3) .build() val objectDetector = ObjectDetection.getClient(customObjectDetectorOptions) }
Java
RemoteModelManager.getInstance().isModelDownloaded(remoteModel) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(Boolean isDownloaded) { CustomObjectDetectorOptions.Builder optionsBuilder; if (isDownloaded) { optionsBuilder = new CustomObjectDetectorOptions.Builder(remoteModel); } else { optionsBuilder = new CustomObjectDetectorOptions.Builder(localModel); } CustomObjectDetectorOptions customObjectDetectorOptions = optionsBuilder .setDetectorMode(CustomObjectDetectorOptions.SINGLE_IMAGE_MODE) .enableClassification() .setClassificationConfidenceThreshold(0.5f) .setMaxPerObjectLabelCount(3) .build(); ObjectDetector objectDetector = ObjectDetection.getClient(customObjectDetectorOptions); } });
หากคุณมีเฉพาะโมเดลที่โฮสต์จากระยะไกล คุณควรปิดใช้ฟังก์ชันการทำงานเกี่ยวกับโมเดล เช่น ทำให้เป็นสีเทาหรือซ่อนบางส่วนของ UI จนกว่าคุณจะยืนยันว่าได้ดาวน์โหลดโมเดลแล้ว ซึ่งทำได้โดยการแนบ Listener ลงในเมธอด download()
ของตัวจัดการโมเดล ดังนี้
Kotlin
RemoteModelManager.getInstance().download(remoteModel, conditions) .addOnSuccessListener { // Download complete. Depending on your app, you could enable the ML // feature, or switch from the local model to the remote model, etc. }
Java
RemoteModelManager.getInstance().download(remoteModel, conditions) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(Void v) { // Download complete. Depending on your app, you could enable // the ML feature, or switch from the local model to the remote // model, etc. } });
3. เตรียมรูปภาพอินพุต
สร้างวัตถุInputImage
จากรูปภาพ
ตัวตรวจจับออบเจ็กต์จะทำงานจาก Bitmap
, NV21 ByteBuffer
หรือ media.Image
โดยตรง เราขอแนะนำให้สร้าง InputImage
จากแหล่งที่มาเหล่านั้น
หากคุณมีสิทธิ์เข้าถึงโดยตรง หากคุณสร้าง InputImage
จากแหล่งที่มาอื่นๆ เราจะจัดการ Conversion เป็นการภายในให้ และอาจมีประสิทธิภาพลดลง
คุณสร้างออบเจ็กต์ InputImage
จากแหล่งที่มาที่แตกต่างกันได้ โดยแต่ละรายการจะมีคำอธิบายอยู่ด้านล่าง
ใช้ media.Image
หากต้องการสร้างออบเจ็กต์ InputImage
จากออบเจ็กต์ media.Image
เช่น เมื่อคุณจับภาพจากกล้องของอุปกรณ์ ให้ส่งวัตถุ media.Image
และการหมุนรูปภาพไปยัง InputImage.fromMediaImage()
หากใช้ไลบรารี
CameraX คลาส OnImageCapturedListener
และ ImageAnalysis.Analyzer
จะคำนวณค่าการหมุนให้คุณ
Kotlin
private class YourImageAnalyzer : ImageAnalysis.Analyzer { override fun analyze(imageProxy: ImageProxy) { val mediaImage = imageProxy.image if (mediaImage != null) { val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees) // Pass image to an ML Kit Vision API // ... } } }
Java
private class YourAnalyzer implements ImageAnalysis.Analyzer { @Override public void analyze(ImageProxy imageProxy) { Image mediaImage = imageProxy.getImage(); if (mediaImage != null) { InputImage image = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees()); // Pass image to an ML Kit Vision API // ... } } }
หากไม่ได้ใช้คลังภาพที่มีระดับการหมุนของภาพ คุณจะคํานวณจากองศาการหมุนของอุปกรณ์และการวางแนวของเซ็นเซอร์กล้องในอุปกรณ์ได้ดังนี้
Kotlin
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 0) ORIENTATIONS.append(Surface.ROTATION_90, 90) ORIENTATIONS.append(Surface.ROTATION_180, 180) ORIENTATIONS.append(Surface.ROTATION_270, 270) } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(CameraAccessException::class) private fun getRotationCompensation(cameraId: String, activity: Activity, isFrontFacing: Boolean): Int { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. val deviceRotation = activity.windowManager.defaultDisplay.rotation var rotationCompensation = ORIENTATIONS.get(deviceRotation) // Get the device's sensor orientation. val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360 } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360 } return rotationCompensation }
Java
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 0); ORIENTATIONS.append(Surface.ROTATION_90, 90); ORIENTATIONS.append(Surface.ROTATION_180, 180); ORIENTATIONS.append(Surface.ROTATION_270, 270); } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private int getRotationCompensation(String cameraId, Activity activity, boolean isFrontFacing) throws CameraAccessException { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int rotationCompensation = ORIENTATIONS.get(deviceRotation); // Get the device's sensor orientation. CameraManager cameraManager = (CameraManager) activity.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360; } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360; } return rotationCompensation; }
จากนั้นส่งออบเจ็กต์ media.Image
และค่าองศาการหมุนไปที่ InputImage.fromMediaImage()
:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
การใช้ URI ของไฟล์
หากต้องการสร้างออบเจ็กต์ InputImage
จาก URI ของไฟล์ ให้ส่งบริบทของแอปและ URI ของไฟล์ไปยัง InputImage.fromFilePath()
ซึ่งจะเป็นประโยชน์เมื่อคุณใช้ Intent ACTION_GET_CONTENT
เพื่อแจ้งให้ผู้ใช้เลือกรูปภาพจากแอปแกลเลอรี
Kotlin
val image: InputImage try { image = InputImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
Java
InputImage image; try { image = InputImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
หากใช้ ByteBuffer
หรือ ByteArray
หากต้องการสร้างออบเจ็กต์ InputImage
จาก ByteBuffer
หรือ ByteArray
ให้คำนวณระดับการหมุนรูปภาพตามที่อธิบายไว้ก่อนหน้านี้สำหรับอินพุต media.Image
จากนั้นสร้างออบเจ็กต์ InputImage
ที่มีบัฟเฟอร์หรืออาร์เรย์ พร้อมความสูง ความกว้าง รูปแบบการเข้ารหัสสี และระดับการหมุนของรูปภาพ ดังนี้
Kotlin
val image = InputImage.fromByteBuffer( byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ) // Or: val image = InputImage.fromByteArray( byteArray, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 )
Java
InputImage image = InputImage.fromByteBuffer(byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ); // Or: InputImage image = InputImage.fromByteArray( byteArray, /* image width */480, /* image height */360, rotation, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 );
ใช้ Bitmap
หากต้องการสร้างออบเจ็กต์ InputImage
จากออบเจ็กต์ Bitmap
ให้ประกาศต่อไปนี้
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
รูปภาพแสดงด้วยวัตถุ Bitmap
ร่วมกับองศาการหมุน
4. เรียกใช้ตัวตรวจจับวัตถุ
Kotlin
objectDetector .process(image) .addOnFailureListener(e -> {...}) .addOnSuccessListener(results -> { for (detectedObject in results) { // ... } });
Java
objectDetector .process(image) .addOnFailureListener(e -> {...}) .addOnSuccessListener(results -> { for (DetectedObject detectedObject : results) { // ... } });
5. รับข้อมูลเกี่ยวกับออบเจ็กต์ที่ติดป้ายกำกับ
หากการเรียก process()
สำเร็จ ระบบจะส่งรายการ DetectedObject
ไปยังผู้ฟังที่ประสบความสำเร็จ
DetectedObject
แต่ละรายการจะมีพร็อพเพอร์ตี้ต่อไปนี้
กรอบล้อมรอบ | Rect ที่แสดงตำแหน่งของวัตถุในรูปภาพ |
||||||
รหัสติดตาม | จำนวนเต็มที่ระบุวัตถุในรูปภาพต่างๆ Null ใน SINGLE_IMAGE_mode | ||||||
ป้ายกำกับ |
|
Kotlin
// The list of detected objects contains one item if multiple // object detection wasn't enabled. for (detectedObject in results) { val boundingBox = detectedObject.boundingBox val trackingId = detectedObject.trackingId for (label in detectedObject.labels) { val text = label.text val index = label.index val confidence = label.confidence } }
Java
// The list of detected objects contains one item if multiple // object detection wasn't enabled. for (DetectedObject detectedObject : results) { Rect boundingBox = detectedObject.getBoundingBox(); Integer trackingId = detectedObject.getTrackingId(); for (Label label : detectedObject.getLabels()) { String text = label.getText(); int index = label.getIndex(); float confidence = label.getConfidence(); } }
ช่วยให้ผู้ใช้ได้รับประสบการณ์ที่ดี
เพื่อให้ผู้ใช้ได้รับประสบการณ์ที่ดีที่สุด โปรดปฏิบัติตามหลักเกณฑ์ต่อไปนี้ในแอป
- การตรวจจับวัตถุที่จะประสบความสำเร็จขึ้นอยู่กับความซับซ้อนของภาพของวัตถุ หากต้องการให้ตรวจพบ วัตถุที่มีฟีเจอร์แบบภาพจำนวนเล็กน้อยอาจต้องใช้พื้นที่เก็บรูปภาพส่วนใหญ่ คุณควรให้คำแนะนำแก่ผู้ใช้เกี่ยวกับการบันทึกข้อมูลที่ทำงานได้ดีที่สุดกับประเภทวัตถุที่คุณต้องการตรวจจับ
- เมื่อคุณใช้การแยกประเภท หากต้องการตรวจหาออบเจ็กต์ที่ไม่ตรงกับหมวดหมู่ที่รองรับ ให้ใช้การจัดการพิเศษสำหรับออบเจ็กต์ที่ไม่รู้จัก
นอกจากนี้ ลองไปที่ แอปแสดงดีไซน์ Material ของ ML Kit และคอลเล็กชัน ดีไซน์ Material สำหรับฟีเจอร์ที่ขับเคลื่อนโดยแมชชีนเลิร์นนิง
Improving performance
หากคุณต้องการใช้การตรวจจับวัตถุในแอปพลิเคชันแบบเรียลไทม์ ให้ทำตามหลักเกณฑ์ต่อไปนี้เพื่อให้ได้อัตราเฟรมที่ดีที่สุดเมื่อคุณใช้โหมดสตรีมมิงในแอปพลิเคชันแบบเรียลไทม์ อย่าใช้การตรวจจับออบเจ็กต์หลายรายการ เนื่องจากอุปกรณ์ส่วนใหญ่จะไม่สามารถสร้างอัตราเฟรมที่เหมาะสมได้
- หากคุณใช้
Camera
หรือcamera2
API ให้ควบคุมการเรียกใช้ตัวตรวจจับ หากเฟรมวิดีโอใหม่พร้อมใช้งานขณะที่ตัวตรวจจับกำลังทำงาน ให้วางเฟรมลง ดูคลาสVisionProcessorBase
ในแอปตัวอย่าง Quickstart - หากคุณใช้
CameraX
API โปรดตรวจสอบว่าได้ตั้งค่ากลยุทธ์ Backpressure ไว้เป็นค่าเริ่มต้นImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
ซึ่งจะช่วยรับประกันว่าระบบจะนำส่งรูปภาพเพียง 1 รูปเพื่อทำการวิเคราะห์ต่อครั้ง หากมีการสร้างรูปภาพเพิ่มเติมเมื่อเครื่องมือวิเคราะห์ไม่ว่าง ระบบจะนำรูปภาพเหล่านั้นออกโดยอัตโนมัติและไม่เข้าคิวสำหรับการนำส่ง เมื่อปิดรูปภาพที่วิเคราะห์แล้วโดยเรียกใช้ ImageProxy.close() ระบบจะส่งรูปภาพล่าสุดถัดไป - หากคุณใช้เอาต์พุตจากตัวตรวจจับเพื่อวางซ้อนกราฟิกบนรูปภาพอินพุต ให้รับผลลัพธ์จาก ML Kit ก่อน จากนั้นจึงแสดงผลรูปภาพและการวางซ้อนในขั้นตอนเดียว ซึ่งจะแสดงผลบนพื้นผิวแสดงผลเพียงครั้งเดียวต่อเฟรมอินพุตแต่ละเฟรม ดูคลาส
CameraSourcePreview
และGraphicOverlay
ในแอปตัวอย่างสำหรับการเริ่มต้นใช้งานอย่างรวดเร็ว - หากคุณใช้ Camera2 API ให้จับภาพในรูปแบบ
ImageFormat.YUV_420_888
หากคุณใช้ Camera API เวอร์ชันเก่า ให้จับภาพในรูปแบบImageFormat.NV21