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

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

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

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

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

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

  2. מוסיפים את התלויות של ספריית המשימות של TensorFlow Lite לקובץ 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. כדי לוודא ש-Gradle לא יכווץ את קובץ המודל כשמבצעים build לאפליקציה, מוסיפים את השורות הבאות לקובץ build.gradle של האפליקציה:

    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 לשיטה 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()
}

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

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

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

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