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

1. مقدمة

ما هو MediaPipe؟

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

يُعدّ إنشاء الصور من النصوص إحدى مهام الذكاء الاصطناعي (ML) المتعددة التي تقدّمها حلول MediaPipe.

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

المُعطيات

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

المتطلبات

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

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

تنزيل تطبيق Android starter

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

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

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

a0b5b070b802e4ea.png

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

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

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

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

83c31de8e8a320ee.png 78b8765e832024e3.png

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

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

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

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

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

imageGenerator = ImageGenerator.createFromOptions(context, options)

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

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

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

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

// 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 حالات واجهة المستخدم والمنطق الآخر المرتبط بهذا المثال على التطبيق. يمكنك فتحه الآن.

في أعلى الملف، من المفترض أن يظهر لك التعليق // الخطوة 6 - ضبط مسار النموذج. يمكنك هنا إخبار تطبيقك بالمكان الذي يمكنه فيه العثور على ملفات النماذج اللازمة لإنشاء الصور. في هذا المثال، ستضبط القيمة على ‎ /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 Storage لتنزيل الملفات اللازمة مباشرةً إلى جهاز المستخدم في وقت التشغيل.

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

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

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

e46cfaeb9d3fc235.gif

6- تهانينا!

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

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

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

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

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