Imagen הוא מודל ליצירת תמונות. אפשר להשתמש בו כדי ליצור אווטרים בהתאמה אישית לפרופילי משתמשים, או כדי לשלב נכסים חזותיים מותאמים אישית בתהליכים קיימים במסכים כדי להגביר את מעורבות המשתמשים.
אתם יכולים לגשת למודלים של Imagen מאפליקציית Android באמצעות Firebase AI Logic SDK. מודלים של Imagen זמינים באמצעות ספקי API של Firebase AI Logic: Gemini Developer API (מומלץ לרוב המפתחים) ו-Vertex AI.
ניסוי עם הנחיות
לפעמים צריך לנסות כמה פעמים כדי ליצור את ההנחיות האידיאליות. אתם יכולים להתנסות בהנחיות ליצירת תמונות ב-Google AI Studio, סביבת פיתוח משולבת (IDE) לעיצוב אב טיפוס של הנחיות. טיפים לשיפור ההנחיות זמינים במדריך להנחיות ולמאפייני תמונות.

הגדרת פרויקט Firebase וקישור האפליקציה
פועלים לפי השלבים במסמכי התיעוד של Firebase כדי להוסיף את Firebase לפרויקט Android.
הוספת יחסי התלות של Gradle
מוסיפים את יחסי התלות הבאים לקובץ build.gradle
:
dependencies {
// Import the BoM for the Firebase platform
implementation(platform("com.google.firebase:firebase-bom:34.4.0"))
// Add the dependency for the Firebase AI Logic library. When using the BoM,
// you don't specify versions in Firebase library dependencies
implementation("com.google.firebase:firebase-ai")
}
יצירת תמונה
כדי ליצור תמונה באפליקציית Android, מתחילים ביצירת מופע של ImagenModel
עם הגדרה אופציונלית.
אפשר להשתמש בפרמטר generationConfig
כדי להגדיר הנחיה שלילית, את מספר התמונות, את יחס הרוחב-גובה של תמונת הפלט, את פורמט התמונה ולהוסיף סימן מים. אפשר להשתמש בפרמטר safetySettings
כדי להגדיר את המסננים של בטיחות ושל אנשים.
Kotlin
val config = ImagenGenerationConfig {
numberOfImages = 2,
aspectRatio = ImagenAspectRatio.LANDSCAPE_16x9,
imageFormat = ImagenImageFormat.jpeg(compressionQuality = 100),
addWatermark = false
}
// Initialize the Gemini Developer API backend service
// For Vertex AI use Firebase.ai(backend = GenerativeBackend.vertexAI())
val model = Firebase.ai(backend = GenerativeBackend.googleAI()).imagenModel(
modelName = "imagen-4.0-generate-001",
generationConfig = config,
safetySettings = ImagenSafetySettings(
safetyFilterLevel = ImagenSafetyFilterLevel.BLOCK_LOW_AND_ABOVE,
personFilterLevel = ImagenPersonFilterLevel.BLOCK_ALL
)
)
Java
ImagenGenerationConfig config = new ImagenGenerationConfig.Builder()
.setNumberOfImages(2)
.setAspectRatio(ImagenAspectRatio.LANDSCAPE_16x9)
.setImageFormat(ImagenImageFormat.jpeg(100))
.setAddWatermark(false)
.build();
// For Vertex AI use Firebase.ai(backend = GenerativeBackend.vertexAI())
ImagenModelFutures model = ImagenModelFutures.from(
FirebaseAI.ai(backend = GenerativeBackend.googleAI()).imagenModel(
"imagen-4.0-generate-001",
config,
ImagenSafetySettings.builder()
.setSafetyFilterLevel(ImagenSafetyFilterLevel.BLOCK_LOW_AND_ABOVE)
.setPersonFilterLevel(ImagenPersonFilterLevel.BLOCK_ALL)
.build())
);
אחרי שיוצרים מופע של ImagenModel
, אפשר ליצור תמונות על ידי קריאה ל-generateImages
:
Kotlin
val imageResponse = model.generateImages(
prompt = "A hyper realistic picture of a t-rex with a blue bagpack in a prehistoric forest",
)
val image = imageResponse.images.first
val bitmapImage = image.asBitmap()
Java
CompletableFuture<GenerateContentResponse> futureResponse =
model.generateContent(
Content.newBuilder()
.addParts(
Part.newBuilder()
.setText("A hyper realistic picture of a t-rex with a blue bagpack in a prehistoric forest")
.build())
.build());
try {
GenerateContentResponse imageResponse = futureResponse.get();
List<GeneratedImage> images =
imageResponse
.getCandidates(0)
.getContent()
.getParts(0)
.getInlineData()
.getImagesList();
if (!images.isEmpty()) {
GeneratedImage image = images.get(0);
Bitmap bitmapImage = image.asBitmap();
// Use bitmapImage
}
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
עריכת תמונות באמצעות Imagen
ערכות ה-SDK של Firebase AI Logic מציעות יכולות מתקדמות לעריכת תמונות באמצעות מודל Imagen, ומאפשרות לכם:
- עריכת תמונות על סמך מסכות, כולל פעולות כמו הוספה או הסרה של אובייקטים, הרחבת תוכן התמונה מעבר לגבולות המקוריים שלה ושינוי הרקע.
- התאמה אישית של תמונות באמצעות החלת סגנונות ספציפיים (דוגמאות, טקסטורות או סגנונות של אומנים), התמקדות בנושאים שונים (כמו מוצרים, אנשים או בעלי חיים) או הקפדה על אמצעי בקרה שונים (כמו סקיצה מצוירת ביד, תמונה עם קצוות ברורים או רשת פנים).
אתחול המודל
כדי להשתמש בתכונות העריכה של Imagen, צריך לציין מודל Imagen שתומך בעריכת תמונות, כמו imgen-3.0-capability-001
. גרסת המודל:
val imagenModel = Firebase.ai(backend = GenerativeBackend.vertexAI())
.imagenModel("imagen-3.0-capability-001")
עריכה מבוססת-מסכה
העריכה מבוססת-המסכה של Imagen מאפשרת לבצע שינויים בתמונות על ידי הגדרת אזורים ספציפיים שהמודל יכול לשנות. היכולת הזו מאפשרת לבצע מגוון פעולות, כולל יצירה והחלה של מסכות, הוספה או הסרה של אובייקטים והרחבה של תוכן התמונה מעבר לגבולות המקוריים.
יצירת מסכה
כדי לבצע עריכה שמבוססת על מסכה, כמו הוספה או הסרה של אובייקטים, צריך להגדיר את האזור שרוצים לערוך באמצעות המודל, כלומר את המסכה.
כדי ליצור מסכה, אפשר להגדיר שהמודל ייצור אותה באופן אוטומטי באמצעות ImagenBackgroundMask()
או ImagenSemanticMask()
, ולהעביר מזהה של מחלקה.
אפשר גם לצייר את המסכה באופן ידני על המסך, על ידי יצירת מפת סיביות של המסכה והמרה שלה ל-ImagenRawMask
. באמצעות detectDragGestures
ו-Canvas
, אתם יכולים להטמיע ממשק משתמש לציור מסכות באפליקציה שלכם עם Jetpack Compose באופן הבא:
import androidx.compose.ui.graphics.Color as ComposeColor
[...]
@Composable
fun ImagenEditingMaskEditor(
sourceBitmap: Bitmap,
onMaskFinalized: (Bitmap) -> Unit,
) {
val paths = remember { mutableStateListOf<Path>() }
var currentPath by remember { mutableStateOf<Path?>(null) }
var scale by remember { mutableFloatStateOf(1f) }
var offsetX by remember { mutableFloatStateOf(0f) }
var offsetY by remember { mutableFloatStateOf(0f) }
Column(
modifier = Modifier.fillMaxSize(),
) {
Box(
modifier = Modifier
.fillMaxWidth()
.pointerInput(Unit) {
detectDragGestures(
onDragStart = { startOffset ->
val transformedStart = Offset(
(startOffset.x - offsetX) / scale,
(startOffset.y - offsetY) / scale,
)
currentPath = Path().apply { moveTo(transformedStart.x, transformedStart.y) }
},
onDrag = { change, _ ->
currentPath?.let {
val transformedChange = Offset(
(change.position.x - offsetX) / scale,
(change.position.y - offsetY) / scale,
)
it.lineTo(transformedChange.x, transformedChange.y)
currentPath = Path().apply { addPath(it) }
}
change.consume()
},
onDragEnd = {
currentPath?.let { paths.add(it) }
currentPath = null
},
)
},
) {
Image(
bitmap = sourceBitmap.asImageBitmap(),
contentDescription = null,
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Fit,
)
Canvas(modifier = Modifier.fillMaxSize()) {
val canvasWidth = size.width
val canvasHeight = size.height
val bitmapWidth = sourceBitmap.width.toFloat()
val bitmapHeight = sourceBitmap.height.toFloat()
scale = min(canvasWidth / bitmapWidth, canvasHeight / bitmapHeight)
offsetX = (canvasWidth - bitmapWidth * scale) / 2
offsetY = (canvasHeight - bitmapHeight * scale) / 2
withTransform(
{
translate(left = offsetX, top = offsetY)
scale(scale, scale, pivot = Offset.Zero)
},
) {
val strokeWidth = 70f / scale
val stroke = Stroke(width = strokeWidth, cap = StrokeCap.Round, join = StrokeJoin.Round)
val pathColor = ComposeColor.White.copy(alpha = 0.5f)
paths.forEach { path ->
drawPath(path = path, color = pathColor, style = stroke)
}
currentPath?.let { path ->
drawPath(path = path, color = pathColor, style = stroke)
}
}
}
}
Button(
onClick = {
val maskBitmap = createMask(sourceBitmap, paths)
onMaskFinalized(maskBitmap)
},
) {
Text("Save mask")
}
}
}
לאחר מכן אפשר ליצור את מפת הסיביות של המסכה על ידי ציור הנתיבים בלוח הציור:
import android.graphics.Color as AndroidColor
import android.graphics.Paint
[...]
private fun createMaskBitmap(
sourceBitmap: Bitmap,
paths: SnapshotStateList<Path>,
): Bitmap {
val maskBitmap = createBitmap(sourceBitmap.width, sourceBitmap.height)
val canvas = android.graphics.Canvas(maskBitmap)
val paint = Paint().apply {
color = AndroidColor.RED
strokeWidth = 70f
style = Paint.Style.STROKE
strokeCap = Paint.Cap.ROUND
strokeJoin = Paint.Join.ROUND
isAntiAlias = true
}
paths.forEach { path -> canvas.drawPath(path.asAndroidPath(), paint) }
return maskBitmap
}
מוודאים שהמסכה באותו גודל כמו תמונת המקור. מידע נוסף זמין בדוגמאות מהקטלוג של Imagen AI.
הוספת אובייקטים
אפשר להוסיף אובייקט או תוכן חדשים לתמונה קיימת. התהליך הזה נקרא גם תיקון תמונה. המודל ייצור את התוכן החדש ויכניס אותו לאזור המוסתר שצוין.
כדי לעשות את זה, משתמשים בפונקציה editImage()
. תצטרכו לספק את התמונה המקורית, מסכה והנחיית טקסט שמתארת את התוכן שרוצים להוסיף. בנוסף, מעבירים אובייקט ImagenEditingConfig
ומוודאים שהמאפיין editMode
שלו מוגדר לערך ImagenEditMode.INPAINT_INSERTION
.
suspend fun insertFlowersIntoImage(
model: ImagenModel,
originalImage: Bitmap,
mask: ImagenMaskReference): ImagenGenerationResponse<ImagenInlineImage> {
val prompt = "a vase of flowers"
// Pass the original image, a mask, the prompt, and an editing configuration.
val editedImage = model.editImage(
sources = listOf(
ImagenRawImage(originalImage),
mask),
prompt = prompt,
// Define the editing configuration for inpainting and insertion.
config = ImagenEditingConfig(ImagenEditMode.INPAINT_INSERTION)
)
return editedImage
}
הסרת אובייקטים
בעזרת מילוי חכם אפשר להסיר אובייקטים לא רצויים מתמונה. כדי לעשות את זה, משתמשים בפונקציה editImage
. תצטרכו לספק את התמונה המקורית ומסכה שמדגישה את האובייקט שרוצים להסיר. אפשר גם להוסיף הנחיית טקסט כדי לתאר את האובייקט, מה שיכול לעזור למודל לזהות אותו בצורה מדויקת. בנוסף, צריך להגדיר את editMode
בתוך ImagenEditingConfig
לערך ImagenEditMode.INPAINT_REMOVAL
.
suspend fun removeBallFromImage(model: ImagenModel, originalImage: Bitmap, mask: ImagenMaskReference): ImagenGenerationResponse<ImagenInlineImage> {
// Optional: provide the prompt describing the content to be removed.
val prompt = "a ball"
// Pass the original image, a mask, the prompt, and an editing configuration.
val editedImage = model.editImage(
sources = listOf(
ImagenRawImage(originalImage),
mask
),
prompt = prompt,
// Define the editing configuration for inpainting and removal.
config = ImagenEditingConfig(ImagenEditMode.INPAINT_REMOVAL)
)
return editedImage
}
הרחבת תוכן התמונה
אפשר להרחיב תמונה מעבר לגבולות המקוריים שלה, בתהליך שנקרא הרחבת תמונה, באמצעות הפונקציה outpaintImage()
. כדי להשתמש בפונקציה הזו צריך את התמונה המקורית ואת Dimensions
של התמונה המורחבת.
אופציונלי: אפשר לכלול הנחיה תיאורית להרחבה ולציין את ImagenImagePlacement
של התמונה המקורית בתוך התמונה החדשה שנוצרה:
suspend fun expandImage(originalImage: Bitmap, imagenModel: ImagenModel): ImagenGenerationResponse<ImagenInlineImage> {
// Optionally describe what should appear in the expanded area.
val prompt = "a sprawling sandy beach next to the ocean"
val editedImage = model.outpaintImage(
ImagenRawImage(originalImage),
Dimension(width, height),
prompt = prompt,
newPosition = ImagenImagePlacement.LEFT_CENTER
)
return editedImage
}
החלפת הרקע
אתם יכולים להחליף את הרקע של תמונה בלי לשנות את הנושא בחזית. כדי לעשות את זה, משתמשים בפונקציה editImage
. מעבירים את התמונה המקורית, אובייקט ImagenBackgroundMask
(שכולל הנחיית טקסט לרקע החדש) ואובייקט ImagenEditingConfig
עם המאפיין editMode
שלו שמוגדר לערך ImagenEditMode.INPAINT_INSERTION
.
suspend fun replaceBackground(model: ImagenModel, originalImage: Bitmap): ImagenGenerationResponse<ImagenInlineImage> {
// Provide the prompt describing the new background.
val prompt = "space background"
// Pass the original image, a mask, the prompt, and an editing configuration.
val editedImage = model.editImage(
sources = listOf(
ImagenRawImage(originalImage),
ImagenBackgroundMask(),
),
prompt = prompt,
config = ImagenEditingConfig(ImagenEditMode.INPAINT_INSERTION)
)
return editedImage
}
התאמה אישית
אתם יכולים להשתמש ביכולת ההתאמה האישית של Imagen כדי ליצור או לערוך תמונות על סמך תמונות לדוגמה שמציינות נושא, אמצעי בקרה או סגנון. כדי להשיג את התוצאה הרצויה, צריך לספק הנחיה טקסטואלית יחד עם תמונה אחת או יותר להשוואה, כדי להנחות את המודל.
התאמה אישית לפי נושא
אתם יכולים ליצור תמונות חדשות של נושא מסוים על סמך תמונה לדוגמה (למשל, מוצר, אדם או בעל חיים). פשוט מזינים הנחיית טקסט ולפחות תמונה אחת לדוגמה של הנושא. לדוגמה, אתם יכולים להעלות תמונה של חיית המחמד שלכם וליצור תמונה חדשה שלה בסביבה שונה לחלוטין.
כדי לעשות זאת, מגדירים את הפניה לנושא באמצעות ImagenSubjectReference
ואז מעבירים אותה אל editImage
יחד עם ההנחיה. בנוסף, צריך לכלול תג ImagenEditingConfig
שמציין את מספר editSteps
. בדרך כלל, ערך גבוה יותר של editSteps
מוביל לתוצאות איכותיות יותר:
suspend fun customizeCatImage(model: ImagenModel, referenceCatImage: Bitmap): ImagenGenerationResponse<ImagenInlineImage> {
// Define the subject reference using the reference image.
val subjectReference = ImagenSubjectReference(
image = referenceCatImage,
referenceID = 1,
description = "cat",
subjectType = ImagenSubjectReferenceType.ANIMAL
)
// Provide a prompt that describes the final image.
// The "[1]" links the prompt to the subject reference with ID 1.
val prompt = "A cat[1] flying through outer space"
// Use the editImage API to perform the subject customization.
val editedImage = model.editImage(
references = listOf(subjectReference),
prompt = prompt,
config = ImagenEditingConfig(
editSteps = 50 // Number of editing steps, a higher value can improve quality
)
)
return editedImage
}
התאמה אישית על סמך אמצעי בקרה
הטכניקה הזו יוצרת תמונה חדשה על סמך תמונת הפניה לבקרה, כמו סקיצה מצוירת ביד ("שרבוט"), תמונה עם קצוות של Canny או רשת פנים. המודל משתמש בתמונת הבקרה כמדריך מבני לפריסה ולסידור של התמונה החדשה, בעוד שההנחיה הטקסטואלית מספקת פרטים כמו צבע ומרקם.
מגדירים הפניה לבקרה באמצעות ImagenControlReference
ומספקים אותה ל-editImage
יחד עם הנחיה ו-ImagenEditingConfig
עם מספר editSteps
(ערך גבוה יותר יכול לשפר את האיכות):
suspend fun customizeCatImageByControl(model: ImagenModel, referenceCatImage: Bitmap): ImagenGenerationResponse<ImagenInlineImage> {
// Define the subject reference using the reference image.
val controlReference = ImagenControlReference(
image = referenceImage,
referenceID = 1,
controlType = CONTROL_TYPE_SCRIBBLE
)
val prompt = "A cat flying through outer space arranged like the scribble map[1]"
val editedImage = model.editImage(
references = listOf(controlReference),
prompt = prompt,
config = ImagenEditingConfig(
editSteps = 50
)
)
return editedImage
}
התאמה אישית על סמך סגנון
אתם יכולים ליצור או לערוך תמונה כך שתתאים לסגנון ספציפי מתוך תמונה לדוגמה, כמו הדפוס, הטקסטורה או העיצוב שלה. המודל משתמש בתמונת ההפניה כדי להבין את האסתטיקה הנדרשת ומחיל אותה על התמונה החדשה שמתוארת בהנחיית הטקסט. לדוגמה, אפשר ליצור תמונה של חתול בסגנון של ציור מפורסם על ידי העלאה של תמונה של הציור הזה.
מגדירים הפניה לסגנון באמצעות ImagenStyleReference
ומספקים אותה ל-editImage
יחד עם הנחיה ו-ImagenEditingConfig
עם מספר editSteps
(ערך גבוה יותר יכול לשפר את האיכות):
suspend fun customizeImageByStyle(model: ImagenModel, referenceVanGoghImage: Bitmap): ImagenGenerationResponse<ImagenInlineImage> {
// Define the style reference using the reference image.
val styleReference = ImagenStyleReference(
image = referenceVanGoghImage,
referenceID = 1,
description = "Van Gogh style"
)
// Provide a prompt that describes the final image.
// The "1" links the prompt to the style reference with ID 1.
val prompt = "A cat flying through outer space, in the Van Gogh style[1]"
// Use the editImage API to perform the style customization.
val editedImage = model.editImage(
references = listOf(styleReference),
prompt = prompt,
config = ImagenEditingConfig(
editSteps = 50 // Number of editing steps, a higher value can improve quality
)
)
return editedImage
}
השלבים הבאים
- מידע נוסף על Firebase AI Logic זמין במסמכי Firebase.
- כדאי לעיין בקטלוג הדוגמאות של AI ב-Android.