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

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

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

אפשרויות לחבילה של מודלים
חבילה באפליקציה
  • המודל הוא חלק מה-APK של האפליקציה
  • המודל זמין באופן מיידי, גם כשמכשיר Android במצב אופליין
  • אין צורך בפרויקט 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 ->

        }

אם יש לכם רק מודל שמתארח מרחוק, עליכם להשבית את הפונקציונליות שקשורה למודל – לדוגמה, להפוך חלק מממשק המשתמש לאפור או להסתיר אותו – עד שתאשרו שהמודל הוריד. אפשר לעשות זאת על ידי צירוף listener ל-method 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 ל-method 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 באפליקציה לדוגמה במדריך למתחילים.
  • אם משתמשים בפלט של מתייג התמונות כדי ליצור שכבת-על של גרפיקה בתמונת הקלט, קודם מקבלים את התוצאה ואז מעבדים את התמונה ושכבת-העל בפעולה אחת. כך אפשר לעבד את משטח המסך פעם אחת בלבד עבור כל מסגרת קלט. לדוגמה, תוכלו לעיין בכיתות CameraSourcePreview ו- GraphicOverlay באפליקציית הדוגמה למדריך למתחילים.
  • אם אתם משתמשים ב-Camera2 API, כדאי לצלם תמונות בפורמט ImageFormat.YUV_420_888.

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