המשימה 'מזהה תנועות של MediaPipe' מאפשרת לזהות תנועות ידיים בזמן אמת, ומציגה תוצאות מוכרות של תנועות יד וציוני דרך של הידיים שזוהו. בהוראות האלה מוסבר איך להשתמש במזהה התנועות באפליקציות ל-Android. דוגמת הקוד שמתוארת בהוראות האלו זמינה ב-GitHub.
כדי לראות את המשימה הזו בפעולה אפשר לראות את הדגמת האתר. למידע נוסף על היכולות, המודלים ואפשרויות ההגדרה של המשימה הזו, קראו את הסקירה הכללית.
קוד לדוגמה
הקוד לדוגמה של משימות MediaPipe הוא יישום פשוט של אפליקציה לזיהוי תנועות ל-Android. בדוגמה הזו נעשה שימוש במצלמה של מכשיר Android פיזי כדי לזהות באופן רציף תנועות ידיים, ואפשר גם להשתמש בתמונות ובסרטונים מהגלריה במכשיר כדי לזהות תנועות באופן סטטי.
תוכלו להשתמש באפליקציה כנקודת התחלה לאפליקציה שלכם ל-Android, או להתייחס אליה כשאתם משנים אפליקציה קיימת. הקוד לדוגמה של מזהה התנועות מתארח ב-GitHub.
הורדת הקוד
בהוראות הבאות מוסבר איך ליצור עותק מקומי של הקוד לדוגמה באמצעות כלי שורת הפקודה git.
כדי להוריד את הקוד לדוגמה:
- משכפלים את מאגר ה-Git באמצעות הפקודה הבאה:
git clone https://github.com/google-ai-edge/mediapipe-samples
- לחלופין, אפשר להגדיר את מכונת ה-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 – טיפול ועיצוב של התוצאות.
הגדרה
בקטע הזה מתוארים שלבים עיקריים להגדרת סביבת הפיתוח ופרויקטים של קוד במיוחד לשימוש בזיהוי תנועות. במדריך ההגדרה ל-Android תוכלו לקרוא מידע כללי על הגדרת סביבת הפיתוח לשימוש במשימות של MediaPipe, כולל הדרישות לגרסת הפלטפורמה.
יחסי תלות
המשימה של מזהה התנועות משתמשת בספרייה 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
:
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
מטפלת בתוצאות.