המשימה של MediaPipe לזיהוי תנועות מאפשרת לכם לזהות תנועות ידיים בזמן אמת. מספק את התוצאות המוכרות של תנועות הידיים ואת ציוני הדרך של ידיים שזוהו. בהוראות הבאות מוסבר איך להשתמש בכלי לזיהוי תנועות עם אפליקציות ל-Android. דוגמת הקוד שמתוארת בהוראות האלה זמינה ב-GitHub.
אפשר לראות את המשימה הזו בפעולה: הדגמה באינטרנט. מידע נוסף על היכולות, המודלים ואפשרויות ההגדרה במשימה הזאת, ראו סקירה כללית.
קוד לדוגמה
קוד הדוגמה למשימות MediaPipe הוא הטמעה פשוטה של מזהה תנועות. לאפליקציה ל-Android. בדוגמה, המצלמה במכשיר Android פיזי משמשת את המצלמה כדי: לזהות תנועות ידיים באופן שוטף, ולהשתמש בתמונות ובסרטונים הגלריה במכשיר כדי לזהות תנועות באופן סטטי.
אפשר להשתמש באפליקציה כנקודת התחלה של אפליקציה משלכם ל-Android, או להתייחס אליה כשמשנים אפליקציה קיימת. הקוד לדוגמה של מזהה התנועות מתארח במכשיר GitHub.
להורדת הקוד
בהוראות הבאות מוסבר איך ליצור עותק מקומי של הדוגמה באמצעות כלי שורת הפקודה git.
כדי להוריד את הקוד לדוגמה:
- משכפלים את מאגר ה-Git באמצעות הפקודה הבאה:
git clone https://github.com/google-ai-edge/mediapipe-samples
- אפשר גם להגדיר את ה-Git למכונת ה-Git לשימוש בקופה מועטה,
כך שיהיו לכם רק את הקבצים של האפליקציה לדוגמה של הכלי לזיהוי תנועות:
cd mediapipe git sparse-checkout init --cone git sparse-checkout set examples/gesture_recognizer/android
אחרי שיוצרים גרסה מקומית של הקוד לדוגמה, אפשר לייבא את הפרויקט אל Android Studio ולהריץ את האפליקציה. הוראות מופיעות מדריך ההגדרה ל-Android.
רכיבים מרכזיים
הקבצים הבאים מכילים את הקוד החיוני לתנועת היד הזו אפליקציה לדוגמה לזיהוי:
- GestureRecognizerHelper.kt - הפעלת מזהה התנועה וטיפול במודל ובהענקת הגישה בחירה.
- MainActivity.kt -
מטמיע את האפליקציה, כולל קריאה ל-
GestureRecognizerHelper
ולGestureRecognizerResultsAdapter
- GestureRecognizerResultsAdapter.kt – טיפול בתוצאות ובעיצוב שלהן.
הגדרה
בקטע הזה מתוארים השלבים העיקריים להגדרת סביבת הפיתוח פרויקטי קוד במיוחד לשימוש בזיהוי תנועות. למידע כללי על להגדיר את סביבת הפיתוח לשימוש במשימות של 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"] |
|
|
|
customGesturesClassifierOptions |
אפשרויות להגדרת ההתנהגות של מסווג תנועות בהתאמה אישית. |
|
|
|
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
מטפל בתוצאות.