זיהוי אובייקטים בתמונות באמצעות מודל AutoML שאומן ב-Android

אחרי שמאמנים מודל משלכם באמצעות AutoML Vision Edge, אפשר להשתמש בו באפליקציה כדי לזהות אובייקטים בתמונות.

יש שתי דרכים לשלב מודלים שהודרכו על ידי AutoML Vision Edge: אפשר לארוז את המודל ולהוסיף אותו לתיקיית הנכסים של האפליקציה, או להוריד אותו באופן דינמי מ-Firebase.

אפשרויות של חבילות מודלים
חבילה באפליקציה
  • המודל הוא חלק מחבילת ה-APK של האפליקציה
  • המודל זמין באופן מיידי, גם כשמכשיר Android במצב אופליין
  • אין צורך בפרויקט Firebase
אירוח ב-Firebase
  • מעלים את המודל ל-למידת מכונה ב-Firebase כדי לארח אותו.
  • הקטנת גודל ה-APK
  • המודל מוריד על פי דרישה
  • איך שולחים עדכונים של מודלים בלי לפרסם מחדש את האפליקציה
  • בדיקות A/B פשוטות באמצעות הגדרת תצורה מרחוק ב-Firebase
  • נדרש פרויקט Firebase

לפני שמתחילים

  1. אם רוצים להוריד מודל, צריך לוודא שמוסיפים את Firebase לפרויקט ב-Android, אם עדיין לא עשיתם זאת. אין צורך לעשות זאת כשמקבצים את המודל.

  2. מוסיפים את יחסי התלות של ספריית TensorFlow Lite Task לקובץ ה-Gradle ברמת האפליקציה של המודול, שבדרך כלל הוא app/build.gradle:

    כדי לצרף מודל לאפליקציה:

    dependencies {
      // ...
      // Object detection with a bundled Auto ML model
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.0.0-nightly-SNAPSHOT'
    }
    

    כדי להוריד מודל באופן דינמי מ-Firebase, צריך להוסיף גם את התלות ב-Firebase ML:

    dependencies {
      // ...
      // Object detection with an Auto ML model deployed to Firebase
      implementation platform('com.google.firebase:firebase-bom:26.1.1')
      implementation 'com.google.firebase:firebase-ml-model-interpreter'
    
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.0.0-nightly'
    }
    

1. טעינת המודל

הגדרת מקור מודל מקומי

כדי לצרף את המודל לאפליקציה:

  1. מחלצים את המודל מארכיון ה-zip שהורדתם מהמסוף Google Cloud.
  2. כוללים את המודל בחבילת האפליקציה:
    1. אם אין לכם תיקיית נכסים בפרויקט, תוכלו ליצור אותה בלחיצה ימנית על התיקייה app/ ואז על New > Folder > Assets Folder.
    2. מעתיקים את קובץ המודל tflite עם המטא-נתונים המוטמעים לתיקיית הנכסים.
  3. מוסיפים את הקוד הבא לקובץ build.gradle של האפליקציה כדי לוודא ש-Gradle לא ידחוס את קובץ המודל בזמן ה-build של האפליקציה:

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

    קובץ המודל ייכלל בחבילת האפליקציה ויהיה זמין כנכס גולמי.

הגדרת מקור מודל שמתארח ב-Firebase

כדי להשתמש במודל שמתארח מרחוק, יוצרים אובייקט RemoteModel ומציינים את השם שהקציתם למודל כשפרסמתם אותו:

Java

// Specify the name you assigned when you deployed the model.
FirebaseCustomRemoteModel remoteModel =
        new FirebaseCustomRemoteModel.Builder("your_model").build();

Kotlin

// Specify the name you assigned when you deployed the model.
val remoteModel =
    FirebaseCustomRemoteModel.Builder("your_model_name").build()

לאחר מכן, מפעילים את המשימה של הורדת המודל ומציינים את התנאים שבהם רוצים לאפשר הורדה. אם המודל לא נמצא במכשיר, או אם יש גרסה חדשה יותר של המודל, המשימה תוריד את המודל מ-Firebase באופן אסינכררוני:

Java

DownloadConditions downloadConditions = new DownloadConditions.Builder()
        .requireWifi()
        .build();
RemoteModelManager.getInstance().download(remoteModel, downloadConditions)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(@NonNull Task<Void> task) {
                // Success.
            }
        });

Kotlin

val downloadConditions = DownloadConditions.Builder()
    .requireWifi()
    .build()
RemoteModelManager.getInstance().download(remoteModel, downloadConditions)
    .addOnSuccessListener {
        // Success.
    }

באפליקציות רבות, משימה ההורדה מתחילה בקוד האיניציאליזציה, אבל אפשר לעשות זאת בכל שלב לפני שמשתמשים במודל.

יצירת גלאי אובייקטים מהמודל

אחרי שמגדירים את מקורות המודלים, יוצרים אובייקט ObjectDetector מאחד מהם.

אם יש לכם רק מודל בחבילה מקומית, פשוט יוצרים גלאי אובייקטים מקובץ המודל ומגדירים את סף ציון האמון הנדרש (ראו בדיקת המודל):

Java

// Initialization
ObjectDetectorOptions options = ObjectDetectorOptions.builder()
    .setScoreThreshold(0)  // Evaluate your model in the Google Cloud console
                           // to determine an appropriate value.
    .build();
ObjectDetector objectDetector = ObjectDetector.createFromFileAndOptions(context, modelFile, options);

Kotlin

// Initialization
val options = ObjectDetectorOptions.builder()
    .setScoreThreshold(0)  // Evaluate your model in the Google Cloud console
                           // to determine an appropriate value.
    .build()
val objectDetector = ObjectDetector.createFromFileAndOptions(context, modelFile, options)

אם יש לכם מודל שמתארח מרחוק, תצטרכו לוודא שהוא הורדה לפני שתפעילו אותו. אפשר לבדוק את סטטוס המשימה של הורדת המודל באמצעות השיטה isModelDownloaded() של מנהל המודל.

צריך לאשר את זה רק לפני שמפעילים את גלאי האובייקטים, אבל אם יש לכם גם מודל שמתארח מרחוק וגם מודל שמקובץ באופן מקומי, כדאי לבצע את הבדיקה הזו כשיוצרים את מודל זיהוי האובייקטים: יוצרים מודל זיהוי אובייקטים מהמודל המרוחק אם הוא הועלה, וממודל מקומי אחרת.

Java

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener(new OnSuccessListener<Boolean>() {
            @Override
            public void onSuccess(Boolean isDownloaded) {
            }
        });

Kotlin

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener { success ->

        }

אם יש לכם רק מודל שמתארח מרחוק, עליכם להשבית את הפונקציונליות שקשורה למודל – לדוגמה, להפוך חלק מממשק המשתמש לאפור או להסתיר אותו – עד שתאשרו שהמודל הוריד. כדי לעשות זאת, צריך לצרף מאזין לשיטה download() של מנהל המודלים.

אחרי שהמודל יורד, יוצרים גלאי אובייקטים מקובץ המודל:

Java

FirebaseModelManager.getInstance().getLatestModelFile(remoteModel)
        .addOnCompleteListener(new OnCompleteListener<File>() {
            @Override
            public void onComplete(@NonNull Task<File> task) {
                File modelFile = task.getResult();
                if (modelFile != null) {
                    ObjectDetectorOptions options = ObjectDetectorOptions.builder()
                            .setScoreThreshold(0)
                            .build();
                    objectDetector = ObjectDetector.createFromFileAndOptions(
                            getApplicationContext(), modelFile.getPath(), options);
                }
            }
        });

Kotlin

FirebaseModelManager.getInstance().getLatestModelFile(remoteModel)
        .addOnSuccessListener { modelFile ->
            val options = ObjectDetectorOptions.builder()
                    .setScoreThreshold(0f)
                    .build()
            objectDetector = ObjectDetector.createFromFileAndOptions(
                    applicationContext, modelFile.path, options)
        }

2. הכנת קובץ הקלט

לאחר מכן, לכל תמונה שרוצים לתייג, יוצרים אובייקט TensorImage מהתמונה. אפשר ליצור אובייקט TensorImage מ-Bitmap באמצעות השיטה fromBitmap:

Java

TensorImage image = TensorImage.fromBitmap(bitmap);

Kotlin

val image = TensorImage.fromBitmap(bitmap)

אם נתוני התמונה לא נמצאים ב-Bitmap, אפשר לטעון מערך פיקסלים כפי שמתואר במסמכי העזרה של TensorFlow Lite.

3. הפעלת הכלי לזיהוי אובייקטים

כדי לזהות אובייקטים בתמונה, מעבירים את האובייקט TensorImage לשיטה detect() של ObjectDetector.

Java

List<Detection> results = objectDetector.detect(image);

Kotlin

val results = objectDetector.detect(image)

4. אחזור מידע על אובייקטים מתויגים

אם הפעולה של זיהוי האובייקטים תצליח, היא תחזיר רשימה של אובייקטים מסוג Detection. כל אובייקט Detection מייצג משהו שזוהה בתמונה. אפשר לקבל את תיבת הגבול של כל אובייקט ואת התוויות שלו.

לדוגמה:

Java

for (Detection result : results) {
    RectF bounds = result.getBoundingBox();
    List<Category> labels = result.getCategories();
}

Kotlin

for (result in results) {
    val bounds = result.getBoundingBox()
    val labels = result.getCategories()
}

טיפים לשיפור הביצועים בזמן אמת

אם אתם רוצים לתייג תמונות באפליקציה בזמן אמת, כדאי לפעול לפי ההנחיות הבאות כדי להשיג את שיעורי הפריימים הטובים ביותר:

  • צמצום מספר הקריאות לכלי לתיוג תמונות. אם מסגרת וידאו חדשה זמינה בזמן שהכלי לתיוג תמונות פועל, צריך להוריד את המסגרת. דוגמה לכך מופיעה בכיתה VisionProcessorBase באפליקציה לדוגמה במדריך למתחילים.
  • אם אתם משתמשים בפלט של הכלי לתיוג תמונות כדי להוסיף שכבת-על של גרפיקה לתמונה של הקלט, תחילה צריך לקבל את התוצאה, ואז לבצע עיבוד (רנדור) של התמונה ושל שכבת-העל בשלב אחד. כך תוכלו לבצע עיבוד (render) למשטח התצוגה רק פעם אחת לכל מסגרת קלט. לדוגמה, תוכלו לעיין בכיתות CameraSourcePreview ו- GraphicOverlay באפליקציית הדוגמה למתחילים.
  • אם אתם משתמשים ב-Camera2 API, כדאי לצלם תמונות בפורמט ImageFormat.YUV_420_888.

    אם משתמשים ב-Camera API הקודם, צריך לצלם תמונות בפורמט ImageFormat.NV21.