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

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

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

קוד לדוגמה

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

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

הורדת הקוד

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

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

  1. משכפלים את מאגר ה-Git באמצעות הפקודה הבאה:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. לחלופין, אפשר להגדיר את מכונת ה-Git לשימוש בקופה עם נפח נתונים גמיש, כדי שיהיו לכם רק את הקבצים של האפליקציה לדוגמה של מזהה הפנים:
    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 – מטמיעה את התצוגה עם תיבות תוחמות עבור פנים שזוהו.

הגדרה

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

יחסי תלות

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

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

מודל

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

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

<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)
    

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

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

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

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

IMAGE: המצב שבו ניתן להזין תמונה יחידה.

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

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()
    

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

מריצים את המשימה.

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

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

תמונה

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)
    

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

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

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

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

בכל הרצת זיהוי, מזהה הפנים מחזיר אובייקט 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)

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

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

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