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

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

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

הגדרה

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

תלויות

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

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

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

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

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

$ 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 Image Generator משתמשת בפונקציה createFromOptions() כדי להגדיר את המשימה. הפונקציה createFromOptions() מקבלת ערכים לאפשרויות ההגדרה. מידע נוסף על אפשרויות ההגדרה זמין במאמר אפשרויות הגדרה.

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

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

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

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

כשמוסיפים מודל פלאגין למודל הבסיס, צריך גם להגדיר את אפשרויות הפלאגין. הפלאגין Face landmark משתמש ב-faceConditionOptions, הפלאגין Canny edge משתמש ב-edgeConditionOptions והפלאגין Depth משתמש ב-depthConditionOptions.

אפשרויות של זיהוי קצוות

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

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

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

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

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

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

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

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

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

קלטים:

  • הנחיה: "דביבון מצויר וצבעוני עם כובע רחב שוליים רפוי, מחזיק מקל והולך ביער, אנימציה, צילום משלושה רבעים, ציור"
  • ערך הבסיס: 312687592
  • Iterations: 20

תמונה שנוצרה על ידי AI:

תמונה שנוצרה של דביבון בהתאם להנחיה