מדריך לפילוח תמונות ב-Android

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

קוד לדוגמה

דוגמת הקוד של MediaPipe Tasks מכילה שתי הטמעות פשוטות של אפליקציה לחלוקת תמונות לקטעים ב-Android:

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

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

מורידים את הקוד

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

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

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

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

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

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

  • ImageSegmenterHelper.kt – הפונקציה הזו מפעילה את המשימה Image Segmenter ומטפלת בבחירת המודל ובסמכות הענקת הגישה.
  • CameraFragment.kt – קובץ שמכיל את ממשק המשתמש ואת קוד הבקרה של המצלמה.
  • GalleryFragment.kt – ממשק המשתמש וקוד הבקרה לבחירת קובצי תמונות וסרטונים.
  • OverlayView.kt – טיפול בתוצאות הפילוח ועיצוב שלהן.

הגדרה

בקטע הזה מתוארים השלבים העיקריים להגדרת סביבת הפיתוח ופרויקטי הקוד לשימוש ב-Image Segmenter. למידע כללי על הגדרת סביבת הפיתוח לשימוש במשימות של 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

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

בקוד לדוגמה של Image Segmenter, המודל מוגדר במחלקה ImageSegmenterHelper.kt בפונקציה setupImageSegmenter().

יצירת המשימה

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

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

תמונה

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.IMAGE)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .build();
imagesegmenter = ImageSegmenter.createFromOptions(context, options);
    

וידאו

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.VIDEO)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .build();
imagesegmenter = ImageSegmenter.createFromOptions(context, options);
    

שידור חי

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .setResultListener((result, inputImage) -> {
         // Process the segmentation result here.
    })
    .setErrorListener((result, inputImage) -> {
         // Process the segmentation errors here.
    })
    .build()
imagesegmenter = ImageSegmenter.createFromOptions(context, options)
    

הטמעת הקוד לדוגמה של Image Segmenter מאפשרת למשתמש לעבור בין מצבי העיבוד. הגישה הזו הופכת את הקוד ליצירת המשימות למורכב יותר, ויכול להיות שהיא לא מתאימה לתרחיש לדוגמה שלכם. אפשר לראות את הקוד הזה בכיתה ImageSegmenterHelper באמצעות הפונקציה setupImageSegmenter().

אפשרויות הגדרה

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

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

IMAGE: המצב להזנת תמונה אחת.

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

LIVE_STREAM: המצב של סטרימינג בשידור חי של נתוני קלט, למשל ממצלמה. במצב הזה, צריך להפעיל את resultListener כדי להגדיר מאזין שיקבל את התוצאות באופן אסינכרוני.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
outputCategoryMask אם הערך מוגדר כ-True, הפלט כולל מסכת פילוח כתמונה מסוג uint8, שבה כל ערך פיקסל מציין את ערך הקטגוריה המנצחת. {True, False} False
outputConfidenceMasks אם הערך מוגדר כ-True, הפלט כולל מסכת פילוח כתמונה של ערך צף, שבו כל ערך צף מייצג את המפה של ציון האמון של הקטגוריה. {True, False} True
displayNamesLocale הגדרת השפה של התוויות לשימוש בשמות התצוגה שסופקו במטא-נתונים של מודל המשימה, אם הם זמינים. ברירת המחדל היא en לאנגלית. אפשר להוסיף תוויות מותאמות לשוק המקומי למטא-נתונים של מודל מותאם אישית באמצעות TensorFlow Lite Metadata Writer API קוד לוקאל en
resultListener מגדיר את מאזין התוצאות לקבל את תוצאות הפיצול באופן אסינכרוני כשכלי הפיצול של התמונות נמצא במצב LIVE_STREAM. אפשר להשתמש בה רק כשמצב ההפעלה מוגדר כ-LIVE_STREAM לא רלוונטי לא רלוונטי
errorListener הגדרת מאזין אופציונלי לשגיאות. לא רלוונטי לא מוגדר

הכנת הנתונים

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

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

תמונה

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 value. Youll need them
// 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()
Image mpImage = new MediaImageBuilder(mediaImage).build();
    

בקוד לדוגמה של 'פילוח תמונות', הכנת הנתונים מתבצעת בכיתה ImageSegmenterHelper באמצעות הפונקציה segmentLiveStreamFrame().

הרצת המשימה

קוראים לפונקציה segment שונה בהתאם למצב ההפעלה שבו אתם משתמשים. הפונקציה Image Segmenter מחזירה את אזורי הפלחים שזוהו בתוך התמונה או המסגרת של הקלט.

תמונה

ImageSegmenterResult segmenterResult = imagesegmenter.segment(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.
ImageSegmenterResult segmenterResult =
    imagesegmenter.segmentForVideo(image, frameTimestampMs);
    

שידור חי

// Run inference on the frame. The segmentations results will be available via
// the `resultListener` provided in the `ImageSegmenterOptions` when the image
// segmenter was created.
imagesegmenter.segmentAsync(image, frameTimestampMs);
    

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

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

בקוד לדוגמה של 'פילוח תמונות', הפונקציות segment מוגדרות בקובץ ImageSegmenterHelper.kt.

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

לאחר הפעלת ההסקה, המשימה Image Segmenter מחזירה אובייקט ImageSegmenterResult שמכיל את התוצאות של משימה הפילוח. תוכן הפלט תלוי ב-outputType שהגדרתם בזמן הגדרת המשימה.

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

רמת הסמך של הקטגוריה

בתמונות הבאות מוצגת תצוגה חזותית של הפלט של המשימה למסכת ביטחון של קטגוריה. הפלט של מסכת האמון מכיל ערכים של משתנה צף בין [0, 1].

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

פלט של המסכה המקורית של רמת האמון בתמונה ובקטגוריה. תמונה ממקור מערך הנתונים Pascal VOC 2012.

ערך הקטגוריה

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

שתי ילדות שרוכבות על סוס וילדה אחת הולכת לצד הסוס מסכת התמונה שמציגה את קווי המתאר של הילדות והסוס מהתמונה הקודמת. הצורה של שלוש הבנות והסוס מטושטשת בצורה מדויקת

פלט של התמונה המקורית ומסכת הקטגוריה. תמונה ממקור מערך הנתונים Pascal VOC 2012.