מדריך לזיהוי פנים ל-Android

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

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

קוד לדוגמה

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

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

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

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

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

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

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

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

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

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

הגדרה

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

יחסי תלות

המשימה Face Detector משתמשת בספרייה com.google.mediapipe:tasks-vision. מוסיפים את התלות הזו לקובץ build.gradle של אפליקציית Android:

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

דגם

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

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

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

מציינים את הנתיב של המודל בתוך הפרמטר ModelAssetPath. בקוד לדוגמה, המודל מוגדר בקובץ FaceDetectorHelper.kt:

val modelName = "face_detection_short_range.tflite"
baseOptionsBuilder.setModelAssetPath(modelName)

יצירת המשימה

המשימה 'זיהוי פנים' של MediaPipe משתמשת בפונקציה createFromOptions() כדי להגדיר את המשימה. הפונקציה createFromOptions() מקבלת ערכים לאפשרויות ההגדרה. מידע נוסף על אפשרויות ההגדרה זמין במאמר אפשרויות הגדרה.

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

תמונה

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(modelName)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder =
    FaceDetector.FaceDetectorOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinDetectionConfidence(threshold)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()

FaceDetector =
    FaceDetector.createFromOptions(context, options)
    

וידאו

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(modelName)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder =
    FaceDetector.FaceDetectorOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinDetectionConfidence(threshold)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()

FaceDetector =
    FaceDetector.createFromOptions(context, options)
    

שידור חי

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(modelName)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder =
    FaceDetector.FaceDetectorOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinDetectionConfidence(threshold)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.LIVE_STREAM)

val options = optionsBuilder.build()

FaceDetector =
    FaceDetector.createFromOptions(context, options)
    

הטמעת הקוד לדוגמה של Face Detector מאפשרת למשתמש לעבור בין מצבי העיבוד. הגישה הזו הופכת את הקוד ליצירת המשימות למורכב יותר, ויכול להיות שהיא לא מתאימה לתרחיש לדוגמה שלכם. הקוד הזה מופיע בפונקציה setupFaceDetector() בקובץ FaceDetectorHelper.kt.

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

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

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

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

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

LIVE_STREAM: המצב של סטרימינג בשידור חי של נתוני קלט, למשל ממצלמה. במצב הזה, צריך להפעיל את resultListener כדי להגדיר מאזין שיקבל את התוצאות באופן אסינכרוני.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
minDetectionConfidence דירוג האמון המינימלי שדרוש כדי שזיהוי הפנים ייחשב כהצלחה. Float [0,1] 0.5
minSuppressionThreshold הסף המינימלי ללא דיכוי מקסימלי, שעבורו זיהוי הפנים נחשב כחופף. Float [0,1] 0.3
resultListener מגדיר את מאזין התוצאות כך שיקבל את תוצאות הזיהוי באופן אסינכרוני כשגלאי הפנים נמצא במצב של שידור חי. אפשר להשתמש בה רק כשמצב ההפעלה מוגדר כ-LIVE_STREAM. N/A Not set
errorListener הגדרת מאזין אופציונלי לשגיאות. N/A Not set

הכנת הנתונים

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

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

תמונה

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

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(image).build()
    

וידאו

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

val argb8888Frame =
    if (frame.config == Bitmap.Config.ARGB_8888) frame
    else frame.copy(Bitmap.Config.ARGB_8888, false)

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(argb8888Frame).build()
    

שידור חי

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

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(rotatedBitmap).build()
    

בקוד לדוגמה של Face Detector, הכנת הנתונים מתבצעת בקובץ FaceDetectorHelper.kt.

הרצת המשימה

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

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

תמונה

val result = faceDetector.detect(mpImage)
    

וידאו

val timestampMs = i * inferenceIntervalMs

faceDetector.detectForVideo(mpImage, timestampMs)
    .let { detectionResult ->
        resultList.add(detectionResult)
    }
    

שידור חי

val mpImage = BitmapImageBuilder(rotatedBitmap).build()
val frameTime = SystemClock.uptimeMillis()

faceDetector.detectAsync(mpImage, frameTime)
    

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

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

בקוד לדוגמה של Face Detector, הפונקציות detect,‏ detectForVideo ו-detectAsync מוגדרות בקובץ FaceDetectorHelper.kt.

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

ה-Face Detector מחזיר אובייקט FaceDetectorResult לכל הפעלה של זיהוי. אובייקט התוצאה מכיל תיבות מלבניות של הפנים שזוהו ודירוג ביטחון לכל פנים שזוהה.

בהמשך מוצגת דוגמה לנתוני הפלט של המשימה הזו:

FaceDetectionResult:
  Detections:
    Detection #0:
      BoundingBox:
        origin_x: 126
        origin_y: 100
        width: 463
        height: 463
      Categories:
        Category #0:
          index: 0
          score: 0.9729152917861938
      NormalizedKeypoints:
        NormalizedKeypoint #0:
          x: 0.18298381567001343
          y: 0.2961040139198303
        NormalizedKeypoint #1:
          x: 0.3302789330482483
          y: 0.29289937019348145
        ... (6 keypoints for each face)
    Detection #1:
      BoundingBox:
        origin_x: 616
        origin_y: 193
        width: 430
        height: 430
      Categories:
        Category #0:
          index: 0
          score: 0.9251380562782288
      NormalizedKeypoints:
        NormalizedKeypoint #0:
          x: 0.6151331663131714
          y: 0.3713381886482239
        NormalizedKeypoint #1:
          x: 0.7460576295852661
          y: 0.38825345039367676
        ... (6 keypoints for each face)

בתמונה הבאה מוצגת תצוגה חזותית של הפלט של המשימה:

שני ילדים עם תיבות מסגרת סביב הפנים שלהם

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

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