إنشاء الصور على الجهاز على Android باستخدام MediaPipe

1. مقدمة

ما هي MediaPipe؟

تتيح لك حلول MediaPipe تطبيق حلول تعلُّم الآلة (ML) على تطبيقاتك. يوفر هذا المنتج إطار عمل لإعداد مسارات معالجة مسبقة الإنشاء تقدّم للمستخدمين نتائج فورية وجذابة ومفيدة. يمكنك حتى تخصيص العديد من هذه الحلول باستخدام MediaPipe Model Maker لتعديل النماذج التلقائية.

يُعدّ تحويل النص إلى صورة إحدى مهام تعلُّم الآلة المتعدّدة التي تقدّمها "حلول MediaPipe".

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

أهداف الدورة التعليمية

  • كيفية تنفيذ عملية تحويل النص إلى صورة التي تعمل محليًا في تطبيق Android باستخدام MediaPipe Tasks.

المتطلبات

  • إصدار مثبَّت من استوديو Android (تمت كتابة هذا الدرس التطبيقي واختباره باستخدام الإصدار Giraffe من "استوديو Android").
  • جهاز Android مزوّد بذاكرة وصول عشوائي (RAM) بسعة 8 غيغابايت على الأقل
  • معرفة أساسية بتطوير تطبيقات Android والقدرة على تشغيل نص Python برمجي مكتوب مسبقًا

2. إضافة MediaPipe Tasks إلى تطبيق Android

تنزيل تطبيق Android الأوّلي

سيبدأ هذا الدرس التطبيقي حول الترميز بنموذج مُعدّ مسبقًا يتألف من واجهة المستخدم التي سيتم استخدامها في إصدار أساسي من إنشاء الصور. يمكنك العثور على تطبيق البدء هذا في مستودع نماذج MediaPipe الرسمي هنا. استنسِخ المستودع أو نزِّل ملف ZIP بالنقر على "الرمز" > "تنزيل ملف ZIP".

استيراد التطبيق إلى "استوديو Android"

  1. افتح "استوديو Android".
  2. من شاشة مرحبًا بك في استوديو Android، انقر على فتح (Open) في أعلى يسار الشاشة.

a0b5b070b802e4ea.png

  1. انتقِل إلى المكان الذي نسخت فيه المستودع أو نزّلته، ثم افتح دليل codelabs/image_generation_basic/android/start.
  2. في هذه المرحلة، يجب ألا يتم تجميع التطبيق لأنّك لم تتضمّن بعد تبعية MediaPipe Tasks.

يمكنك إصلاح التطبيق وتشغيله من خلال الانتقال إلى ملف build.gradle والتمرير للأسفل إلى // Step 1 - Add dependency. من هناك، أدرِج السطر التالي ثم انقر على الزر المزامنة الآن الذي يظهر في البانر أعلى "استوديو Android".

// Step 1 - Add dependency
implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'

بعد اكتمال المزامنة، تأكَّد من أنّ كل شيء تم فتحه وتثبيته بشكل صحيح من خلال النقر على سهم التشغيل الأخضر ( 7e15a9c9e1620fe7.png) في أعلى يسار "استوديو Android". من المفترض أن يفتح التطبيق على شاشة تتضمّن زرَّي اختيار وزرًا يحمل التصنيف INITIALIZE. إذا نقرت على هذا الزر، سيتم نقلك على الفور إلى واجهة مستخدم منفصلة تتضمّن طلبًا نصيًا وخيارات أخرى إلى جانب زر يحمل التصنيف إنشاء.

83c31de8e8a320ee.png 78b8765e832024e3.png

هذا كل ما يتضمّنه التطبيق المبدئي، لذا حان الوقت لتعلُّم كيفية إكمال هذا التطبيق والبدء في إنشاء صور جديدة على جهازك.

3- إعداد "أداة إنشاء الصور"

في هذا المثال، سيتم تنفيذ معظم عملية إنشاء الصور في الملف ImageGenerationHelper.kt. عند فتح هذا الملف، ستلاحظ متغيّرًا في أعلى الفئة يُسمى imageGenerator. هذا هو عنصر Task الذي سيقوم بالعمل الشاق في تطبيق إنشاء الصور.

ستظهر لك أسفل هذا العنصر مباشرةً دالة باسم initializeImageGenerator() مع التعليق التالي: // Step 2 - initialize the image generator. كما قد تتوقّع، هذا هو المكان الذي ستتم فيه تهيئة عنصر ImageGenerator. استبدِل نص الدالة بالرمز التالي لضبط مسار نموذج إنشاء الصور وتهيئة عنصر ImageGenerator:

// Step 2 - initialize the image generator
val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

imageGenerator = ImageGenerator.createFromOptions(context, options)

سيظهر أدناه دالة أخرى باسم setInput(). تقبل هذه الدالة ثلاث مَعلمات: سلسلة طلب سيتم استخدامها لتحديد الصورة التي تم إنشاؤها، وعدد التكرارات التي يجب أن يمر بها Task أثناء إنشاء الصورة الجديدة، وقيمة seed التي يمكن استخدامها لإنشاء إصدارات جديدة من صورة استنادًا إلى الطلب نفسه أثناء إنشاء الصورة نفسها عند استخدام seed نفسه. الغرض من هذه الدالة هو ضبط هذه المَعلمات الأولية لـ "أداة إنشاء الصور" عند محاولة إنشاء صورة تعرض خطوات وسيطة.

استبدِل نص الدالة setInput() (حيث سيظهر التعليق // Step 3 - accept inputs) بهذا السطر:

// Step 3 - accept inputs
imageGenerator.setInputs(prompt, iteration, seed)

في الخطوتَين التاليتَين، يتم إنشاء المحتوى. تقبل الدالة generate() المدخلات نفسها التي تقبلها الدالة setInput، ولكنها تنشئ صورة كطلب لمرة واحدة لا يعرض أي صور للخطوات الوسيطة. يمكنك استبدال نص هذه الدالة (الذي يتضمّن التعليق // Step 4 - generate without showing iterations) بما يلي:

// Step 4 - generate without showing iterations
val result = imageGenerator.generate(prompt, iteration, seed)
val bitmap = BitmapExtractor.extract(result?.generatedImage())
return bitmap

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

الخطوة الأخيرة التي ستتّخذها في هذا الملف هي ملء الدالة execute() (المصنّفة على أنّها الخطوة 5). سيقبل هذا الرمز مَعلمة تحدّد ما إذا كان يجب عرض صورة وسيطة أم لا لخطوة واحدة من عملية الإنشاء التي سيتم تنفيذها باستخدام الدالة execute() في ImageGenerator. استبدِل نص الدالة بالرمز التالي:

// Step 5 - generate with iterations
val result = imageGenerator.execute(showResult)

if (result == null || result.generatedImage() == null) {
    return Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888)
        .apply {
            val canvas = Canvas(this)
            val paint = Paint()
            paint.color = Color.WHITE
            canvas.drawPaint(paint)
        }
}

val bitmap =
    BitmapExtractor.extract(result.generatedImage())

return bitmap

هذا كل ما يتعلق بملف المساعد. في القسم التالي، ستملأ ملف ViewModel الذي يتعامل مع منطق هذا المثال.

4. دمج التطبيق

سيتولّى ملف MainViewModel معالجة حالات واجهة المستخدم والمنطق الآخر المرتبط بهذا التطبيق النموذجي. يمكنك فتحه الآن.

في أعلى الملف، يجب أن يظهر التعليق // Step 6 - set model path. هنا ستخبر تطبيقك بمكان العثور على ملفات النموذج الضرورية لإنشاء الصور. في هذا المثال، ستضبط القيمة على /data/local/tmp/image_generator/bins/.

// Step 6 - set model path
private val MODEL_PATH = "/data/local/tmp/image_generator/bins/"

بعد ذلك، انتقِل إلى أسفل الصفحة إلى الدالة generateImage(). في أسفل هذه الدالة، ستظهر الخطوتان 7 و8، وسيتم استخدامهما لإنشاء صور تتضمّن تكرارات تم إرجاعها أو لا تتضمّن أي تكرارات، على التوالي. بما أنّ هاتين العمليتين تحدثان بشكل متزامن، ستلاحظ أنّهما مضمّنتان في روتين فرعي. يمكنك البدء باستبدال // الخطوة 7 - إنشاء بدون عرض التكرارات بكتلة الرمز هذه لاستدعاء generate() من ملف ImageGenerationHelper، ثم تعديل حالة واجهة المستخدم.

// Step 7 - Generate without showing iterations
val result = helper?.generate(prompt, iteration, seed)
_uiState.update {
    it.copy(outputBitmap = result)
}

تصبح الخطوة 8 أكثر صعوبة. بما أنّ الدالة execute() تنفّذ خطوة واحدة فقط بدلاً من جميع خطوات إنشاء الصور، عليك استدعاء كل خطوة على حدة من خلال حلقة. عليك أيضًا تحديد ما إذا كان يجب عرض الخطوة الحالية للمستخدم. أخيرًا، ستعدّل حالة واجهة المستخدم إذا كان من المفترض عرض التكرار الحالي. يمكنك إجراء كل ذلك الآن.

// Step 8 - Generate with showing iterations
helper?.setInput(prompt, iteration, seed)
for (step in 0 until iteration) {
    isDisplayStep =
        (displayIteration > 0 && ((step + 1) % displayIteration == 0))
    val result = helper?.execute(isDisplayStep)

    if (isDisplayStep) {
        _uiState.update {
            it.copy(
                outputBitmap = result,
                generatingMessage = "Generating... (${step + 1}/$iteration)",
            )
        }
    }
}

في هذه المرحلة، يجب أن تتمكّن من تثبيت تطبيقك وتهيئة أداة إنشاء الصور، ثم إنشاء صورة جديدة استنادًا إلى طلب نصي.

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

بالإضافة إلى نسخ الملفات مباشرةً إلى جهاز التطوير، يمكنك أيضًا إعداد مساحة تخزين Firebase لتنزيل الملفات اللازمة مباشرةً إلى جهاز المستخدم في وقت التشغيل.

5- نشر التطبيق واختباره

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

  1. انقر على "تشغيل" ( 7e15a9c9e1620fe7.png) في شريط أدوات "استوديو Android" لتشغيل التطبيق.
  2. اختَر نوع خطوات الإنشاء (نهائية أو مع تكرارات)، ثم اضغط على الزر بدء.
  3. في الشاشة التالية، اضبط أي خصائص تريدها وانقر على الزر إنشاء للاطّلاع على النتائج التي تقدّمها الأداة.

e46cfaeb9d3fc235.gif

6. تهانينا!

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

الخطوات التالية

يمكنك الاستفادة من ميزة "إنشاء الصور" في المزيد من المهام، بما في ذلك:

  • استخدام صورة أساسية لتنظيم الصور التي يتم إنشاؤها من خلال الإضافات، أو تدريب أوزان LoRA الإضافية الخاصة بك من خلال Vertex AI
  • استخدِم مساحة تخزين Firebase لاسترداد ملفات النماذج على جهازك بدون الحاجة إلى استخدام أداة ADB.

نتطلّع إلى رؤية كلّ المشاريع الرائعة التي ستنشئها باستخدام هذه المهمة التجريبية، وننصحك بمتابعة المزيد من دروس البرمجة والمحتوى من فريق MediaPipe.