מדריך לזיהוי תנועות ל-Android

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

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

קוד לדוגמה

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

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

להורדת הקוד

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

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

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

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

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

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

הגדרה

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

יחסי תלות

במשימה של הכלי לזיהוי תנועות נעשה שימוש ב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. ב קוד לדוגמה, המודל מוגדר GestureRecognizerHelper.kt file:

baseOptionBuilder.setModelAssetPath(MP_RECOGNIZER_TASK)

יצירת המשימה

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

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

תמונה

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

val optionsBuilder =
    GestureRecognizer.GestureRecognizerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()
gestureRecognizer =
    GestureRecognizer.createFromOptions(context, options)
    

וידאו

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

val optionsBuilder =
    GestureRecognizer.GestureRecognizerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()
gestureRecognizer =
    GestureRecognizer.createFromOptions(context, options)
    

שידור חי

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

val optionsBuilder =
    GestureRecognizer.GestureRecognizerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.LIVE_STREAM)

val options = optionsBuilder.build()
gestureRecognizer =
    GestureRecognizer.createFromOptions(context, options)
    

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

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

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

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

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

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

LIVE_STREAM: המצב לשידור חי של קלט נתונים ממצלמה, במצב הזה, resultListener חייב להיות נשלחה קריאה כדי להגדיר אוזן כדי לקבל תוצאות באופן אסינכרוני.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numHands מספר הידיים המקסימלי שניתן לזהות GestureRecognizer. Any integer > 0 1
minHandDetectionConfidence ציון הסמך המינימלי שצריך להיות זיהוי היד נחשב למוצלח במודל זיהוי כף היד. 0.0 - 1.0 0.5
minHandPresenceConfidence ציון הסמך המינימלי של ציון הנוכחות בכף היד לזיהוי מאפיינים של ציוני דרך. במצב וידאו ובמצב שידור חי באמצעות הכלי לזיהוי תנועות, אם הציון המשוער של נוכחות היד מהמודל של יד הציון מוצג מתחת הסף הזה, הוא מפעיל את המודל לזיהוי כף היד. אחרת, נעשה שימוש באלגוריתם קל למעקב אחר תנועות הידיים כדי לקבוע את המיקום של את הידיים לזיהוי של ציוני הדרך הבאים. 0.0 - 1.0 0.5
minTrackingConfidence ציון הסמך המינימלי שצריך להביא בחשבון את המעקב אחר היד הפעולה הצליחה. זהו סף IoU של התיבה התוחמת בין הידיים הפריים הנוכחי והפריים האחרון. במצב וידאו ובמצב 'זרם' של הכלי לזיהוי תנועות, אם המעקב נכשל, הכלי לזיהוי תנועות מפעיל את היד זיהוי וזיהוי אובייקטים. אחרת, המערכת תדלג על זיהוי היד. 0.0 - 1.0 0.5
cannedGesturesClassifierOptions אפשרויות להגדרת ההתנהגות של מסַווג התנועות המוכנות מראש. התנועות המוכנות מראש הן ["None", "Closed_Fist", "Open_Palm", "Pointing_Up", "Thumb_Down", "Thumb_Up", "Victory", "ILoveYou"]
  • הלוקאל של השמות לתצוגה: הלוקאל שבו צריך להשתמש לשמות לתצוגה שצוינו באמצעות המטא-נתונים של המודלים של TFLite, אם יש כאלה.
  • 'מקסימום תוצאות': המספר המקסימלי של תוצאות הסיווג עם הדירוג הגבוה ביותר שיחזרו. אם < 0, כל התוצאות הזמינות יוחזרו.
  • סף ניקוד: הציון שמתחתיו התוצאות נדחו. אם הוא מוגדר ל-0, יוחזרו כל התוצאות הזמינות.
  • רשימת היתרים של קטגוריות: רשימת ההיתרים של שמות הקטגוריות. אם התוכן לא ריק, לא יתבצע סינון של תוצאות הסיווג שהקטגוריה לא נמצאת בהן בקבוצה הזו. בלעדי באופן הדדי לרשימת הישויות שנחסמו.
  • רשימת קטגוריות שנחסמו: רשימת הישויות שנחסמו. אם השדה לא ריק, תוצאות הסיווג שהקטגוריה שלהן נמצאת בקבוצה הזו יסוננו. בלעדי באופן הדדי עם רשימת היתרים.
    • הלוקאל של השמות המוצגים: any string
    • מקסימום תוצאות: any integer
    • סף הניקוד: 0.0-1.0
    • רשימת היתרים של קטגוריות: vector of strings
    • רשימת קטגוריות שנחסמו: vector of strings
    • הלוקאל של השמות המוצגים: "en"
    • מקסימום תוצאות: -1
    • סף הניקוד: 0
    • רשימת היתרים של קטגוריות: ריקה
    • רשימת הישויות שנחסמו: ריקה
    customGesturesClassifierOptions אפשרויות להגדרת ההתנהגות של מסווג תנועות בהתאמה אישית.
  • הלוקאל של השמות לתצוגה: הלוקאל שבו צריך להשתמש לשמות לתצוגה שצוינו באמצעות המטא-נתונים של המודלים של TFLite, אם יש כאלה.
  • 'מקסימום תוצאות': המספר המקסימלי של תוצאות הסיווג עם הדירוג הגבוה ביותר שיחזרו. אם < 0, כל התוצאות הזמינות יוחזרו.
  • סף ניקוד: הציון שמתחתיו התוצאות נדחו. אם הוא מוגדר ל-0, יוחזרו כל התוצאות הזמינות.
  • רשימת היתרים של קטגוריות: רשימת ההיתרים של שמות הקטגוריות. אם התוכן לא ריק, לא יתבצע סינון של תוצאות הסיווג שהקטגוריה לא נמצאת בהן בקבוצה הזו. בלעדי באופן הדדי לרשימת הישויות שנחסמו.
  • רשימת קטגוריות שנחסמו: רשימת הישויות שנחסמו. אם השדה לא ריק, תוצאות הסיווג שהקטגוריה שלהן נמצאת בקבוצה הזו יסוננו. בלעדי באופן הדדי עם רשימת היתרים.
    • הלוקאל של השמות המוצגים: any string
    • מקסימום תוצאות: any integer
    • סף הניקוד: 0.0-1.0
    • רשימת היתרים של קטגוריות: vector of strings
    • רשימת קטגוריות שנחסמו: vector of strings
    • הלוקאל של השמות המוצגים: "en"
    • מקסימום תוצאות: -1
    • סף הניקוד: 0
    • רשימת היתרים של קטגוריות: ריקה
    • רשימת הישויות שנחסמו: ריקה
    resultListener מגדיר את אוזן התוצאות לקבל את תוצאות הסיווג באופן אסינכרוני כשמזהה התנועה נמצא במצב השידור החי. אפשר להשתמש באפשרות הזו רק כשמצב הריצה מוגדר ל-LIVE_STREAM ResultListener לא רלוונטי לא רלוונטי
    errorListener הגדרת האזנה לשגיאות אופציונלית. ErrorListener לא רלוונטי לא רלוונטי

    הכנת נתונים

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

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

    תמונה

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

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

    הרצת המשימה

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

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

    תמונה

    val result = gestureRecognizer?.recognize(mpImage)
        

    וידאו

    val timestampMs = i * inferenceIntervalMs
    
    gestureRecognizer?.recognizeForVideo(mpImage, timestampMs)
        ?.let { recognizerResult ->
            resultList.add(recognizerResult)
        }
        

    שידור חי

    val mpImage = BitmapImageBuilder(rotatedBitmap).build()
    val frameTime = SystemClock.uptimeMillis()
    
    gestureRecognizer?.recognizeAsync(mpImage, frameTime)
        

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

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

    ב הקוד לדוגמה של מזהה התנועה, recognize, recognizeForVideo וגם פונקציות recognizeAsync מוגדרות GestureRecognizerHelper.kt חדש.

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

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

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

    התוצאה GestureRecognizerResult מכילה ארבעה רכיבים, וכל רכיב הוא מערך שבו כל רכיב מכיל את התוצאה שזוהתה יד אחת שזוהתה.

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

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

    • תנועות

      קטגוריות התנועה שזוהו של הידיים שזוהו.

    • ציוני דרך

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

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

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

    GestureRecognizerResult:
      Handedness:
        Categories #0:
          index        : 0
          score        : 0.98396
          categoryName : Left
      Gestures:
        Categories #0:
          score        : 0.76893
          categoryName : Thumb_Up
      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)
    

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

    ב הקוד לדוגמה של מזהה התנועות, המחלקה GestureRecognizerResultsAdapter ב GestureRecognizerResultsAdapter.kt מטפל בתוצאות.