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

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

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

קוד לדוגמה

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

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

הורדת הקוד

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

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

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

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

רכיבים עיקריים

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

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

הגדרה

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

יחסי תלות

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

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

מודל

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

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

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

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

baseOptionsBuilder.setModelAssetPath(MP_FACE_LANDMARKER_TASK)

יצירת המשימה

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

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

תמונה

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

val optionsBuilder = 
    FaceLandmarker.FaceLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinFaceDetectionConfidence(minFaceDetectionConfidence)
        .setMinTrackingConfidence(minFaceTrackingConfidence)
        .setMinFacePresenceConfidence(minFacePresenceConfidence)
        .setNumFaces(maxNumFaces)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()
FaceLandmarker = FaceLandmarker.createFromOptions(context, options)
    

וידאו

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

val optionsBuilder = 
    FaceLandmarker.FaceLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinFaceDetectionConfidence(minFaceDetectionConfidence)
        .setMinTrackingConfidence(minFaceTrackingConfidence)
        .setMinFacePresenceConfidence(minFacePresenceConfidence)
        .setNumFaces(maxNumFaces)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()
FaceLandmarker = FaceLandmarker.createFromOptions(context, options)
    

שידור חי

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

val optionsBuilder = 
    FaceLandmarker.FaceLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinFaceDetectionConfidence(minFaceDetectionConfidence)
        .setMinTrackingConfidence(minFaceTrackingConfidence)
        .setMinFacePresenceConfidence(minFacePresenceConfidence)
        .setNumFaces(maxNumFaces)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.LIVE_STREAM)

val options = optionsBuilder.build()
FaceLandmarker = FaceLandmarker.createFromOptions(context, options)
    

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

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

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

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

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

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

LIVE_STREAM: המצב עבור סטרימינג בשידור חי של נתוני קלט, למשל ממצלמה. במצב הזה, יש להפעיל את resultListener כדי להגדיר מאזין לקבלת תוצאות באופן אסינכרוני.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numFaces המספר המקסימלי של פנים שניתן לזהות באמצעות FaceLandmarker. ההחלקה מתבצעת רק כאשר הערך של num_faces מוגדר ל-1. Integer > 0 1
minFaceDetectionConfidence ציון הסמך המינימלי שצריך לעמוד בו כדי שזיהוי הפנים ייחשב כמוצלח. Float [0.0,1.0] 0.5
minFacePresenceConfidence ציון המהימנות המינימלי של ציון נוכחות הפנים בזיהוי של ציון הפנים. Float [0.0,1.0] 0.5
minTrackingConfidence ציון הסמך המינימלי הנדרש למעקב אחר זיהוי הפנים כדי להיחשב כמוצלח. Float [0.0,1.0] 0.5
outputFaceBlendshapes האם Face Looker יוצר מיקסים של פנים. שילובים של הפנים משמשים להצגת התבנית התלת-ממדית לזיהוי הפנים. Boolean False
outputFacialTransformationMatrixes האם סמן הפלט הוא פלט של מטריצת טרנספורמציית הפנים. התכונה 'סמן פנים' משתמשת במטריצה כדי לשנות את ציוני הדרך של הפנים מתבנית קנונית לזיהוי פנים לזיהוי הפנים שזוהו. כך המשתמשים יכולים להחיל אפקטים על ציוני הדרך שזוהו. Boolean False
resultListener מגדיר את מאזין התוצאות לקבלת תוצאות של ציוני דרך באופן אסינכרוני כאשר FaceLandmark נמצא במצב שידור חי. אפשר להשתמש רק כשמצב ריצה מוגדר ל-LIVE_STREAM ResultListener N/A
errorListener מגדירה האזנה לשגיאות כאופציונלי. ErrorListener N/A

הכנת הנתונים

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

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

תמונה

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 BrandConnect, הכנת הנתונים מטופלת בקובץ FaceLandmarkerHelper.kt.

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

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

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

תמונה

val result = FaceLandmarker.detect(mpImage)
    

וידאו

val timestampMs = i * inferenceIntervalMs

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

שידור חי

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

FaceLandmarker.detectAsync(mpImage, frameTime)
    

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

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

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

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

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

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

FaceLandmarkerResult:
  face_landmarks:
    NormalizedLandmark #0:
      x: 0.5971359014511108
      y: 0.485361784696579
      z: -0.038440968841314316
    NormalizedLandmark #1:
      x: 0.3302789330482483
      y: 0.29289937019348145
      z: -0.09489090740680695
    ... (478 landmarks for each face)
  face_blendshapes:
    browDownLeft: 0.8296722769737244
    browDownRight: 0.8096957206726074
    browInnerUp: 0.00035583582939580083
    browOuterUpLeft: 0.00035752105759456754
    ... (52 blendshapes for each face)
  facial_transformation_matrixes:
    [9.99158978e-01, -1.23036895e-02, 3.91213447e-02, -3.70770246e-01]
    [1.66496094e-02,  9.93480563e-01, -1.12779640e-01, 2.27719707e+01]
    ...

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

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