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

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

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

קוד לדוגמה

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

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

להורדת הקוד

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

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

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

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

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

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

  • HandLandmarkerHelper.kt - הפעלת הגלאי של ציוני הדרך בכתב יד ומטפלת במודל ובהאצלת הגישה בחירה.
  • MainActivity.kt - מטמיע את האפליקציה, כולל קריאה ל-HandLandmarkerHelper.

הגדרה

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

יחסי תלות

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

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

דגם

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

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

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

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

baseOptionBuilder.setModelAssetPath(MP_HAND_LANDMARKER_TASK)

יצירת המשימה

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

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

תמונה

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

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

וידאו

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

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

שידור חי

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

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

הטמעת הקוד לדוגמה של Hand Scoreer מאפשרת למשתמש לעבור בין במצבי עיבוד שונים. הגישה הזו הופכת את הקוד ליצירת משימה למורכב יותר לא מתאים לתרחיש לדוגמה שלכם. אפשר לראות את הקוד הזה הפונקציה setupHandLandmarker() HandLandmarkerHelper.kt חדש.

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

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

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

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

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

LIVE_STREAM: המצב לשידור חי של קלט נתונים ממצלמה, במצב הזה, resultListener חייב להיות נשלחה קריאה כדי להגדיר אוזן כדי לקבל תוצאות באופן אסינכרוני.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numHands מספר הידיים המקסימלי שזוהה על ידי מזהה ציון הדרך של היד. Any integer > 0 1
minHandDetectionConfidence ציון הסמך המינימלי שצריך להיות זיהוי היד נחשב למוצלח במודל זיהוי כף היד. 0.0 - 1.0 0.5
minHandPresenceConfidence ציון הסמך המינימלי של ציון הנוכחות בכף היד לזיהוי מאפיינים של ציוני דרך. במצב וידאו ובמצב 'שידור חי': אם ציון המהימנות של נוכחות היד מהמודל של יד הציון נמצא מתחת את הסף הזה, Hand landmarker מפעיל את המודל לזיהוי כף היד. אחרת, אלגוריתם קל ופשוט למעקב אחר תנועות הידיים קובע את המיקום של את הידים לזיהוי של ציוני הדרך הבאים. 0.0 - 1.0 0.5
minTrackingConfidence ציון הסמך המינימלי שצריך להביא בחשבון את המעקב אחר היד הפעולה הצליחה. זהו סף IoU של התיבה התוחמת בין הידיים הפריים הנוכחי והפריים האחרון. במצב וידאו ובמצב 'זרם' של Hand Placeer, אם המעקב נכשל, Hand Largeer מפעיל את היד זיהוי וזיהוי אובייקטים. אחרת, התכונה מדלגת על זיהוי היד. 0.0 - 1.0 0.5
resultListener מגדיר את אוזן התוצאות לקבל את תוצאות הזיהוי באופן אסינכרוני כשסמן היד נמצא במצב של שידור חי. רלוונטי רק כשמצב הריצה מוגדר כ-LIVE_STREAM לא רלוונטי לא רלוונטי
errorListener הגדרת האזנה לשגיאות אופציונלית. לא רלוונטי לא רלוונטי

הכנת נתונים

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

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

תמונה

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

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

הרצת המשימה

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

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

תמונה

val result = handLandmarker?.detect(mpImage)
    

וידאו

val timestampMs = i * inferenceIntervalMs

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

שידור חי

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

handLandmarker?.detectAsync(mpImage, frameTime)
    

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

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

ב קוד הדוגמה של היד של ציון הדרך, detect, detectForVideo פונקציות detectAsync מוגדרות HandLandmarkerHelper.kt חדש.

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

Hand Placeer יוצר אובייקט תוצאת חיפוש ידני לכל זיהוי לרוץ. אובייקט התוצאה מכיל ציוני דרך של יד בקואורדינטות של תמונה, יד ציוני דרך בעולם מבחינת הקואורדינטות והידיות(יד שמאל/ימין) של את הידיים.

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

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

  • התאמה ליד הדומיננטית

    היד הדומיננטית מבחינה ידנית מציינת אם הידיים שזוהו הן ידיים שמאל או ידיים ימין.

  • ציוני דרך

    יש 21 ציוני דרך בעבודת יד, כל אחד מהם מורכב מקואורדינטות x, y ו-z. הקואורדינטות x ו-y מנורמלות ל-[0.0, 1.0] על ידי רוחב התמונה ו בהתאמה, בהתאמה. הקואורדינטה z מייצגת את העומק של ציון הדרך, יחד עם העומק בפרק כף היד הוא המקור. ככל שהערך קטן יותר, כך הוא למצלמה. העוצמה של z משתמשת בסולם הזהות, פחות או יותר, כמו x.

  • אתרים חשובים בעולם

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

HandLandmarkerResult:
  Handedness:
    Categories #0:
      index        : 0
      score        : 0.98396
      categoryName : Left
  Landmarks:
    Landmark #0:
      x            : 0.638852
      y            : 0.671197
      z            : -3.41E-7
    Landmark #1:
      x            : 0.634599
      y            : 0.536441
      z            : -0.06984
    ... (21 landmarks for a hand)
  WorldLandmarks:
    Landmark #0:
      x            : 0.067485
      y            : 0.031084
      z            : 0.055223
    Landmark #1:
      x            : 0.063209
      y            : -0.00382
      z            : 0.020920
    ... (21 world landmarks for a hand)

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

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