إعداد دليل رصد المعالم في Android

تتيح لك مهمة MediaPipe Pose Landmarker رصد معالم أجسام البشر في صورة أو فيديو. يمكنك استخدام هذه المهمة لتحديد مواضع الجسم الرئيسية وتحليل الوضع و تصنيف الحركات. تستخدِم هذه المهمة نماذج تعلُّم الآلة التي تعمل مع الصور أو الفيديوهات الفردية. تُخرج المهمة معالم وضع الجسم في إحداثيات الصورة وفي إحداثيات العالم الثلاثية الأبعاد.

يتوفّر نموذج الرمز البرمجي الموضّح في هذه التعليمات على 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/pose_landmarker/android
    

بعد إنشاء نسخة محلية من رمز المثال، يمكنك استيراد المشروع إلى Android Studio وتشغيل التطبيق. للحصول على التعليمات، اطّلِع على دليل الإعداد لنظام Android.

المكونات الرئيسية

تحتوي الملفات التالية على الرمز البرمجي المهم لهذا المثال على تطبيق وضع علامات على معالم الوضع:

  • PoseLandmarkerHelper.kt: لإعداد علامة موضع الوضع ومعالجة النموذج وتحديد المفوَّض
  • CameraFragment.kt: تعالج بيانات إدخال الصور والفيديوهات وتتعامل مع كاميرا الجهاز.
  • GalleryFragment.kt: تتفاعل مع OverlayView لعرض الصورة أو الفيديو الناتج.
  • OverlayView.kt: تُنفِّذ هذه الفئة عرض الوضعيات التي تم رصدها.

ضبط إعدادات الجهاز

يوضّح هذا القسم الخطوات الرئيسية لإعداد بيئة التطوير و مشاريع الرموز البرمجية لاستخدام أداة "وضع علامات على العناصر في اللقطة" خصيصًا. للحصول على معلومات عامة حول إعداد بيئة التطوير لاستخدام مهام MediaPipe، بما في ذلك requirements لإصدار النظام الأساسي، يُرجى الاطّلاع على دليل الإعداد لنظام Android.

التبعيات

تستخدِم مهمة "مُحدِّد مَعلمات الوضع" مكتبة com.google.mediapipe:tasks-vision. أضِف هذه التبعية إلى ملف build.gradle لتطبيق Android:

dependencies {
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

الطراز

تتطلّب مهمة MediaPipe Pose Landmarker حِزمة نموذج مدرَّب متوافقة مع هذه المهمة. لمزيد من المعلومات عن النماذج المدربة المتاحة لميزة "وضع علامات على نقاط الجسد"، اطّلِع على قسم النظرة العامة على المهمة قسم "النماذج".

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

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

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

val modelName = "pose_landmarker_lite.task"
baseOptionsBuilder.setModelAssetPath(modelName)

إنشاء المهمة

تستخدِم مهمة MediaPipe Pose Landmarker الدالة createFromOptions() لإعداد المهمة. تقبل الدالة createFromOptions() قيمًا لإعدادات options. لمزيد من المعلومات حول خيارات الضبط، يُرجى الاطّلاع على خيارات الضبط.

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

صورة

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

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()
poseLandmarker = poseLandmarker.createFromOptions(context, options)
    

فيديو

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

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()
poseLandmarker = poseLandmarker.createFromOptions(context, options)
    

بث مباشر

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

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.LIVE_STREAM)

val options = optionsBuilder.build()
poseLandmarker = poseLandmarker.createFromOptions(context, options)
    

يتيح مثال تنفيذ رمز "مُحدِّد مَعلمات الوضع" للمستخدم التبديل بين أوضاع المعالجة. تؤدي هذه الطريقة إلى جعل رمز إنشاء المهام أكثر تعقيدًا، وقد لا يكون مناسبًا لحالة الاستخدام. يمكنك الاطّلاع على هذا الرمز في دالة setupPoseLandmarker() في ملف PoseLandmarkerHelper.kt.

خيارات الضبط

تتضمّن هذه المهمة خيارات الضبط التالية لتطبيقات Android:

اسم الخيار الوصف نطاق القيمة القيمة التلقائية
runningMode لضبط وضع التشغيل للمهمة هناك ثلاثة أوضاع:

IMAGE: وضع الإدخالات باستخدام صورة واحدة.

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

LIVE_STREAM: وضع البث المباشر لبيانات الإدخال ، مثل بيانات الكاميرا في هذا الوضع، يجب استدعاء resultListener لإعداد مستمع لتلقّي النتائج بشكل غير متزامن.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numposes الحد الأقصى لعدد الوضعيات التي يمكن رصدها من خلال أداة وضع علامات على العناصر Integer > 0 1
minPoseDetectionConfidence الحد الأدنى لنتيجة الثقة ليعتبر رصد الوضعان ناجحًا Float [0.0,1.0] 0.5
minPosePresenceConfidence الحد الأدنى لنتيجة الثقة في توفّر الوضع في عملية رصد معالم الوضع Float [0.0,1.0] 0.5
minTrackingConfidence الحد الأدنى لنتيجة الثقة لتتبُّع الوضع ليكون ناجحاً Float [0.0,1.0] 0.5
outputSegmentationMasks ما إذا كان عنصر وضع المَعلمات يُخرج قناعًا لتقسيم العناصر للوضع الذي تم رصده Boolean False
resultListener يضبط مستمع النتائج لتلقّي نتائج علامة المَعلمة بشكل غير متزامن عندما تكون علامة مَعلمة الوضع في وضع البث المباشر. لا يمكن استخدامها إلا عند ضبط وضع التشغيل على LIVE_STREAM ResultListener N/A
errorListener تُستخدَم لضبط مستمع أخطاء اختياري. ErrorListener N/A

إعداد البيانات

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

يوضّح الرمز البرمجي التالي كيفية تسليم البيانات لمعالجتها. تتضمّن هذه النماذج تفاصيل عن كيفية التعامل مع البيانات من الصور وملفات الفيديو وعمليات البث المباشر للفيديو.

صورة

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

في مثال رمز علامة موضع الجسم، يتم التعامل مع إعداد البيانات في ملف PoseLandmarkerHelper.kt.

تنفيذ المهمة

استنادًا إلى نوع البيانات التي تعمل معها، استخدِم طريقة poseLandmarker.detect...() الخاصة بهذا النوع من البيانات. استخدِم detect() للصور الفردية وdetectForVideo() للإطارات في ملفات الفيديو وdetectAsync() لأحداث بث الفيديو. عند إجراء عمليات رصد في مجرى فيديو، تأكَّد من تشغيل عمليات الرصد في سلسلة محادثات منفصلة لتجنُّب حظر سلسلة محادثات المستخدم.

تعرض عيّنات الرموز البرمجية التالية أمثلة بسيطة على كيفية تشغيل ميزة "وضع علامات على معالم الوضع" في أوضاع البيانات المختلفة التالية:

صورة

val result = poseLandmarker.detect(mpImage)
    

فيديو

val timestampMs = i * inferenceIntervalMs

poseLandmarker.detectForVideo(mpImage, timestampMs)
    .let { detectionResult ->
        resultList.add(detectionResult)
    }
    

بث مباشر

val mpImage = BitmapImageBuilder(rotatedBitmap).build()
val frameTime = SystemClock.uptimeMillis()

poseLandmarker.detectAsync(mpImage, frameTime)
    

يُرجى ملاحظة ما يلي:

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

في رمز مثال علامة موضع الجسم، تم تحديد الدوال detect وdetectForVideo و detectAsync في ملف PoseLandmarkerHelper.kt.

معالجة النتائج وعرضها

يعرض عنصر وضع الجسم poseLandmarkerResult لكل عملية الكشف. يحتوي عنصر النتيجة على إحداثيات لكلّ معلمة في الوضع.

في ما يلي مثال على بيانات الإخراج من هذه المهمة:

PoseLandmarkerResult:
  Landmarks:
    Landmark #0:
      x            : 0.638852
      y            : 0.671197
      z            : 0.129959
      visibility   : 0.9999997615814209
      presence     : 0.9999984502792358
    Landmark #1:
      x            : 0.634599
      y            : 0.536441
      z            : -0.06984
      visibility   : 0.999909
      presence     : 0.999958
    ... (33 landmarks per pose)
  WorldLandmarks:
    Landmark #0:
      x            : 0.067485
      y            : 0.031084
      z            : 0.055223
      visibility   : 0.9999997615814209
      presence     : 0.9999984502792358
    Landmark #1:
      x            : 0.063209
      y            : -0.00382
      z            : 0.020920
      visibility   : 0.999976
      presence     : 0.999998
    ... (33 world landmarks per pose)
  SegmentationMasks:
    ... (pictured below)

يحتوي الإخراج على كلّ من الإحداثيات العادية (Landmarks) وإحداثيات العالم (WorldLandmarks) لكلّ معلم.

يحتوي الإخراج على الإحداثيات التالية (Landmarks) التي تم تسويتها:

  • x وy: إحداثيات المَعلمة التي تم تسويتها بين 0.0 و1.0 حسب عرض الصورة (x) وارتفاعها (y).

  • z: عمق المَعلم، مع تحديد عمق منتصف الوركين كنقطة المنشأ وكلما كانت القيمة أصغر، كان المَعلم أقرب إلى الكاميرا. يستخدم حجم z المقياس نفسه تقريبًا المستخدَم في x.

  • visibility: احتمال ظهور المَعلمة في الصورة

يحتوي الإخراج على إحداثيات العالم التالية (WorldLandmarks):

  • x وy وz: إحداثيات ثلاثية الأبعاد في العالم الواقعي بالمتر، مع تحديد نقطة وسط الوركين كمصدر.

  • visibility: احتمال ظهور المَعلمة في الصورة

تعرض الصورة التالية عرضًا مرئيًا لمعدّل تكرار المهمة:

امرأة في وضعية تأمل تم تمييز وضعها باستخدام إطار شبكي يشير إلى موضع أطرافها وجذعها.

يمثّل قناع التقسيم الاختياري احتمالية أن تنتمي كل بكسل إلى شخص تم رصده. الصورة التالية هي قناع تقسيم لمخرجات المهمة:

قناع تقسيم للصورة السابقة يحدّد شكل المرأة

يوضّح مثال رمز علامة موضع الجسم كيفية عرض النتائج المعروضة من المهمة، اطّلِع على فئة OverlayView لمزيد من التفاصيل.