دليل تصنيف الصور لنظام التشغيل Android

تتيح لك مهمة مصنِّف صور MediaPipe تصنيف الصور. يمكنك استخدام هذه المهمة لتحديد ما تمثله الصورة بين مجموعة من الفئات المحددة في وقت التدريب. توضّح لك هذه التعليمات كيفية استخدام "مصنِّف الصور" مع تطبيقات Android. يتوفر نموذج التعليمات البرمجية الموضح في هذه التعليمات على GitHub.

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

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

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

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

تنزيل الرمز

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

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

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

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

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

تحتوي الملفات التالية على التعليمات البرمجية المهمة لمثال تصنيف الصور هذا:

  • ImageClassifierHelper.kt - يهيأ مصنِّف الصور ويعالج النموذج واختيار التفويض.
  • MainActivity.kt - ينفّذ التطبيق، بما في ذلك طلب البيانات من ImageClassificationHelper وClassificationResultsAdapter.
  • ClassificationResultsAdapter.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

استخدِم الطريقة BaseOptions.Builder.setModelAssetPath() لتحديد المسار الذي يستخدمه النموذج. يشار إلى هذه الطريقة في مثال التعليمة البرمجية في القسم التالي.

في مثال الرمز على "مصنِّف الصور"، يتم تحديد النموذج في ملف ImageClassifierHelper.kt.

إنشاء المهمة

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

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

صورة

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.IMAGE)
    .setMaxResults(5)
    .build();
imageClassifier = ImageClassifier.createFromOptions(context, options);
    

فيديو

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.VIDEO)
    .setMaxResults(5)
    .build();
imageClassifier = ImageClassifier.createFromOptions(context, options);
    

البث المباشر

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setMaxResults(5)
    .setResultListener((result, inputImage) -> {
         // Process the classification result here.
    })
    .setErrorListener((result, inputImage) -> {
         // Process the classification errors here.
    })
    .build()
imageClassifier = ImageClassifier.createFromOptions(context, options)
    

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

خيارات الإعداد

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

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

IMAGE: هو الوضع الخاص بإدخالات الصور الفردية.

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

LIVE_STREAM: وضع البث المباشر لبيانات الإدخال، مثل الكاميرا. في هذا الوضع، يجب استدعاء كائن resultsListener لإعداد أداة استماع لتلقّي النتائج بشكل غير متزامن.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
displayNamesLocale لضبط لغة التصنيفات المراد استخدامها للأسماء المعروضة المقدمة في البيانات الوصفية لنموذج المهمة، إذا كانت متوفرة. اللغة التلقائية هي en للغة الإنجليزية. يمكنك إضافة تصنيفات مترجَمة إلى البيانات الوصفية لنموذج مخصّص باستخدام TensorFlow Lite Metadata Writer API. رمز اللغة en
maxResults تحدد الحد الأقصى الاختياري لنتائج تصنيف أعلى الدرجات لعرضها. وإذا كانت < 0، سيتم عرض جميع النتائج المتاحة. أي أرقام موجبة -1
scoreThreshold لتعيين الحد الأدنى لنتيجة التوقعات الذي يلغي الحد المقدم في البيانات الوصفية للنموذج (إن وُجد). يتم رفض النتائج التي تكون أدنى من هذه القيمة. أي عدد عائم لم يتم التحديد
categoryAllowlist تضبط هذه السياسة القائمة الاختيارية لأسماء الفئات المسموح بها. إذا كانت غير فارغة، فستتم تصفية نتائج التصنيف التي لا يوجد اسم الفئة لها في هذه المجموعة. ويتم تجاهل أسماء الفئات المكرّرة أو غير المعروفة. لا يقتصر استخدام هذا الخيار على categoryDenylist ويؤدي استخدام كلاهما إلى حدوث خطأ. أي سلاسل لم يتم التحديد
categoryDenylist تحدِّد هذه السياسة القائمة الاختيارية لأسماء الفئات غير المسموح بها. إذا كانت غير فارغة، فسيتم تصفية نتائج التصنيف التي يكون اسم الفئة في هذه المجموعة بها. ويتم تجاهل أسماء الفئات المكرّرة أو غير المعروفة. لا يقتصر استخدام هذا الخيار على categoryAllowlist ويؤدي استخدام كلا الخيارين إلى حدوث خطأ. أي سلاسل لم يتم التحديد
resultListener تضبط أداة معالجة النتائج على تلقّي نتائج التصنيف بشكل غير متزامن عندما يكون "مصنِّف الصور" في وضع البث المباشر. لا يمكن استخدام الإذن إلا عند ضبط "وضع التشغيل" على LIVE_STREAM لا ينطبق لم يتم التحديد
errorListener تضبط هذه السياسة أداة معالجة للأخطاء اختيارية. لا ينطبق لم يتم التحديد

تجهيز البيانات

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

يجب تحويل الصورة أو الإطار المُدخل إلى عنصر com.google.mediapipe.framework.image.MPImage قبل تمريره إلى مصنِّف الصور.

صورة

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load an image on the user’s device as a Bitmap object using BitmapFactory.

// Convert an Android’s Bitmap object to a MediaPipe’s Image object.
Image mpImage = new BitmapImageBuilder(bitmap).build();
    

فيديو

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load a video file on the user's device using MediaMetadataRetriever

// From the video’s metadata, load the METADATA_KEY_DURATION and
// METADATA_KEY_VIDEO_FRAME_COUNT value. You’ll need them
// to calculate the timestamp of each frame later.

// Loop through the video and load each frame as a Bitmap object.

// Convert the Android’s Bitmap object to a MediaPipe’s Image object.
Image mpImage = new BitmapImageBuilder(frame).build();
    

البث المباشر

import com.google.mediapipe.framework.image.MediaImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Create a CameraX’s ImageAnalysis to continuously receive frames 
// from the device’s camera. Configure it to output frames in RGBA_8888
// format to match with what is required by the model.

// For each Android’s ImageProxy object received from the ImageAnalysis, 
// extract the encapsulated Android’s Image object and convert it to 
// a MediaPipe’s Image object.
android.media.Image mediaImage = imageProxy.getImage()
Image mpImage = new MediaImageBuilder(mediaImage).build();
    

في مثال الرمز البرمجي لمصنّف الصور، تتم معالجة إعداد البيانات في ملف ImageClassifierHelper.kt.

تنفيذ المهمة

يمكنك استدعاء الدالة classify المرتبطة بوضع الجري لعرض الاستنتاجات. تعرض واجهة برمجة التطبيقات Image Classifier API الفئات المحتملة للعنصر داخل الصورة أو الإطار الذي تم إدخاله.

صورة

ImageClassifierResult classifierResult = imageClassifier.classify(image);
    

فيديو

// Calculate the timestamp in milliseconds of the current frame.
long frame_timestamp_ms = 1000 * video_duration * frame_index / frame_count;

// Run inference on the frame.
ImageClassifierResult classifierResult =
    imageClassifier.classifyForVideo(image, frameTimestampMs);
    

البث المباشر


// Run inference on the frame. The classifications results will be available 
// via the `resultListener` provided in the `ImageClassifierOptions` when 
// the image classifier was created.
imageClassifier.classifyAsync(image, frameTimestampMs);
    

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

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

في الرمز البرمجي الخاص بمثال "مصنِّف الصور"، يتم تحديد دوال classify في ملف ImageClassifierHelper.kt.

التعامل مع العملاء وعرض النتائج

عند تنفيذ الاستنتاج، تعرض مهمة "مصنِّف الصور" الكائن ImageClassifierResult الذي يحتوي على قائمة الفئات المحتملة للكائنات داخل الصورة أو الإطار الذي تم إدخاله.

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

ImageClassifierResult:
 Classifications #0 (single classification head):
  head index: 0
  category #0:
   category name: "/m/01bwb9"
   display name: "Passer domesticus"
   score: 0.91406
   index: 671
  category #1:
   category name: "/m/01bwbt"
   display name: "Passer montanus"
   score: 0.00391
   index: 670

تم الحصول على هذه النتيجة من خلال تشغيل مصنِّف الطيور على:

في مثال الرمز البرمجي لمصنّف الصور، تعالج الفئة ClassificationResultsAdapter في الملف ClassificationResultsAdapter.kt النتائج:

fun updateResults(imageClassifierResult: ImageClassifierResult? = null) {
    categories = MutableList(adapterSize) { null }
    if (imageClassifierResult != null) {
        val sortedCategories = imageClassifierResult.classificationResult()
            .classifications()[0].categories().sortedBy { it.index() }
        val min = kotlin.math.min(sortedCategories.size, categories.size)
        for (i in 0 until min) {
            categories[i] = sortedCategories[i]
        }
    }
}