تتيح لك مهمة "تصنيف الصور" من MediaPipe إجراء تصنيف للصور. يمكنك استخدام هذه المهمة لتحديد ما تمثله الصورة من بين مجموعة من الفئات المحدّدة في وقت التدريب. توضِّح لك هذه التعليمات كيفية استخدام "أداة تصنيف الصور" مع تطبيقات Android. يتوفّر نموذج الرمز البرمجي الموضّح في هذه التعليمات على GitHub.
يمكنك الاطّلاع على هذه المهمة أثناء تنفيذها من خلال مشاهدة الإصدار التجريبي على الويب. لمزيد من المعلومات عن الإمكانات والنماذج وخيارات الضبط لهذه المهمة، اطّلِع على نظرة عامة.
مثال على الرمز البرمجي
مثال رمز MediaPipe Tasks هو تطبيق مصنّف صور بسيط لنظام التشغيل 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/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: وضع الإدخالات باستخدام صورة واحدة. VIDEO: وضع الإطارات التي تم فك ترميزها في الفيديو LIVE_STREAM: وضع البث المباشر لبيانات الإدخال ، مثل بيانات الكاميرا في هذا الوضع، يجب استدعاء resultListener لإعداد مستمع لتلقّي النتائج بشكل غير متزامن. |
{IMAGE, VIDEO, LIVE_STREAM } |
IMAGE |
displayNamesLocale |
لضبط لغة التصنيفات لاستخدامها في الأسماء المعروضة المقدَّمة في
البيانات الوصفية لنموذج المهمة، في حال توفّرها. القيمة التلقائية هي en لعبارة
English. يمكنك إضافة تصنيفات مترجَمة إلى البيانات الوصفية لنموذج مخصّص
باستخدام واجهة برمجة التطبيقات TensorFlow Lite Metadata Writer API. |
رمز اللغة | en |
maxResults |
تُستخدَم لتحديد الحد الأقصى الاختياري لعدد نتائج التصنيف التي ستعرضها. إذا كان < 0، سيتم عرض جميع النتائج المتاحة. | أي أرقام موجبة | -1 |
scoreThreshold |
تُستخدَم لضبط الحدّ الأدنى لنتيجة التوقّع الذي يتجاوز الحدّ الأدنى المقدَّم في البيانات الوصفية للنموذج (إن توفّرت). ويتم رفض النتائج التي تقلّ عن هذه القيمة. | أيّ عائمة | لم يتم الضبط |
categoryAllowlist |
لضبط القائمة الاختيارية لأسماء الفئات المسموح بها. إذا لم تكن فارغة،
سيتم استبعاد نتائج التصنيف التي لا يتضمّن اسم فئتها هذه المجموعة. ويتم تجاهل أسماء الفئات المكرّرة أو غير المعروفة.
هذا الخيار غير متوافق مع الخيار categoryDenylist ، ويؤدي استخدام
كلا الخيارَين إلى حدوث خطأ. |
أي سلاسل | لم يتم الضبط |
categoryDenylist |
لضبط القائمة الاختيارية لأسماء الفئات غير المسموح بها. إذا كانت هذه المجموعة ليست فارغة، سيتم فلترة نتائج التصنيف التي يكون اسم فئتها في هذه المجموعة. ويتم تجاهل أسماء الفئات المكرّرة أو غير المعروفة. هذا الخيار متناقض
مع الخيار categoryAllowlist ، ويؤدي استخدام كليهما إلى حدوث خطأ. |
أي سلاسل | لم يتم الضبط |
resultListener |
ضبط مستمع النتائج لتلقّي نتائج التصنيف
بشكل غير متزامن عندما يكون "تصنيف الصور" في وضع البث المباشر
لا يمكن استخدامها إلا عند ضبط وضع التشغيل على LIVE_STREAM |
لا ينطبق | لم يتم الضبط |
errorListener |
تُستخدَم لضبط مستمع أخطاء اختياري. | لا ينطبق | لم يتم الضبط |
إعداد البيانات
يعمل "تصنيف الصور" مع الصور وملفات الفيديو والفيديوهات المباشرة. تعالج المهمة المعالجة المُسبَقة لإدخال البيانات، بما في ذلك تغيير الحجم والدوران ومعالجة قيم البيانات.
عليك تحويل الصورة أو اللقطة المُدخلة إلى عنصر
com.google.mediapipe.framework.image.MPImage
قبل تمريرها إلى
Image Classifier.
صورة
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);
يُرجى ملاحظة ما يلي:
- عند التشغيل في وضع الفيديو أو وضع البث المباشر، يجب أيضًا تقديم الطابع الزمني لإطار الإدخال إلى مهمة "تصنيف الصور".
- عند التشغيل في وضع الصورة أو الفيديو، تحظر مهمة Image Classifier سلسلة المهام الحالية إلى أن تنتهي من معالجة الصورة أو الإطار المُدخل. لتجنّب حظر واجهة المستخدم، نفِّذ المعالجة في سلسلسة مهام في الخلفية.
- عند التشغيل في وضع البث المباشر، لا تحظر مهمة Image Classifier
سلسلة المحادثات الحالية، بل تعود على الفور. سيستدعي مستمع النتائج
نتيجة الكشف في كل مرة تنتهي فيها من معالجة ملف
إطار الإدخال. إذا تمّ استدعاء الدالة
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]
}
}
}