خيارات تصنيف الوضع

باستخدام واجهة برمجة التطبيقات ML Kit Pose Detection، يمكنك الحصول على تفسيرات مفيدة للوضعية من خلال التحقق من المواضع النسبية لمختلف أجزاء الجسم. هذه الصفحة وتوضح بعض الأمثلة.

وضع التصنيف وعدّ التكرار باستخدام خوارزمية k-NN

يعد تتبع اللياقة البدنية أحد أكثر التطبيقات شيوعًا لاكتشاف وضعية الجسم. إنشاء مصنف للوضعيات يتعرف على أوضاع وإحصاءات اللياقة البدنية المحددة يمكن أن يكون التكرار إنجازًا صعبًا للمطورين.

سنصف في هذا القسم كيف صمّمنا وضعًا مخصّصًا. مصنِّف باستخدام MediaPipe Colab توضيح طريقة عمل مُصنِّفة في تطبيق نموذج حزمة تعلُّم الآلة.

إذا لم تكن معتادًا على استخدام Google Colaboratory، يُرجى الاطّلاع على دليل المقدمة.

من أجل التعرّف على الوضعيات، نستخدم خوارزمية الجار الأقرب (k-NN) لأنّها بسيطة وسهلة البدء. تحدد الخوارزمية فئة الكائن بناءً على العينات الأقرب في التطبيق.

اتّبع الخطوات التالية لإنشاء أداة التعرّف وتدريبها:

1. جمع عيّنات من الصور

جمعنا عيّنات من الصور للتمارين الهدف من مصادر مختلفة. أر اختيار بضع مئات من الصور لكل تمرين، مثل "أعلى" و"أسفل" المواضع لتمرينات الضغط. من المهم جمع العيّنات التي تغطي كاميرا مختلفة الزوايا والظروف البيئية وأشكال الجسم والاختلافات في التمارين الرياضية.

الشكل 1 وضعيات تمارين الضغط للأعلى وللأسفل

2. شغِّل ميزة "رصد الوضعية" على عيّنات الصور

وينتج عن ذلك مجموعة من معالم الوضع التي سيتم استخدامها للتدريب. لسنا تهتم باكتشاف الوضعية نفسها، حيث إننا سنتدرب على نموذجك الخاص في الخطوة التالية.

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

لتحويل معالم وضعية إلى متجه الخصائص، نستخدم المسافات الزوجية بين القوائم المحددة مسبقًا لمفاصل وضعية الجسم، مثل المسافة بين المعصم والكتف والكاحل والورك، والمعصمَين الأيسر والأيمن. نظرًا لأن مقياس الصور يمكن أن يختلف، قمنا بضبط الوضعيات ليكون لها نفس حجم الجذع والجذع العمودي الاتجاه قبل تحويل المعالم.

3- تدريب النموذج واحتساب مرات التكرار

استخدمنا MediaPipe Colab للوصول إلى رمز المصنِّف لتدريب النموذج.

لحساب التكرارات، استخدمنا خوارزمية Colab أخرى لمراقبة احتمالية الحد الأدنى للوضع المستهدف. على سبيل المثال:

  • عندما تكون احتمالية "انخفاض" فئة الوضعية تجتاز حدًا معينًا لأول مرة، تشير الخوارزمية إلى أن القيمة "أسفل" إدخال فئة الوضع.
  • فعندما تنخفض الاحتمالية إلى أقل من الحد الأدنى، تحدد الخوارزمية "أسفل" تم الخروج من فئة الوضع وزادت من العدّاد.
الشكل 2. مثال على احتساب التكرار

4. الدمج مع تطبيق البدء السريع في حزمة تعلّم الآلة

تنشئ Colab أعلاه ملف CSV يمكنك تعبئته بكل وضعيات العينات. في هذا القسم، ستتعلم كيفية دمج ملف CSV مع يتيح لك ML Kit تطبيق البدء السريع على Android للاطّلاع على تصنيف الوضع المخصّص في الوقت الفعلي.

تجربة تصنيف الصور باستخدام عيّنات مضمَّنة في تطبيق Quickstart

  • الحصول على مشروع تطبيق البدء السريع في Android باستخدام ML Kit من جيت هب والتأكد من أنه يعمل بشكل جيد.
  • يمكنك الانتقال إلى LivePreviewActivity وتفعيل ميزة "رصد الوضع" Run classification. من "الإعدادات" . الآن ينبغي أن تكون قادرًا على تصنيف تمارين الضغط والقرفصاء.

إضافة ملف CSV الخاص بك

  • أضِف ملف CSV إلى مجلد مواد العرض في التطبيق.
  • في PoseClassifierProcessor، عدِّل متغيّري POSE_SAMPLES_FILE وPOSE_CLASSES لمطابقة ملف CSV ووضع النماذج.
  • أنشئ التطبيق وشغِّله.

لاحظ أن التصنيف قد لا يعمل بشكل جيد إذا لم تكن هناك عينات كافية. بشكل عام، تحتاج إلى حوالي 100 عينة لكل فئة من الوضع.

لمزيد من المعلومات وتجربة هذه الميزة بنفسك، يمكنك الاطّلاع على MediaPipe Colab. ودليل تصنيف MediaPipe.

التعرف على الإيماءات البسيطة من خلال حساب مسافة المعالم

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

الشكل 3. تفسير الوضعية

التعرّف على وضعية اليوغا من خلال إرشادات مفصّلة حول اليوغا

يمكنك التعرّف على وضعية اليوغا من خلال حساب زوايا المفاصل المختلفة. بالنسبة على سبيل المثال، يوضح الشكل 2 أدناه وضعية يوغا المحارب الثاني. الزوايا التقريبية التي تحدد هذه الوضعية مكتوبة باللغة:

الشكل 4 تقسيم الوضعية إلى زوايا

يمكن وصف هذه الوضعية على أنها التركيبة التالية من الجسم التقريبي. زوايا الأجزاء:

  • زاوية 90 درجة عند كلا الكتفَين
  • 180 درجة عند المرفقين
  • بزاوية 90 درجة للساق الأمامية والخصر
  • بزاوية 180 درجة للركبة الخلفية
  • زاوية تبلغ 135 درجة عند الخصر

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

بعد حساب جميع الزوايا اللازمة لتحديد الوضعية، يمكنك التحقق من لترى ما إذا كان هناك تطابق، وفي هذه الحالة تعرفت على الوضعية.

يوضح مقتطف الرمز أدناه كيفية استخدام إحداثيي X وY لحساب الزاوية بين جزأين من الجسم. يعد هذا النهج في التصنيف لبعض القيود. من خلال فحص س و ص فقط، تختلف الزوايا المحسوبة وفقًا للزاوية بين الهدف والكاميرا. ستحصل على أفضل النتائج من خلال صورة رأسية ذات مستوٍ ومباشرة. يمكنك أيضًا حاول توسيع هذه الخوارزمية بالاستفادة من الإحداثي Z ونرى ما إذا كان يعمل بشكل أفضل لحالة الاستخدام أم لا.

حساب زوايا المعالم على Android

تحسب الطريقة التالية الزاوية بين أي ثلاثة المعالم. ويضمن أن الزاوية التي يتم إرجاعها بين 0 و180 درجة.

Kotlin

fun getAngle(firstPoint: PoseLandmark, midPoint: PoseLandmark, lastPoint: PoseLandmark): Double {
        var result = Math.toDegrees(atan2(lastPoint.getPosition().y - midPoint.getPosition().y,
                lastPoint.getPosition().x - midPoint.getPosition().x)
                - atan2(firstPoint.getPosition().y - midPoint.getPosition().y,
                firstPoint.getPosition().x - midPoint.getPosition().x))
        result = Math.abs(result) // Angle should never be negative
        if (result > 180) {
            result = 360.0 - result // Always get the acute representation of the angle
        }
        return result
    }

Java

static double getAngle(PoseLandmark firstPoint, PoseLandmark midPoint, PoseLandmark lastPoint) {
  double result =
        Math.toDegrees(
            atan2(lastPoint.getPosition().y - midPoint.getPosition().y,
                      lastPoint.getPosition().x - midPoint.getPosition().x)
                - atan2(firstPoint.getPosition().y - midPoint.getPosition().y,
                      firstPoint.getPosition().x - midPoint.getPosition().x));
  result = Math.abs(result); // Angle should never be negative
  if (result > 180) {
      result = (360.0 - result); // Always get the acute representation of the angle
  }
  return result;
}

في ما يلي طريقة حساب الزاوية عند الورك الأيمن:

Kotlin

val rightHipAngle = getAngle(
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE))

Java

double rightHipAngle = getAngle(
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE));

حساب زوايا المعالم في نظام التشغيل iOS

تحسب الطريقة التالية الزاوية بين أي ثلاثة المعالم. ويضمن أن الزاوية التي يتم إرجاعها بين 0 و180 درجة.

Swift

func angle(
      firstLandmark: PoseLandmark,
      midLandmark: PoseLandmark,
      lastLandmark: PoseLandmark
  ) -> CGFloat {
      let radians: CGFloat =
          atan2(lastLandmark.position.y - midLandmark.position.y,
                    lastLandmark.position.x - midLandmark.position.x) -
            atan2(firstLandmark.position.y - midLandmark.position.y,
                    firstLandmark.position.x - midLandmark.position.x)
      var degrees = radians * 180.0 / .pi
      degrees = abs(degrees) // Angle should never be negative
      if degrees > 180.0 {
          degrees = 360.0 - degrees // Always get the acute representation of the angle
      }
      return degrees
  }

Objective-C

(CGFloat)angleFromFirstLandmark:(MLKPoseLandmark *)firstLandmark
                      midLandmark:(MLKPoseLandmark *)midLandmark
                     lastLandmark:(MLKPoseLandmark *)lastLandmark {
    CGFloat radians = atan2(lastLandmark.position.y - midLandmark.position.y,
                            lastLandmark.position.x - midLandmark.position.x) -
                      atan2(firstLandmark.position.y - midLandmark.position.y,
                            firstLandmark.position.x - midLandmark.position.x);
    CGFloat degrees = radians * 180.0 / M_PI;
    degrees = fabs(degrees); // Angle should never be negative
    if (degrees > 180.0) {
        degrees = 360.0 - degrees; // Always get the acute representation of the angle
    }
    return degrees;
}

في ما يلي طريقة حساب الزاوية عند الورك الأيمن:

Swift

let rightHipAngle = angle(
      firstLandmark: pose.landmark(ofType: .rightShoulder),
      midLandmark: pose.landmark(ofType: .rightHip),
      lastLandmark: pose.landmark(ofType: .rightKnee))

Objective-C

CGFloat rightHipAngle =
    [self angleFromFirstLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightShoulder]
                     midLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightHip]
                    lastLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightKnee]];