יצירת תמונות במכשיר ב-Android עם MediaPipe

1. מבוא

מה זה MediaPipe?

פתרונות MediaPipe מאפשרים לכם להחיל פתרונות של למידת מכונה (ML) על האפליקציות שלכם. היא מספקת מסגרת להגדרת צינורות עיבוד מוכנים מראש שמספקים למשתמשים פלט מיידי, מעניין ושימושי. אפשר אפילו להתאים אישית הרבה מהפתרונות האלה באמצעות MediaPipe Model Maker כדי לעדכן את מודלי ברירת המחדל.

יצירת תמונות לפי טקסט היא אחת ממשימות ה-ML הרבות ש-MediaPipe Solutions מציעה.

ב-Codelab הזה, תתחילו עם אפליקציית Android בסיסית, ותעברו כמה שלבים עד שתוכלו ליצור תמונות חדשות ישירות במכשיר Android.

מה תלמדו

  • איך מטמיעים יצירת תמונות לפי טקסט שפועלת באופן מקומי באפליקציית Android באמצעות MediaPipe Tasks.

הדרישות

  • גרסה מותקנת של Android Studio (ה-Codelab הזה נכתב ונבדק באמצעות Android Studio Giraffe).
  • מכשיר Android עם זיכרון RAM בנפח 8GB לפחות.
  • ידע בסיסי בפיתוח ל-Android ויכולת להריץ סקריפט Python שנכתב מראש.

2. הוספת MediaPipe Tasks לאפליקציית Android

הורדת אפליקציה לתחילת הדרך ל-Android

ב-Codelab הזה נתחיל עם דוגמה מוכנה מראש שכוללת את ממשק המשתמש שישמש לגרסה בסיסית של יצירת תמונות. אפשר למצוא את אפליקציית ההתחלה במאגר הדוגמאות הרשמי של MediaPipe כאן. משכפלים את המאגר או מורידים את קובץ ה-ZIP על ידי לחיצה על Code (קוד) > Download ZIP (הורדת קובץ ZIP).

ייבוא האפליקציה ל-Android Studio

  1. פותחים את Android Studio.
  2. במסך Welcome to Android Studio (ברוכים הבאים ל-Android Studio), לוחצים על Open (פתיחה) בפינה השמאלית העליונה.

a0b5b070b802e4ea.png

  1. עוברים למיקום שבו שיבטתם או הורדתם את המאגר ופותחים את codelabs/image_generation_basic/android/start directory.
  2. בשלב הזה לא אמורה להתבצע קומפילציה של האפליקציה כי עדיין לא הוספתם את יחסי התלות של MediaPipe Tasks.

כדי לתקן את האפליקציה ולהפעיל אותה, עוברים לקובץ build.gradle וגוללים למטה אל // Step 1 - Add dependency. משם, מוסיפים את השורה הבאה ולוחצים על הלחצן סנכרון עכשיו שמופיע בבאנר בחלק העליון של Android Studio.

// 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. זהו אובייקט המשימה שיבצע את העבודה הקשה באפליקציה ליצירת תמונות.

מתחת לאובייקט הזה תופיע פונקציה בשם 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(). הפונקציה הזו מקבלת שלושה פרמטרים: מחרוזת הנחיה שתשמש להגדרת התמונה שנוצרה, מספר האיטרציות שהמשימה צריכה לעבור במהלך יצירת התמונה החדשה, וערך 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

חשוב לדעת שהמשימה הזו מתבצעת באופן סינכרוני, ולכן צריך להפעיל את הפונקציה משרשור ברקע. בהמשך ה-codelab הזה נרחיב בנושא.

השלב האחרון שתבצעו בקובץ הזה הוא מילוי הפונקציה 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, שישמשו ליצירת תמונות עם איטרציות שהוחזרו או ללא איטרציות, בהתאמה. שתי הפעולות האלה מתרחשות באופן סינכרוני, ולכן הן מופיעות כחלק משגר משנה. אפשר להתחיל בהחלפת השורה // Step 7 - Generate without showing iterations בקטע הקוד הזה כדי לקרוא לפונקציה 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 פיזי כדי לבדוק אותה, אבל חשוב לזכור שכדאי לנסות את זה במכשיר עם זיכרון בנפח 8GB לפחות.

  1. לוחצים על Run (הפעלה) ( 7e15a9c9e1620fe7.png) בסרגל הכלים של Android Studio כדי להפעיל את האפליקציה.
  2. בוחרים את סוג שלבי היצירה (סופיים או עם איטרציות) ואז לוחצים על הלחצן הפעלה.
  3. במסך הבא, מגדירים את המאפיינים הרצויים ולוחצים על הלחצן יצירה כדי לראות את התוצאה שהכלי יצר.

e46cfaeb9d3fc235.gif

6. מעולה!

כל הכבוד! ב-Codelab הזה למדתם איך להוסיף לאפליקציית Android תכונה של יצירת תמונות לפי טקסט במכשיר.

השלבים הבאים

יש עוד פעולות שאפשר לבצע באמצעות המשימה של יצירת תמונות, כולל

  • להשתמש בתמונת בסיס כדי לבנות את התמונות שנוצרות באמצעות תוספים, או לאמן משקלים נוספים של LoRA באמצעות Vertex AI.
  • אפשר להשתמש באחסון ב-Firebase כדי לאחזר קבצים של מודלים במכשיר בלי להשתמש בכלי adb.

אנחנו מצפים לראות את כל הדברים המגניבים שתצרו באמצעות המשימה הניסיונית הזו, וממליצים לכם לעקוב אחרי עוד סדנאות ומידע מצוות MediaPipe.