מדריך לזיהוי אובייקטים ב-Android

המשימה 'זיהוי אובייקטים' מאפשרת לך לזהות את הנוכחות והמיקום של מספר של אובייקטים. לדוגמה, מכשיר לזיהוי חפצים יכול לאתר כלבים בתוך תמונה. בהוראות האלה מוסבר איך להשתמש במשימה 'גלאי אובייקטים' Android. דוגמת הקוד שמתוארת בהוראות אלה זמינה במכשירים הבאים: GitHub. אפשר לראות את המשימה הזו בפעולה הדגמה באינטרנט. מידע נוסף על היכולות, המודלים ואפשרויות ההגדרה במשימה הזאת, ראו סקירה כללית.

קוד לדוגמה

קוד הדוגמה למשימות MediaPipe הוא הטמעה פשוטה של גלאי אובייקטים לאפליקציה ל-Android. בדוגמה, המצלמה במכשיר Android פיזי משמשת את המצלמה כדי: לזהות אובייקטים באופן שוטף, וגם להשתמש בתמונות ובסרטונים הגלריה של המכשיר כדי לזהות אובייקטים באופן סטטי.

אפשר להשתמש באפליקציה כנקודת התחלה של אפליקציה משלכם ל-Android, או להתייחס אליה כשמשנים אפליקציה קיימת. הקוד לדוגמה של 'מזהה אובייקטים' מתארח ב GitHub.

להורדת הקוד

בהוראות הבאות מוסבר איך ליצור עותק מקומי של הדוגמה באמצעות כלי שורת הפקודה git.

כדי להוריד את הקוד לדוגמה:

  1. משכפלים את מאגר ה-Git באמצעות הפקודה הבאה:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. אפשר גם להגדיר את ה-Git למכונת ה-Git לשימוש בקופה מועטה, קיימים רק הקבצים של האפליקציה לדוגמה של 'מזהה אובייקטים':
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/object_detection/android
    

אחרי שיוצרים גרסה מקומית של הקוד לדוגמה, אפשר לייבא את הפרויקט אל Android Studio ולהריץ את האפליקציה. הוראות מופיעות מדריך ההגדרה ל-Android.

רכיבים מרכזיים

הקבצים הבאים מכילים את הקוד החיוני לגלאי האובייקטים אפליקציה לדוגמה:

  • ObjectDetectorHelper.kt - הפעלת מזהה האובייקטים וטיפול במודל ובהענקת גישה בחירה
  • MainActivity.kt - הטמעת האפליקציה והרכבה של רכיבי ממשק המשתמש
  • OverlayView.kt - כינויים והצגת התוצאות

הגדרה

בקטע הזה מתוארים השלבים העיקריים להגדרת סביבת הפיתוח של פרויקטי קוד לשימוש ב-Object Detect. למידע כללי על להגדיר את סביבת הפיתוח לשימוש במשימות של MediaPipe, כולל הדרישות לגרסת הפלטפורמה. מדריך ההגדרה ל-Android.

יחסי תלות

התכונה 'מזהה אובייקטים' משתמשת בספרייה com.google.mediapipe:tasks-vision. הוספת הפריט שתלויות בקובץ build.gradle של פרויקט של פיתוח אפליקציות ל-Android. לייבא את יחסי התלות הנדרשים באמצעות את הקוד הבא:

dependencies {
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

דגם

למשימה 'מזהה אובייקטים של MediaPipe' נדרש מודל מאומן שתואם למשימה הזו. לקבלת מידע נוסף על מודלים זמינים מאומנים של מזהה אובייקטים, ראו בסקירה הכללית על המשימה בקטע 'מודלים'.

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

<dev-project-root>/src/main/assets

משתמשים בשיטה BaseOptions.Builder.setModelAssetPath() כדי לציין את הנתיב שבו משתמש המודל. בקטע הבא מופיע קוד לדוגמה.

יצירת המשימה

אפשר להשתמש בפונקציה createFromOptions כדי ליצור את המשימה. הפונקציה createFromOptions מקבלת אפשרויות הגדרה כולל הרצה מצב, שם תצוגה, לוקאל, מספר מקסימלי של תוצאות, סף מהימנות, רשימת היתרים של קטגוריות ורשימת ישויות שנחסמו. אם לא מצוינת אפשרות הגדרה, המערכת תשתמש בערך ברירת המחדל. למידע נוסף על אפשרויות הגדרה, לפרטים נוספים, אפשר לקרוא את הסקירה הכללית על ההגדרות.

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

תמונה

ObjectDetectorOptions options =
  ObjectDetectorOptions.builder()
    .setBaseOptions(BaseOptions.builder().setModelAssetPath(‘model.tflite’).build())
    .setRunningMode(RunningMode.IMAGE)
    .setMaxResults(5)
    .build();
objectDetector = ObjectDetector.createFromOptions(context, options);
    

וידאו

ObjectDetectorOptions options =
  ObjectDetectorOptions.builder()
    .setBaseOptions(BaseOptions.builder().setModelAssetPath(‘model.tflite’).build())
    .setRunningMode(RunningMode.VIDEO)
    .setMaxResults(5)
    .build();
objectDetector = ObjectDetector.createFromOptions(context, options);
    

שידור חי

ObjectDetectorOptions options =
  ObjectDetectorOptions.builder()
    .setBaseOptions(BaseOptions.builder().setModelAssetPath(model.tflite).build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setMaxResults(5)
    .setResultListener((result, inputImage) -> {
      // Process the detection result here.
    })
    .setErrorListener((result, inputImage) -> {
      // Process the classification errors here.
    })
   .build();
objectDetector = ObjectDetector.createFromOptions(context, options);
    

הטמעת הקוד לדוגמה של מזהה האובייקטים מאפשרת למשתמש לעבור בין במצבי עיבוד שונים. הגישה הזו הופכת את הקוד ליצירת משימה למורכב יותר לא מתאים לתרחיש לדוגמה שלכם. אפשר לראות את הקוד הזה ObjectDetectorHelper מחלקה setupObjectDetector().

אפשרויות תצורה

המשימה הזו כוללת את אפשרויות ההגדרה הבאות לאפליקציות ל-Android:

שם האפשרות תיאור טווח ערכים ערך ברירת מחדל
runningMode מגדיר את מצב הריצה של המשימה. יש שלושה סוגים מצבים:

IMAGE: המצב לקלט של תמונה יחידה.

סרטון: המצב של פריימים מפוענחים בסרטון.

LIVE_STREAM: המצב לשידור חי של קלט נתונים ממצלמה, במצב הזה, resultListener חייב להיות נשלחה קריאה כדי להגדיר אוזן כדי לקבל תוצאות באופן אסינכרוני.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
displayNamesLocales מגדיר את השפה של תוויות שישמשו לשמות לתצוגה שסופקו של מודל המשימה, אם יש כאלה. ברירת המחדל היא en עבור אנגלית. אפשר להוסיף תוויות שמותאמות לשוק המקומי למטא-נתונים של מודל מותאם אישית באמצעות TensorFlow Lite Metadata Writer API קוד שפה en
maxResults מגדיר את המספר המקסימלי האופציונלי של תוצאות זיהוי עם הדירוג הגבוה ביותר של החזרה. מספרים חיוביים כלשהם 1- (כל התוצאות מוחזרות)
scoreThreshold הגדרת סף הציון של התחזית שמבטל את הסף שצוין ב את המטא-נתונים של המודל (אם יש). תוצאות מתחת לערך הזה נדחות. כל מספר ממשי (float) לא מוגדר
categoryAllowlist מגדיר את הרשימה האופציונלית של שמות קטגוריות מותרות. אם השדה לא ריק, תוצאות זיהוי ששם הקטגוריה שלהן אינו בקבוצה זו יהיו מסונן. המערכת מתעלמת משמות קטגוריות כפולים או לא ידועים. האפשרות הזו בלעדית למשתמשי categoryDenylist ומשתמשים ושניהם יובילו לשגיאה. כל מחרוזת לא מוגדר
categoryDenylist מגדיר את הרשימה האופציונלית של שמות קטגוריות שאינם מותרים. אם המיקום לא ריקות, תוצאות זיהוי ששם הקטגוריה שלהן נמצא בקבוצה זו יסוננו החוצה. המערכת מתעלמת משמות קטגוריות כפולים או לא ידועים. האפשרות הזו מקבילה בלעדי ל-categoryAllowlist ושימוש בשתי התוצאות עלול לגרום לשגיאה. כל מחרוזת לא מוגדר
resultListener מגדיר את אוזן התוצאות לקבל את תוצאות הזיהוי באופן אסינכרוני כשמזהה האובייקטים נמצא בשידור החי במצב תצוגה. ניתן להשתמש באפשרות הזו רק כשמגדירים את runningMode כ-LIVE_STREAM. לא רלוונטי לא מוגדר

הכנת נתונים

צריך להמיר את קלט התמונה או המסגרת אובייקט com.google.mediapipe.framework.image.MPImage לפני העברה שלו גלאי אובייקטים.

בדוגמאות הבאות מוסבר איך מכינים נתונים לעיבוד, ומראים בהם איך עושים את זה לגבי כל אחד מסוגי הנתונים הזמינים:

תמונה

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load an image on the users device as a Bitmap object using BitmapFactory.

// Convert an Androids Bitmap object to a MediaPipes Image object.
Image mpImage = new BitmapImageBuilder(bitmap).build();
    

וידאו

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load a video file on the user's device using MediaMetadataRetriever

// From the videos metadata, load the METADATA_KEY_DURATION and
// METADATA_KEY_VIDEO_FRAME_COUNT values. Use these values
// to calculate the timestamp of each frame later.

// Loop through the video and load each frame as a Bitmap object.

// Convert the Androids Bitmap object to a MediaPipes Image object.
Image mpImage = new BitmapImageBuilder(frame).build();
    

שידור חי

import com.google.mediapipe.framework.image.MediaImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Create a CameraXs ImageAnalysis to continuously receive frames
// from the devices camera. Configure it to output frames in RGBA_8888
// format to match with what is required by the model.

// For each Androids ImageProxy object received from the ImageAnalysis,
// extract the encapsulated Androids Image object and convert it to
// a MediaPipes Image object.
android.media.Image mediaImage = imageProxy.getImage()
MPImage mpImage = new MediaImageBuilder(mediaImage).build();
    

בקוד לדוגמה של מזהה האובייקטים, הכנת הנתונים מטופלת ObjectDetectorHelper כיתה בdetectImage(), detectVideoFile(), detectLivestreamFrame() למשימות ספציפיות.

הרצת המשימה

בהתאם לסוג הנתונים שאתם עובדים איתם, משתמשים באופרטור ObjectDetector.detect...() שספציפית לסוג הנתונים הזה. כדאי להשתמש detect() לתמונות בודדות, detectForVideo() לפריימים בקובצי וידאו, וגם detectAsync() לזרמי וידאו. כשאתם מבצעים זיהוי וידאו בסטרימינג, חשוב לוודא שאתם מריצים את הזיהוי בשרשור נפרד, וחוסם את ה-thread של ממשק המשתמש.

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

תמונה

ObjectDetectorResult detectionResult = objectDetector.detect(image);
    

וידאו

// Calculate the timestamp in milliseconds of the current frame.
long frame_timestamp_ms = 1000 * video_duration * frame_index / frame_count;

// Run inference on the frame.
ObjectDetectorResult detectionResult =
    objectDetector.detectForVideo(image, frameTimestampMs);
    

שידור חי

// Run inference on the frame. The detection results will be available
// via the `resultListener` provided in the `ObjectDetectorOptions` when
// the object detector was created.
objectDetector.detectAsync(image, frameTimestampMs);
    

בדוגמה של הקוד של מזהה האובייקטים אפשר לראות את ההטמעות של כל אחד מהרכיבים האלה במצב מפורט יותר detect() detectVideoFile(), ו-detectAsync(). הקוד לדוגמה מאפשר למשתמש לעבור בין מצבי עיבוד שאולי לא יהיה הכרחי בתרחיש לדוגמה שלכם.

שימו לב לנקודות הבאות:

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

טיפול בתוצאות והצגתן

כשמריצים את ההסקה, המשימה 'גלאי אובייקטים' מחזירה אובייקט ObjectDetectorResult שמתאר את האובייקטים שהוא מצא בהם של קובץ הקלט

בדוגמה הבאה אפשר לראות את נתוני הפלט מהמשימה:

ObjectDetectorResult:
 Detection #0:
  Box: (x: 355, y: 133, w: 190, h: 206)
  Categories:
   index       : 17
   score       : 0.73828
   class name  : dog
 Detection #1:
  Box: (x: 103, y: 15, w: 138, h: 369)
  Categories:
   index       : 17
   score       : 0.73047
   class name  : dog

בתמונה הזו אפשר לראות את פלט המשימה:

הקוד לדוגמה של 'מזהה אובייקטים' מדגים איך להציג את הזיהוי של התוצאות שהוחזרו מהמשימה, OverlayView לקבלת פרטים נוספים.