מדריך ליצירת תמונות ל-Android

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

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

דוגמת הקוד שמתוארת בהוראות האלה זמינה ב-GitHub. מידע נוסף על היכולות, המודלים והאפשרויות להגדרה של המשימה הזו זמין בסקירה הכללית.

קוד לדוגמה

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

מורידים את הקוד

בהוראות הבאות מוסבר איך ליצור עותק מקומי של קוד הדוגמה באמצעות כלי שורת הפקודה git.

כדי להוריד את הקוד לדוגמה:

  1. משכפלים את מאגר git באמצעות הפקודה הבאה:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. אפשר גם להגדיר את מכונה של git כך שתשתמש ב-sparse checkout, כך שיישארו רק הקבצים של אפליקציית הדוגמה Image Generator:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_generation/android
    

אחרי שיוצרים גרסה מקומית של קוד הדוגמה, אפשר לייבא את הפרויקט ל-Android Studio ולהריץ את האפליקציה. להוראות, אפשר לעיין במדריך ההגדרה ל-Android.

רכיבים מרכזיים

הקבצים הבאים מכילים את הקוד החשוב לאפליקציה לדוגמה ליצירת תמונות:

  • ImageGenerationHelper.kt: הפונקציה הזו מפעילה את המשימה ומטפלת ביצירת התמונות.
  • DiffusionActivity.kt: יוצר תמונות כשפלאגינים או משקלים של LoRA לא מופעלים.
  • PluginActivity.kt: הטמעת המודלים של הפלאגין, שמאפשרת למשתמשים לספק קובץ אימג' של תנאי כקלט.
  • LoRAWeightActivity.kt: פונקציה שמאפשרת לגשת למשקולות LoRA ולנהל אותם. המשקולות האלה משמשים להתאמה אישית של מודלים בסיסיים ומאפשרים להם ליצור תמונות של מושגים ספציפיים.

הגדרה

בקטע הזה מתוארים השלבים העיקריים להגדרת סביבת הפיתוח ופרויקטי הקוד, באופן ספציפי לשימוש ב-Image Generator. למידע כללי על הגדרת סביבת הפיתוח לשימוש במשימות של MediaPipe, כולל דרישות לגבי גרסת הפלטפורמה, אפשר לעיין במדריך ההגדרה ל-Android.

יחסי תלות

המשימה 'יצירת תמונות' משתמשת בספרייה com.google.mediapipe:tasks-vision-image-generator. מוסיפים את יחסי התלות האלה לקובץ build.gradle של אפליקציית Android:

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

במכשירים עם Android 12 (API 31) ואילך, מוסיפים את התלות בספרייה המקורית של OpenCL. מידע נוסף זמין במסמכי העזרה בנושא התג uses-native-library.

מוסיפים את תגי uses-native-library הבאים לקובץ AndroidManifest.xml:

<uses-native-library android:name="libOpenCL.so" android:required="false" />
<uses-native-library android:name="libOpenCL-car.so" android:required="false"/>
<uses-native-library android:name="libOpenCL-pixel.so" android:required="false" />

דגם

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

מידע נוסף על המודלים המאומנים הזמינים ל-Image Generator זמין בקטע 'מודלים' בסקירה הכללית של המשימה.

הורדת מודל הבסיס

התנאי של הכלי ליצירת תמונות הוא שמודל הבסיס תואם לפורמט המודל runwayml/stable-diffusion-v1-5 EMA-only, על סמך המודל הבא: runwayml/stable-diffusion-v1-5.

התקנה של יחסי תלות והמרה של המודל

$ pip install torch typing_extensions numpy Pillow requests pytorch_lightning absl-py

מריצים את הסקריפט convert.py:

$ python3 convert.py --ckpt_path <ckpt_path> --output_path <output_path>

דחיפת המודל המומר למכשיר

מעבירים את התוכן של התיקייה <output_path> למכשיר Android.

$ adb shell rm -r /data/local/tmp/image_generator/ # Remove any previously loaded weights
$ adb shell mkdir -p /data/local/tmp/image_generator/
$ adb push <output_path>/. /data/local/tmp/image_generator/bins

מורידים מודלים של פלאגין ומוסיפים משקלים של LoRA (אופציונלי)

אם אתם מתכוונים להשתמש במודל של פלאגין, עליכם לבדוק אם צריך להוריד את המודל. בפלאגינים שדורשים מודל נוסף, מודל הפלאגין צריך להיות בחבילה של קובץ ה-APK או להורדה על פי דרישה. מודלים של יישומי פלאגין הם קלים (כ-23MB) וניתן לקבץ אותם ישירות ב-APK. עם זאת, מומלץ להוריד מודלים של פלאגינים על פי דרישה.

אם התאמתם מודל באמצעות LoRa, תוכלו להוריד אותו על פי דרישה. למידע נוסף, ראו מודל הפלאגין של משקלים של LoRA.

יצירת המשימה

המשימה 'יצירת תמונות ב-MediaPipe' משתמשת בפונקציה createFromOptions() כדי להגדיר את המשימה. הפונקציה createFromOptions() מקבלת ערכים לאפשרויות ההגדרה. מידע נוסף על אפשרויות ההגדרה זמין במאמר אפשרויות הגדרה.

אפשרויות הגדרה

למשימה הזו יש את אפשרויות התצורה הבאות לאפליקציות ל-Android:

שם האפשרות תיאור טווח ערכים
imageGeneratorModelDirectory הספרייה של מודל ה-generator של התמונות שבה מאוחסנים משקלי המודל. PATH
loraWeightsFilePath הגדרת הנתיב לקובץ המשקלים של LoRA. אופציונלי ורלוונטי רק אם הדגם מותאם אישית באמצעות LoRA. PATH
errorListener הגדרת מאזין אופציונלי לשגיאות. N/A

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

כשמוסיפים מודל פלאגין למודל הבסיס, צריך גם להגדיר את אפשרויות הפלאגין. הפלאגין של ציון מקום בפנים משתמש ב-faceConditionOptions, הפלאגין של קצה Canny משתמש ב-edgeConditionOptions והפלאגין של עומק משתמש ב-depthConditionOptions.

אפשרויות של קווי Canny

מגדירים את האפשרויות הבאות ב-edgeConditionOptions.

שם האפשרות תיאור טווח ערכים ערך ברירת מחדל
threshold1 הסף הראשון של תהליך ההיסטריה. Float 100
threshold2 הסף השני של תהליך ההייסטרזיס. Float 200
apertureSize גודל הצמצם של אופרטור Sobel. הטווח האופייני הוא בין 3 ל-7. Integer 3
l2Gradient האם נעשה שימוש בתקן L2 כדי לחשב את עוצמת שיפוע התמונה, במקום התקן L1 שמוגדר כברירת מחדל. BOOLEAN False
EdgePluginModelBaseOptions האובייקט BaseOptions שמגדיר את הנתיב של מודל הפלאגין. אובייקט BaseOptions N/A

מידע נוסף על אופן הפעולה של אפשרויות ההגדרה האלה זמין במאמר חיפוש קצוות של Canny.

אפשרויות של נקודות ציון בפנים

מגדירים את האפשרויות הבאות ב-faceConditionOptions.

שם האפשרות תיאור טווח ערכים ערך ברירת מחדל
minFaceDetectionConfidence דירוג האמון המינימלי שדרוש כדי שזיהוי הפנים יחשב כהצלחה. Float [0.0,1.0] 0.5
minFacePresenceConfidence דירוג הוודאות המינימלי של דירוג נוכחות הפנים בזיהוי נקודות ציון בפנים. Float [0.0,1.0] 0.5
faceModelBaseOptions האובייקט BaseOptions שמגדיר את הנתיב של המודל שיוצר את קובץ האימג' של התנאי. אובייקט BaseOptions N/A
FacePluginModelBaseOptions האובייקט BaseOptions שמגדיר את הנתיב של מודל הפלאגין. אובייקט BaseOptions N/A

מידע נוסף על אופן הפעולה של אפשרויות ההגדרה האלה זמין במאמר משימה של זיהוי נקודות ציון בפנים.

אפשרויות עומק

מגדירים את האפשרויות הבאות ב-depthConditionOptions.

שם האפשרות תיאור טווח ערכים ערך ברירת מחדל
depthModelBaseOptions האובייקט BaseOptions שמגדיר את הנתיב של המודל שיוצר את קובץ האימג' של התנאי. אובייקט BaseOptions N/A
depthPluginModelBaseOptions האובייקט BaseOptions שמגדיר את הנתיב של מודל הפלאגין. אובייקט BaseOptions N/A

יצירה באמצעות מודל הבסיס בלבד

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

imageGenerator = ImageGenerator.createFromOptions(context, options)

יצירת מודעות באמצעות יישומי פלאגין

אם מחילים מודל פלאגין אופציונלי, מגדירים את האפשרויות הבסיסיות של מודל הפלאגין באמצעות setPluginModelBaseOptions. אם מודל הפלאגין מחייב מודל נוסף שהורדתם כדי ליצור את תמונת התנאי, צריך לציין את הנתיב ב-BaseOptions.

ציון דרך בפנים

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

val faceModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("face_landmarker.task")
    .build()

val facePluginModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("face_landmark_plugin.tflite")
    .build()

val faceConditionOptions = FaceConditionOptions.builder()
    .setFaceModelBaseOptions(faceModelBaseOptions)
    .setPluginModelBaseOptions(facePluginModelBaseOptions)
    .setMinFaceDetectionConfidence(0.3f)
    .setMinFacePresenceConfidence(0.3f)
    .build()

val conditionOptions = ConditionOptions.builder()
    .setFaceConditionOptions(faceConditionOptions)
    .build()

imageGenerator =
    ImageGenerator.createFromOptions(context, options, conditionOptions)
    

Canny Edge

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

val edgePluginModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("canny_edge_plugin.tflite")
    .build()

val edgeConditionOptions = EdgeConditionOptions.builder()
    .setThreshold1(100.0f)
    .setThreshold2(100.0f)
    .setApertureSize(3)
    .setL2Gradient(false)
    .setPluginModelBaseOptions(edgePluginModelBaseOptions)
    .build()

val conditionOptions = ConditionOptions.builder()
    .setEdgeConditionOptions(edgeConditionOptions)
    .build()

imageGenerator =
    ImageGenerator.createFromOptions(context, options, conditionOptions)
    

עומק

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

val depthModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("depth_model.tflite")
    .build()

val depthPluginModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("depth_plugin.tflite")
    .build()

val depthConditionOptions =
    ConditionOptions.DepthConditionOptions.builder()
        .setDepthModelBaseOptions(depthModelBaseOptions)
        .setPluginModelBaseOptions(depthPluginModelBaseOptions)
        .build()

val conditionOptions = ConditionOptions.builder()
    .setDepthConditionOptions(depthConditionOptions)
    .build()

imageGenerator =
    ImageGenerator.createFromOptions(context, options, conditionOptions)
    

יצירה באמצעות משקלים של LoRA

אם אתם כוללים משקלים של LoRA, צריך להשתמש בפרמטר loraWeightsFilePath כדי להפנות למיקום הנתיב.

val options = ImageGeneratorOptions.builder()
    .setLoraWeightsFilePath(weightsPath)
    .setImageGeneratorModelDirectory(modelPath)
    .build()

imageGenerator = ImageGenerator.createFromOptions(context, options)

הכנת הנתונים

הכלי ליצירת תמונות מקבל את הקלטות הבאות:

  • prompt (חובה): הנחיית הטקסט שמתארת את התמונה שרוצים ליצור.
  • iterations (חובה): מספר החזרות הכולל ליצירת התמונה. נקודת התחלה טובה היא 20.
  • seed (חובה): המקור האקראי שמשמש ליצירת התמונה.
  • condition image (אופציונלי): התמונה שבה המערכת משתמשת כתמונה לדוגמה ליצירה. רלוונטי רק כשמשתמשים במודל פלאגין.
  • condition type (אופציונלי): סוג מודל הפלאגין שמשמש במשימה. רלוונטי רק כשמשתמשים במודל פלאגין.

נתוני קלט עם מודל הבסיס בלבד

fun setInput(prompt: String, iteration: Int, seed: Int) {
    imageGenerator.setInputs(prompt, iteration, seed)
}

קלט עם פלאגינים

אם מחילים מודל פלאגין אופציונלי, צריך להשתמש גם בפרמטר conditionType כדי לבחור את מודל הפלאגין, ובפרמטר sourceConditionImage כדי ליצור את קובץ האימג' של התנאי.

שם האפשרות תיאור ערך
conditionType מודל הפלאגין שהוחל על מודל הבסיס. {"FACE", "EDGE", "DEPTH"}
sourceConditionImage תמונת המקור ששימשה ליצירת תמונת התנאי. אובייקט MPImage

אם אתם משתמשים במודל של פלאגין, צריך להשתמש ב-createConditionImage כדי ליצור את קובץ האימג' של התנאי:

fun createConditionImage(
    inputImage: MPImage,
    conditionType: ConditionType
): Bitmap {
    val result =
        imageGenerator.createConditionImage(inputImage, conditionType)
    return BitmapExtractor.extract(result)
}

אחרי שיוצרים את קובץ האימג' של התנאי, צריך לכלול אותו כקלט יחד עם ההנחיה, זרעי ה-seed ומספר החזרות.

imageGenerator.setInputs(
    prompt,
    conditionalImage,
    conditionType,
    iteration,
    seed
)

קלט עם משקלים של LoRA

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

fun setInput(prompt: String, iteration: Int, seed: Int) {
    imageGenerator.setInputs(prompt, iteration, seed)
}

הרצת המשימה

משתמשים בשיטה generate() כדי ליצור תמונה באמצעות הקלט שצוין בקטע הקודם. כך נוצרת תמונה אחת.

יצירת מודלים רק עם מודל הבסיס

fun generate(prompt: String, iteration: Int, seed: Int): Bitmap {
    val result = imageGenerator.generate(prompt, iteration, seed)
    val bitmap = BitmapExtractor.extract(result?.generatedImage())
    return bitmap
}

יצירה באמצעות יישומי פלאגין

fun generate(
    prompt: String,
    inputImage: MPImage,
    conditionType: ConditionType,
    iteration: Int,
    seed: Int
): Bitmap {
    val result = imageGenerator.generate(
        prompt,
        inputImage,
        conditionType,
        iteration,
        seed
    )
    val bitmap = BitmapExtractor.extract(result?.generatedImage())
    return bitmap
}

יצירה באמצעות משקלים של LoRA

התהליך של יצירת תמונות עם מודל מותאם אישית עם משקלים של LoRA דומה לתהליך עם מודל בסיס רגיל. מוודאים שהאסימון נכלל בהנחיה ומריצים את אותו קוד.

fun generate(prompt: String, iteration: Int, seed: Int): Bitmap {
    val result = imageGenerator.generate(prompt, iteration, seed)
    val bitmap = BitmapExtractor.extract(result?.generatedImage())
    return bitmap
}

יצירת מודלים חוזרת

הכלי ליצירת תמונות יכול גם להפיק את התמונות הביניים שנוצרו במהלך כל מחזור, כפי שמוגדר בפרמטר הקלט iterations. כדי להציג את התוצאות הממוצעות האלה, צריך להפעיל את השיטה setInputs ואז להפעיל את execute() כדי להריץ כל שלב. כדי להציג את התוצאות הביניים, מגדירים את הפרמטר showResult לערך true.

fun execute(showResult: Boolean): Bitmap {
    val result = imageGenerator.execute(showResult)

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

    return bitmap
}

טיפול בתוצאות והצגתן

ה-Image Generator מחזיר ImageGeneratorResult, שכולל את התמונה שנוצרה, חותמת זמן של מועד השלמה ואת התמונה המותנית, אם היא סופקה כקלט.

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

התמונה הבאה נוצרה מהנתונים הבאים, באמצעות מודל בסיס בלבד.

קלט:

  • הנחיה: "דביבון צבעוני בקריקטורה עם כובע רחב שוליים רופף, נושא מקל וצועד ביער. אנימציה, תצוגה ברבע, ציור"
  • Seed: 312687592
  • חזרות: 20

התמונה שנוצרה: