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

1. מבוא

מה זה MediaPipe?

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

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

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

מה תלמדו

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

למה תזדקק?

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

2. הוספת משימות של MediaPipe לאפליקציה ל-Android

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

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

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

  1. פותחים את Android Studio.
  2. במסך ברוכים הבאים אל Android Studio, בוחרים באפשרות פתיחה בפינה השמאלית העליונה.

a0b5b070b802e4ea.png

  1. עוברים למקום שבו שכפול או הורדת את המאגר, ופותחים את ספריית Codelabs/image_generative_basic/android/start.
  2. בשלב הזה, האפליקציה לא אמורה לבצע הידור (compile) כי עדיין לא כללתם את התלות של MediaPipe Tasks.

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

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

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

83c31de8e8a320ee.png 78b8765e832024e3.png

לצערנו, מדובר בהיקף של אפליקציית ההתחלה, ולכן הגיע הזמן ללמוד איך לסיים את השימוש באפליקציה ולהתחיל ליצור תמונות חדשות במכשיר!

3. הגדרת מחולל התמונות

בדוגמה הזו, רוב העבודה ליצירת התמונות תתבצע בקובץ ImageGenerationHelper.kt. כשתפתחו את הקובץ, יופיע משתנה בחלק העליון של המחלקה שנקרא imageGenerator. זהו אובייקט המשימה שיעשה את העבודה הקשה באפליקציה שלכם ליצירת תמונות.

ממש מתחת לאובייקט מופיעה פונקציה בשםInitializeImageGenerator() עם ההערה הבאה: // שלב 2 - אתחול מחולל התמונות. כאן אפשר לאתחל את האובייקט ImageGenerator, כפי שאתם יכולים לנחש. כדי להגדיר את נתיב המודל ליצירת תמונה ולאתחל את האובייקט ImageGenerator, צריך להחליף את גוף הפונקציה בקוד הבא:

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

imageGenerator = ImageGenerator.createFromOptions(context, options)

מתחתיה מופיעה פונקציה אחרת בשם setInput(). היא מקבלת שלושה פרמטרים: מחרוזת הנחיה שתשמש להגדרת התמונה שתיווצר, מספר האיטרציות שהמשימה צריכה לעבור במהלך יצירת התמונה החדשה, וערך seed שאפשר להשתמש בו כדי ליצור גרסאות חדשות של תמונה על סמך אותה הנחיה, תוך יצירת אותה תמונה כשמשתמשים באותו מקור. מטרת הפונקציה הזו היא להגדיר את הפרמטרים הראשוניים האלה למחולל התמונות כשמנסים ליצור תמונה שכוללת את שלבי הביניים.

עכשיו צריך להחליף את הגוף setInput() (במקום שבו תוכלו לראות את התגובה // שלב 3 - מקבלים קלט) בשורה הזו:

// 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

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

השלב האחרון שתצטרכו לבצע בקובץ הזה הוא למלא את הפונקציה generate() (מסווגת כשלב 5). הפעולה הזו תקבל פרמטר שיודיע לו אם עליו להחזיר תמונת ביניים או לא עבור השלב היחיד בתהליך היצירה שיבוצע באמצעות פונקציית ImageGenerator Activate() . מחליפים את גוף הפונקציה בקוד הבא:

// 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

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

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

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

e46cfaeb9d3fc235.gif

6. מעולה!

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

השלבים הבאים

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

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

אנחנו מצפים לראות את כל הדברים המגניבים שתצרו במשימה הניסיונית הזו. שימו לב ל-codelabs ולתוכן נוספים מצוות MediaPipe!