دليل التعرّف على الإيماءات لنظام التشغيل Android

تتيح لك مهمة MediaPipe Gesture Recognizer (معرّف إيماءات MediaPipe) التعرّف على إيماءات اليد في الوقت الفعلي، و توفّر نتائج إيماءات اليد التي تم التعرّف عليها ومَعلمات اليد للأيدي التي تم رصدها. توضِّح لك هذه التعليمات كيفية استخدام ميزة "التعرّف على الإيماءات" مع تطبيقات Android. يتوفّر نموذج الرمز البرمجي الموضّح في هذه التعليمات على GitHub.

يمكنك الاطّلاع على هذه المهمة وهي قيد التنفيذ من خلال الاطّلاع على الإصدار التجريبي على الويب. لمزيد من المعلومات عن الإمكانات والنماذج وخيارات الضبط لهذه المهمة، اطّلِع على نظرة عامة.

مثال على الرمز البرمجي

مثال رمز MediaPipe Tasks هو تطبيق بسيط لنظام التشغيل Android يُستخدَم لرصد الإيماءات. يستخدم المثال الكاميرا على جهاز Android مادي لرصد إيماءات اليد باستمرار، ويمكنه أيضًا استخدام الصور والفيديوهات من معرض الصور على الجهاز لرصد الإيماءات بشكل ثابت.

يمكنك استخدام التطبيق كنقطة بداية لتطبيق Android الخاص بك، أو الرجوع إليه عند تعديل تطبيق حالي. يتم استضافة مثال رمز معرّف الإيماءات على GitHub.

تنزيل الرمز

توضِّح لك التعليمات التالية كيفية إنشاء نسخة محلية من مثال الرمز البرمجي باستخدام أداة سطر الأوامر git.

لتنزيل نموذج الرمز البرمجي:

  1. استنسِخ مستودع git باستخدام الأمر التالي:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. يمكنك اختياريًا ضبط مثيل git لاستخدام ميزة "الفحص الخفيف"، لكي لا تتوفّر لديك سوى ملفات مثال تطبيق "معرّف الإيماءات":
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/gesture_recognizer/android
    

بعد إنشاء نسخة محلية من رمز المثال، يمكنك استيراد المشروع إلى "استوديو Android" وتشغيل التطبيق. للحصول على التعليمات، اطّلِع على دليل الإعداد لنظام التشغيل 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 Gesture Recognizer حِزمة نموذج مدرَّب متوافقة مع هذه المهمة. لمزيد من المعلومات عن النماذج المدربة المتاحة لميزة "التعرّف على الإيماءات"، اطّلِع على النظرة العامة على المهمة في قسم "النماذج".

اختَر النموذج ونزِّله واحفظه في دليل مشروعك:

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

حدِّد مسار النموذج ضمن المَعلمة ModelAssetPath. في المثال التالي على الرمز، يتم تحديد التصميم في ملف GestureRecognizerHelper.kt:

baseOptionBuilder.setModelAssetPath(MP_RECOGNIZER_TASK)

إنشاء المهمة

تستخدِم مهمة MediaPipe Gesture Recognizer الدالة 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: وضع الإدخالات باستخدام صورة واحدة.

‫VIDEO: وضع الإطارات التي تم فك ترميزها في الفيديو

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 النتائج.