ติดป้ายกำกับรูปภาพด้วยโมเดลที่กำหนดเองใน Android

คุณใช้ ML Kit เพื่อจดจำเอนทิตีในรูปภาพและติดป้ายกำกับได้ API นี้รองรับโมเดลการจัดประเภทรูปภาพที่กำหนดเองอย่างหลากหลาย โปรดอ่านโมเดลที่กำหนดเองที่มี ML Kit เพื่อดูคำแนะนำเกี่ยวกับข้อกำหนดความเข้ากันได้ของโมเดล ตำแหน่งที่ฝึกโมเดลก่อนการฝึก และวิธีฝึกโมเดลของคุณเอง

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

รวมกลุ่มไม่ได้จัดกลุ่ม
ชื่อไลบรารีcom.google.mlkit:image-labeling-customcom.google.android.gms:play-services-mlkit-image-labeling-custom
การใช้งานไปป์ไลน์จะลิงก์กับแอปของคุณแบบคงที่ ณ เวลาบิลด์ระบบจะดาวน์โหลดไปป์ไลน์แบบไดนามิกผ่านบริการ Google Play
ขนาดแอปขนาดเพิ่มขึ้นประมาณ 3.8 MBเพิ่มขนาดได้ประมาณ 200 KB
เวลาเริ่มไปป์ไลน์จะพร้อมใช้ทันทีอาจต้องรอให้ดาวน์โหลดไปป์ไลน์ก่อนใช้งานครั้งแรก
ขั้นของวงจร APIเวอร์ชันสำหรับผู้ใช้ทั่วไป (GA)เบต้า

การผสานรวมโมเดลที่กำหนดเองทำได้ 2 วิธี ได้แก่ รวมโมเดลโดยใส่ไว้ในโฟลเดอร์เนื้อหาของแอป หรือดาวน์โหลดจาก Firebase แบบไดนามิก ตารางต่อไปนี้จะเปรียบเทียบตัวเลือกทั้งสอง

โมเดลที่ให้มาด้วย โมเดลที่โฮสต์
รูปแบบนี้เป็นส่วนหนึ่งของ APK ของแอป ซึ่งจะเพิ่มขนาด โมเดลนี้ไม่ได้เป็นส่วนหนึ่งของ APK ของคุณ โดยโฮสต์โดยการอัปโหลดไปยัง Firebase Machine Learning
โมเดลนี้จะพร้อมใช้งานทันทีแม้ว่าอุปกรณ์ Android จะออฟไลน์อยู่ มีการดาวน์โหลดโมเดลตามคำขอ
ไม่จำเป็นต้องใช้โปรเจ็กต์ Firebase ต้องมีโปรเจ็กต์ Firebase
คุณต้องเผยแพร่แอปอีกครั้งเพื่ออัปเดตโมเดล พุชการอัปเดตโมเดลโดยไม่ต้องเผยแพร่แอปอีกครั้ง
ไม่มีการทดสอบ A/B ในตัว การทดสอบ A/B ง่ายๆ ด้วยการกำหนดค่าระยะไกลของ Firebase

ลองเลย

  • โปรดดูแอป Vision Quickstart สำหรับตัวอย่างการใช้งานโมเดลแพ็กเกจและแอป Automl Quickstart สำหรับตัวอย่างการใช้งานโมเดลที่โฮสต์

ก่อนเริ่มต้น

  1. ในไฟล์ build.gradle ระดับโปรเจ็กต์ ให้ตรวจสอบว่าได้ใส่ที่เก็บ Maven ของ Google ไว้ทั้งในส่วน buildscript และ allprojects

  2. เพิ่มทรัพยากร Dependency สำหรับไลบรารี Android ของ ML Kit ลงในไฟล์ Gradle ระดับแอปของโมดูล ซึ่งโดยปกติจะอยู่ที่ app/build.gradle เลือกทรัพยากร Dependency ต่อไปนี้ 1 รายการตามความต้องการของคุณ

    สำหรับการรวมไปป์ไลน์กับแอป ให้ทำดังนี้

    dependencies {
      // ...
      // Use this dependency to bundle the pipeline with your app
      implementation 'com.google.mlkit:image-labeling-custom:17.0.2'
    }
    

    สำหรับการใช้ไปป์ไลน์ในบริการ Google Play

    dependencies {
      // ...
      // Use this dependency to use the dynamically downloaded pipeline in Google Play Services
      implementation 'com.google.android.gms:play-services-mlkit-image-labeling-custom:16.0.0-beta5'
    }
    
  3. หากเลือกใช้ไปป์ไลน์ในบริการ Google Play คุณสามารถกำหนดค่าแอปให้ดาวน์โหลดไปป์ไลน์ลงในอุปกรณ์โดยอัตโนมัติหลังจากติดตั้งแอปจาก Play Store แล้ว โดยเพิ่มประกาศต่อไปนี้ในไฟล์ AndroidManifest.xml ของแอป

    <application ...>
        ...
        <meta-data
            android:name="com.google.mlkit.vision.DEPENDENCIES"
            android:value="custom_ica" />
        <!-- To use multiple downloads: android:value="custom_ica,download2,download3" -->
    </application>
    

    นอกจากนี้คุณยังตรวจสอบความพร้อมใช้งานของไปป์ไลน์อย่างชัดแจ้งและส่งคำขอดาวน์โหลดผ่านบริการ Google Play ได้ที่ ModuleInstallClient API

    หากคุณไม่เปิดใช้การดาวน์โหลดไปป์ไลน์ขณะติดตั้งหรือขอการดาวน์โหลดอย่างชัดแจ้ง ระบบจะดาวน์โหลดไปป์ไลน์เมื่อคุณเรียกใช้ผู้ติดป้ายกำกับเป็นครั้งแรก คำขอของคุณก่อนการดาวน์โหลดจะเสร็จสมบูรณ์จะไม่สร้างผลลัพธ์ใดๆ

  4. เพิ่มทรัพยากร Dependency linkFirebase หากคุณต้องการดาวน์โหลดโมเดลจาก Firebase แบบไดนามิก

    สำหรับการดาวน์โหลดโมเดลแบบไดนามิกจาก Firebase ให้เพิ่มการอ้างอิง linkFirebase:

    dependencies {
      // ...
      // Image labeling feature with model downloaded from Firebase
      implementation 'com.google.mlkit:image-labeling-custom:17.0.2'
      // Or use the dynamically downloaded pipeline in Google Play Services
      // implementation 'com.google.android.gms:play-services-mlkit-image-labeling-custom:16.0.0-beta5'
      implementation 'com.google.mlkit:linkfirebase:17.0.0'
    }
    
  5. หากต้องการดาวน์โหลดโมเดล ให้ตรวจสอบว่าคุณเพิ่ม Firebase ลงในโปรเจ็กต์ Android หากยังไม่ได้ทำ ขั้นตอนนี้ไม่จำเป็นเมื่อรวมโมเดลเข้าด้วยกัน

1. โหลดโมเดล

กำหนดค่าต้นทางของโมเดลในเครื่อง

วิธีรวมโมเดลเข้ากับแอป

  1. คัดลอกไฟล์โมเดล (โดยปกติจะลงท้ายด้วย .tflite หรือ .lite) ไปยังโฟลเดอร์ assets/ ของแอป (คุณอาจต้องสร้างโฟลเดอร์ก่อนโดยคลิกขวาที่โฟลเดอร์ app/ แล้วคลิกใหม่ > โฟลเดอร์ > โฟลเดอร์ชิ้นงาน)

  2. จากนั้นเพิ่มข้อมูลต่อไปนี้ลงในไฟล์ build.gradle ของแอปเพื่อให้มั่นใจว่า Gradle จะไม่บีบอัดไฟล์โมเดลเมื่อสร้างแอป

    android {
        // ...
        aaptOptions {
            noCompress "tflite"
            // or noCompress "lite"
        }
    }
    

    ไฟล์โมเดลจะรวมอยู่ในแพ็กเกจแอปและพร้อมให้เล่นใน ML Kit เป็นเนื้อหาดิบ

  3. สร้างออบเจ็กต์ 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

หากต้องการใช้โมเดลที่โฮสต์จากระยะไกล ให้สร้างออบเจ็กต์ RemoteModel ด้วย 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.
            }
        });

แอปจำนวนมากเริ่มต้นงานดาวน์โหลดในโค้ดการเริ่มต้น แต่คุณสามารถเริ่มงานได้ทุกเมื่อก่อนที่จะต้องใช้โมเดล

กำหนดค่าผู้ติดป้ายกำกับรูปภาพ

หลังจากที่กำหนดค่าแหล่งที่มาของโมเดลแล้ว ให้สร้างออบเจ็กต์ ImageLabeler จากต้นทางดังกล่าว

โดยมีตัวเลือกดังต่อไปนี้

ตัวเลือก
confidenceThreshold

คะแนนความเชื่อมั่นขั้นต่ำของป้ายกำกับที่ตรวจพบ หากไม่ได้ตั้งค่า ระบบจะใช้เกณฑ์ของตัวแยกประเภทที่ระบุโดยข้อมูลเมตาของโมเดล หากโมเดลไม่มีข้อมูลเมตาหรือข้อมูลเมตาไม่ได้ระบุเกณฑ์ของตัวแยกประเภท ระบบจะใช้เกณฑ์เริ่มต้นที่ 0.0

maxResultCount

จำนวนป้ายกำกับสูงสุดที่จะแสดง หากไม่ได้ตั้งค่า ระบบจะใช้ค่าเริ่มต้น 10

หากคุณมีเฉพาะโมเดลที่รวมในเครื่อง เพียงสร้างผู้ติดป้ายกำกับจากออบเจ็กต์ LocalModel ดังนี้

Kotlin

val customImageLabelerOptions = CustomImageLabelerOptions.Builder(localModel)
    .setConfidenceThreshold(0.5f)
    .setMaxResultCount(5)
    .build()
val labeler = ImageLabeling.getClient(customImageLabelerOptions)

Java

CustomImageLabelerOptions customImageLabelerOptions =
        new CustomImageLabelerOptions.Builder(localModel)
            .setConfidenceThreshold(0.5f)
            .setMaxResultCount(5)
            .build();
ImageLabeler labeler = ImageLabeling.getClient(customImageLabelerOptions);

หากคุณมีโมเดลที่โฮสต์จากระยะไกล คุณจะต้องตรวจสอบว่าโมเดลดังกล่าวได้รับการดาวน์โหลดแล้วก่อนที่จะเรียกใช้ คุณจะตรวจสอบสถานะของงานการดาวน์โหลดโมเดลได้โดยใช้เมธอด isModelDownloaded() ของตัวจัดการโมเดล

แม้ว่าคุณจะต้องยืนยันสิ่งนี้ก่อนที่จะเรียกใช้ผู้ติดป้ายกำกับ แต่ถ้าคุณมีทั้งโมเดลที่โฮสต์จากระยะไกลและโมเดลที่รวมในเครื่อง คุณอาจต้องทำการตรวจสอบนี้เมื่อเริ่มต้นผู้ติดป้ายกำกับรูปภาพ นั่นคือ สร้างป้ายกำกับจากโมเดลระยะไกลหากดาวน์โหลดไว้แล้ว และจากโมเดลในเครื่อง

Kotlin

RemoteModelManager.getInstance().isModelDownloaded(remoteModel)
    .addOnSuccessListener { isDownloaded ->
    val optionsBuilder =
        if (isDownloaded) {
            CustomImageLabelerOptions.Builder(remoteModel)
        } else {
            CustomImageLabelerOptions.Builder(localModel)
        }
    val options = optionsBuilder
                  .setConfidenceThreshold(0.5f)
                  .setMaxResultCount(5)
                  .build()
    val labeler = ImageLabeling.getClient(options)
}

Java

RemoteModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener(new OnSuccessListener() {
            @Override
            public void onSuccess(Boolean isDownloaded) {
                CustomImageLabelerOptions.Builder optionsBuilder;
                if (isDownloaded) {
                    optionsBuilder = new CustomImageLabelerOptions.Builder(remoteModel);
                } else {
                    optionsBuilder = new CustomImageLabelerOptions.Builder(localModel);
                }
                CustomImageLabelerOptions options = optionsBuilder
                    .setConfidenceThreshold(0.5f)
                    .setMaxResultCount(5)
                    .build();
                ImageLabeler labeler = ImageLabeling.getClient(options);
            }
        });

หากคุณมีเฉพาะโมเดลที่โฮสต์จากระยะไกล คุณควรปิดใช้ฟังก์ชันการทำงานเกี่ยวกับโมเดล เช่น ทำให้เป็นสีเทาหรือซ่อนบางส่วนของ 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.
            }
        });

2. เตรียมรูปภาพอินพุต

จากนั้นสร้างออบเจ็กต์ InputImage จากรูปภาพแต่ละรูปภาพที่ต้องการติดป้ายกำกับ เครื่องมือติดป้ายกำกับรูปภาพจะทำงานได้เร็วที่สุดเมื่อคุณใช้ Bitmap หรือหากคุณใช้ Camera2 API ระบบจะใช้ YUV_420_888 media.Image ซึ่งระบบจะแนะนำเมื่อเป็นไปได้

คุณสร้างออบเจ็กต์ 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 ร่วมกับองศาการหมุน

3. เรียกใช้เครื่องมือติดป้ายกำกับรูปภาพ

หากต้องการติดป้ายกำกับวัตถุในรูปภาพ ให้ส่งออบเจ็กต์ image ไปยังเมธอด process() ของ ImageLabeler

Kotlin

labeler.process(image)
        .addOnSuccessListener { labels ->
            // Task completed successfully
            // ...
        }
        .addOnFailureListener { e ->
            // Task failed with an exception
            // ...
        }

Java

labeler.process(image)
        .addOnSuccessListener(new OnSuccessListener<List<ImageLabel>>() {
            @Override
            public void onSuccess(List<ImageLabel> labels) {
                // Task completed successfully
                // ...
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // Task failed with an exception
                // ...
            }
        });

4. รับข้อมูลเกี่ยวกับเอนทิตีที่ติดป้ายกำกับ

หากการดำเนินการติดป้ายกำกับรูปภาพสำเร็จ ระบบจะส่งรายการออบเจ็กต์ ImageLabel ไปยัง Listener ที่สำเร็จ ออบเจ็กต์ ImageLabel แต่ละรายการแสดงถึงสิ่งที่ติดป้ายกำกับในรูปภาพ คุณดูข้อความอธิบายของแต่ละป้ายกำกับ (หากมีในข้อมูลเมตาของไฟล์โมเดล TensorFlow Lite) คะแนนความเชื่อมั่น และดัชนีได้ เช่น

Kotlin

for (label in labels) {
    val text = label.text
    val confidence = label.confidence
    val index = label.index
}

Java

for (ImageLabel label : labels) {
    String text = label.getText();
    float confidence = label.getConfidence();
    int index = label.getIndex();
}

เคล็ดลับในการปรับปรุงประสิทธิภาพแบบเรียลไทม์

หากต้องการติดป้ายกำกับรูปภาพในแอปพลิเคชันแบบเรียลไทม์ ให้ทำตามหลักเกณฑ์ต่อไปนี้เพื่อให้ได้อัตราเฟรมที่ดีที่สุด

  • หากใช้ API Camera หรือ camera2 ให้ควบคุมการเรียกใช้ไปยังผู้ติดป้ายกำกับรูปภาพ หากเฟรมวิดีโอใหม่พร้อมใช้งานขณะที่ผู้ติดป้ายกำกับรูปภาพกำลังทำงาน ให้วางเฟรมดังกล่าว ดูคลาส 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