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

تتيح لك مهمة MediaPipe Image inlineer (أداة تضمين الصور MediaPipe) تحويل بيانات الصور إلى تمثيل رقمي لإنجاز مهام معالجة الصور المتعلقة بتعلُّم الآلة، مثل مقارنة التشابه بين صورتين. توضح لك هذه التعليمات كيفية استخدام أداة تضمين الصور مع تطبيقات Android.

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

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

إنّ الرمز البرمجي لمهام MediaPipe هو تنفيذ بسيط لتطبيق أداة تضمين الصور لنظام 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/image_embedder/android
    

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

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

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

  • ImageEmbedderHelper.kt: يتم ضبط أداة تضمين الصور والتعامل مع النموذج وتفويض عملية الاختيار.
  • MainActivity.kt: تنفّذ التطبيق وتجمع مكوّنات واجهة المستخدم.

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

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

التبعيات

تستخدم أداة تضمين الصور مكتبة com.google.mediapipe:tasks-vision. أضِف هذه التبعية إلى ملف build.gradle لمشروع تطوير تطبيقات Android. قم باستيراد التبعيات المطلوبة باستخدام الرمز التالي:

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

الطراز

تتطلب مهمة MediaPipe Image embeder (أداة تضمين الصور MediaPipe) نموذجًا مدرَّبًا متوافقًا مع هذه المهمة. لمزيد من المعلومات حول النماذج المدربة المتاحة لأداة تضمين الصور، راجِع النظرة العامة على المهمة في قسم النماذج.

حدد النموذج ونزّله ثم قم بتخزينه في دليل المشروع:

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

حدِّد مسار النموذج ضمن المَعلمة ModelAssetPath. في المثال البرمجي، يتم تعريف النموذج في الدالة setupImageEmbedder() في ملف ImageEmbedderHelper.kt:

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

إنشاء المهمة

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

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

صورة

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.IMAGE)
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

حملة فيديو

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.VIDEO)
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

البث المباشر

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setResultListener((result, inputImage) -> {
         // Process the embedding result here.
    })
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

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

خيارات الضبط

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

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

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

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

البث المباشر: وضع بث مباشر لبيانات الإدخال، مثل الكاميرا. في هذا الوضع، يجب استدعاء resultsListener لإعداد أداة معالجة الصوت لكي تتلقى النتائج بشكل غير متزامن.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
l2_normalize ما إذا كان سيتم تسوية الخط المتجه للميزة الذي تم إرجاعه باستخدام معيار L2. لا تستخدم هذا الخيار إلا إذا لم يكن النموذج يحتوي على L2_NORMALIZATION TFLite Op أصلي. في معظم الحالات، يتم تسوية L2 من خلال استنتاج TFLite بدون الحاجة إلى هذا الخيار. Boolean False
quantize ما إذا كان يجب تحديد قيمة التضمين التي تم إرجاعها إلى وحدات البايت من خلال تحديد كمّية عددية ومن المفترض ضمنيًا أن تكون عمليات التضمين عبارة عن معيار وحدة، وبالتالي يمكن أن يكون لأي سمة قيمة في [ -1.0, 1.0]. واستخدِم الخيار l2_normalize إذا لم يكن الأمر كذلك. Boolean False
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();
    

في نموذج التعليمات البرمجية، تتم معالجة عملية إعداد البيانات في ملف ImageEmbedderHelper.kt.

تنفيذ المهمة

يمكنك استدعاء الدالة embed المقابلة لوضع التشغيل الخاص بك لعرض الاستنتاجات. تعرض واجهة برمجة تطبيقات تضمين الصور متجهات التضمين للصورة أو الإطار الذي يتم إدخاله.

صورة

ImageEmbedderResult embedderResult = imageEmbedder.embed(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.
ImageEmbedderResult embedderResult =
    imageEmbedder.embedForVideo(image, frameTimestampMs);
    

البث المباشر


// Run inference on the frame. The embedding results will be available
// via the `resultListener` provided in the `ImageEmbedderOptions` when
// the image embedder was created.
imageEmbedder.embedAsync(image, frameTimestampMs);
    

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

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

في نموذج الرمز البرمجي، يتم تحديد الدالة embed في ملف ImageEmbedderHelper.kt.

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

عند تنفيذ الاستنتاج، تعرض مهمة "تضمين الصور" كائن ImageEmbedderResult يحتوي على قائمة بعمليات التضمين (سواء كانت نقطة عائمة أو كمية كميّة) للصورة المُدخَلة.

ويوضح ما يلي مثالاً على بيانات المخرجات من هذه المهمة:

ImageEmbedderResult:
  Embedding #0 (sole embedding head):
    float_embedding: {0.0, 0.0, ..., 0.0, 1.0, 0.0, 0.0, 2.0}
    head_index: 0

تم الحصول على هذه النتيجة من خلال تضمين الصورة التالية:

يمكنك مقارنة التشابه بين تضمينين باستخدام الدالة ImageEmbedder.cosineSimilarity. انظر التعليمة البرمجية التالية للحصول على مثال.

// Compute cosine similarity.
double similarity = ImageEmbedder.cosineSimilarity(
  result.embeddingResult().embeddings().get(0),
  otherResult.embeddingResult().embeddings().get(0));