מדריך לזיהוי של ציוני דרך ב-Android

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

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

קוד לדוגמה

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

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

להורדת הקוד

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

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

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

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

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

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

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

הגדרה

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

יחסי תלות

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

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

דגם

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

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

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

צריך לציין את הנתיב של המודל בתוך הפרמטר ModelAssetPath. ב המודל מוגדר PoseLandmarkerHelper.kt file:

val modelName = "pose_landmarker_lite.task"
baseOptionsBuilder.setModelAssetPath(modelName)

יצירת המשימה

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

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

תמונה

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

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setRunningMode(RunningMode.IMAGE)

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

וידאו

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

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setRunningMode(RunningMode.VIDEO)

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

שידור חי

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

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.LIVE_STREAM)

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

הטמעת הקוד לדוגמה של Pose Lander מאפשרת למשתמש לעבור בין במצבי עיבוד שונים. הגישה הזו הופכת את הקוד ליצירת משימה למורכב יותר לא מתאים לתרחיש לדוגמה שלכם. אפשר לראות את הקוד הזה הפונקציה setupPoseLandmarker() PoseLandmarkerHelper.kt חדש.

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

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

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

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

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

LIVE_STREAM: המצב לשידור חי של קלט נתונים ממצלמה, במצב הזה, resultListener חייב להיות נשלחה קריאה כדי להגדיר אוזן כדי לקבל תוצאות באופן אסינכרוני.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numposes המספר המקסימלי של תנוחות שהמערכת יכולה לזהות תנו לציוני דרך. Integer > 0 1
minPoseDetectionConfidence ציון הסמך המינימלי שצריך להיות לזיהוי התנוחה נחשב למוצלח. Float [0.0,1.0] 0.5
minPosePresenceConfidence ציון הסמך המינימלי של הנוכחות בתנוחת הפוקוס בזיהוי התנוחה של ציון הדרך. Float [0.0,1.0] 0.5
minTrackingConfidence ציון הסמך המינימלי למעקב אחרי התנוחה כדי להיחשב כהצלחה. Float [0.0,1.0] 0.5
outputSegmentationMasks האם Pose srcer מפיק מסיכת פילוח עבור של התנוחה. Boolean False
resultListener מגדיר את אוזן התוצאות לקבל את תוצאות ה- במעקב באופן אסינכרוני כש-Pose Lander נמצא במצב שידור חי. אפשר להשתמש באפשרות הזו רק כשמצב הריצה מוגדר ל-LIVE_STREAM ResultListener N/A
errorListener הגדרת האזנה לשגיאות אופציונלית. ErrorListener N/A

הכנת נתונים

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

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

תמונה

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

בקוד לדוגמה של Pose srcer, הכנת הנתונים מטופלת PoseLandmarkerHelper.kt חדש.

הרצת המשימה

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

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

תמונה

val result = poseLandmarker.detect(mpImage)
    

וידאו

val timestampMs = i * inferenceIntervalMs

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

שידור חי

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

poseLandmarker.detectAsync(mpImage, frameTime)
    

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

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

בקוד לדוגמה של Poseוןer, הערכים detect, detectForVideo פונקציות detectAsync מוגדרות PoseLandmarkerHelper.kt חדש.

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

ה-Pose Lander מחזיר אובייקט poseLandmarkerResult לכל זיהוי לרוץ. אובייקט התוצאה מכיל קואורדינטות של כל מאפיין של מיקום.

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

PoseLandmarkerResult:
  Landmarks:
    Landmark #0:
      x            : 0.638852
      y            : 0.671197
      z            : 0.129959
      visibility   : 0.9999997615814209
      presence     : 0.9999984502792358
    Landmark #1:
      x            : 0.634599
      y            : 0.536441
      z            : -0.06984
      visibility   : 0.999909
      presence     : 0.999958
    ... (33 landmarks per pose)
  WorldLandmarks:
    Landmark #0:
      x            : 0.067485
      y            : 0.031084
      z            : 0.055223
      visibility   : 0.9999997615814209
      presence     : 0.9999984502792358
    Landmark #1:
      x            : 0.063209
      y            : -0.00382
      z            : 0.020920
      visibility   : 0.999976
      presence     : 0.999998
    ... (33 world landmarks per pose)
  SegmentationMasks:
    ... (pictured below)

הפלט מכיל גם קואורדינטות מנורמלות (Landmarks) וגם את העולם את הקואורדינטות (WorldLandmarks) של כל ציון דרך.

הפלט מכיל את הקואורדינטות המנורמלות הבאות (Landmarks):

  • x ו-y: קואורדינטות של ציון דרך, מנורמלות בין 0.0 ל-1.0 באמצעות רוחב התמונה (x) וגובה התמונה (y).

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

  • visibility: הסבירות שציון הדרך יופיע בתמונה.

הפלט מכיל את קואורדינטות העולם הבאות (WorldLandmarks):

  • x, y ו-z: קואורדינטות תלת-ממדיות בעולם האמיתי במטרים, כאשר נקודת האמצע של הירכיים בתור המקור.

  • visibility: הסבירות שציון הדרך יופיע בתמונה.

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

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

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