Imagen ile resim oluşturma

Imagen, görüntü üretme modelidir. Kullanıcı profilleri için özel avatarlar oluşturmak veya kullanıcı etkileşimini artırmak amacıyla kişiselleştirilmiş görsel öğeleri mevcut ekran akışlarına entegre etmek için kullanılabilir.

Firebase AI Logic SDK'sını kullanarak Android uygulamanızdan Imagen modellerine erişebilirsiniz. Imagen modelleri, hem Firebase AI Logic API sağlayıcıları (Gemini Developer API (çoğu geliştirici için önerilir) ve Vertex AI) kullanılarak kullanılabilir.

Gemini Developer API'ye erişmek için Firebase AI Logic entegrasyon mimarisini gösteren bir diyagram. Android uygulaması, Firebase'e bağlanmak için Firebase Android SDK'sını kullanır. Ardından Firebase, buluttaki Gemini Pro ve Flash'e erişen Gemini Developer API ile etkileşim kurar.
1. şekil. Firebase AI Logic'i kullanarak Imagen modellerine erişin.

İstemlerle denemeler yapma

İdeal istemleri oluşturmak genellikle birden fazla deneme gerektirir. İstem tasarımı ve prototip oluşturmaya yönelik bir entegre geliştirme ortamı olan Google AI Studio'da görüntü istemleriyle denemeler yapabilirsiniz. İstemlerinizi iyileştirme hakkında ipuçları için istem ve resim özelliği kılavuzunu inceleyin.

Google Yapay Zeka Stüdyosu arayüzünün ekran görüntüsünde, tarih öncesi bir ormanda mavi sırt çantalı bir T-Rex'in dört farklı yapay görüntüleri gösteriliyor.
Şekil 2. Google AI Studio, görüntü oluşturma istemlerinizi iyileştirmenize yardımcı olabilir.

Firebase projesi oluşturma ve uygulamanızı bağlama

Firebase'i Android projenize eklemek için Firebase dokümanlarındaki adımları uygulayın.

Gradle bağımlılığını ekleyin

build.gradle dosyanıza aşağıdaki bağımlılıkları ekleyin:

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")
}

Görüntü üretme

Android uygulamanızda görüntü oluşturmak için isteğe bağlı yapılandırmayla bir ImagenModel örneği oluşturarak başlayın.

generationConfig parametresini kullanarak negatif istem, resim sayısı, çıktı resminin en boy oranı, resim biçimi tanımlayabilir ve filigran ekleyebilirsiniz. Güvenlik ve kişi filtrelerini yapılandırmak için safetySettings parametresini kullanabilirsiniz.

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 örneklendirildikten sonra generateImages'i çağırarak resim oluşturabilirsiniz:

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();
}

Resimleri Imagen ile düzenleme

Firebase AI Logic SDK'ları, Imagen modeli aracılığıyla gelişmiş görüntü düzenleme özellikleri sunar. Bu sayede:

  • Maskelere göre resimleri düzenleme (ör. nesne ekleme veya kaldırma, resim içeriğini orijinal sınırlarının ötesine genişletme ve arka planları değiştirme)
  • Belirli stiller (desenler, dokular veya sanatçı stilleri) uygulayarak, çeşitli konulara (ör. ürünler, insanlar veya hayvanlar) odaklanarak ya da farklı kontrolleri (ör. elle çizilmiş bir eskiz, keskin kenarlı bir resim veya yüz ağı) kullanarak resimleri özelleştirin.

Model başlatma

Imagen düzenleme özelliklerini kullanmak için imgen-3.0-capability-001 gibi görüntü düzenlemeyi destekleyen bir Imagen modeli belirtin. modelin sürümü:

val imagenModel = Firebase.ai(backend = GenerativeBackend.vertexAI())
.imagenModel("imagen-3.0-capability-001")

Maske tabanlı düzenleme

Imagen'ın maske tabanlı düzenleme özelliği, modelin üzerinde değişiklik yapacağı belirli alanları tanımlayarak resimlerde değişiklik yapmanıza olanak tanır. Bu özellik, maske oluşturma ve uygulama, nesne ekleme veya kaldırma ve resim içeriğini orijinal sınırların ötesine genişletme gibi çeşitli işlemler yapmanızı sağlar.

Maske oluşturma

Nesne ekleme veya kaldırma gibi maske tabanlı düzenleme işlemleri yapmak için model tarafından düzenlenmesi gereken alanı, yani maskeyi tanımlamanız gerekir.

Maske oluşturmak için ImagenBackgroundMask() veya ImagenSemanticMask() kullanarak modeli otomatik olarak oluşturabilir ve sınıf kimliği iletebilirsiniz.

Maske bit eşlemi oluşturup ImagenRawMask dosyasına dönüştürerek maskeyi ekranda manuel olarak da çizebilirsiniz. detectDragGestures ve Canvas kullanarak uygulamanızda Jetpack Compose ile maske çizme kullanıcı arayüzünü aşağıdaki gibi uygulayabilirsiniz:

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")
        }
    }
}

Ardından, tuvalde yolları çizerek maske bit eşlemini oluşturabilirsiniz:

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
}

Maskenin, kaynak resimle aynı boyutta olduğundan emin olun. Daha fazla bilgi için Imagen Yapay Zeka Katalog Örnekleri'ne bakın.

Nesne ekleme

Mevcut bir resme yeni bir nesne veya içerik ekleyebilirsiniz. Bu işleme inpainting de denir. Model, yeni içeriği oluşturup belirtilen maskelenmiş alana ekler.

Bunu yapmak için editImage() işlevini kullanın. Orijinal resmi, maskeyi ve eklemek istediğiniz içeriği açıklayan bir metin istemi sağlamanız gerekir. Ayrıca, ImagenEditingConfig nesnesi iletin ve editMode özelliğinin ImagenEditMode.INPAINT_INSERTION olarak ayarlandığından emin olun.

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
}

Nesneleri kaldırma

İç boyama, istenmeyen nesneleri resimden kaldırmanıza olanak tanır. Bunu yapmak için editImage işlevini kullanın. Orijinal resmi ve kaldırmak istediğiniz nesneyi vurgulayan bir maske sağlamanız gerekir. İsteğe bağlı olarak, nesneyi açıklayan bir metin istemi ekleyebilirsiniz. Bu istem, modelin doğru tanımlama yapmasına yardımcı olabilir. Ayrıca, ImagenEditingConfig içindeki editMode öğesini ImagenEditMode.INPAINT_REMOVAL olarak ayarlamanız gerekir.

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
}

Resim içeriğini genişletme

outpaintImage() işlevini kullanarak bir resmi orijinal sınırlarının ötesine genişletebilirsiniz. Bu işleme outpainting denir. Bu işlev için orijinal resim ve genişletilmiş resmin gerekli Dimensions gerekir. İsteğe bağlı olarak, genişletme için açıklayıcı bir istem ekleyebilir ve yeni oluşturulan resimde orijinal resmin ImagenImagePlacement bölümünü belirtebilirsiniz:

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
}

Arka planı değiştirme

Ön plandaki öğeyi koruyarak bir resmin arka planını değiştirebilirsiniz. Bunu yapmak için editImage işlevini kullanın. Orijinal resmi, ImagenBackgroundMask nesnesini (yeni arka plan için metin istemi içeren) ve editMode özelliği ImagenEditMode.INPAINT_INSERTION olarak ayarlanmış bir ImagenEditingConfig nesnesini iletin.

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
}

Özelleştirme

Bir özne, kontrol veya stil belirten referans görüntülere göre görüntü oluşturmak ya da düzenlemek için Imagen'in özelleştirme özelliğini kullanabilirsiniz. Bu işlem, modele yol göstermek için bir veya daha fazla referans resimle birlikte metin istemi sağlanarak gerçekleştirilir.

Konuya göre özelleştirme

Referans resimden (ör. ürün, kişi veya hayvan) belirli bir öznenin yeni resimlerini oluşturabilirsiniz. Metin istemi ve konuyla ilgili en az bir referans resim sağlamanız yeterlidir. Örneğin, evcil hayvanınızın resmini yükleyip tamamen farklı bir ortamda yeni bir resim oluşturabilirsiniz.

Bunu yapmak için ImagenSubjectReference kullanarak konu referansını tanımlayın ve ardından isteminizle birlikte editImage'ye iletin. Ayrıca, editSteps sayısını belirten bir ImagenEditingConfig ekleyin. Daha yüksek bir editSteps değeri genellikle daha kaliteli sonuçlar sağlar:

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
}

Bir kontrole göre özelleştirme

Bu teknik, elle çizilmiş bir eskiz ("karalama"), Canny kenar görüntüsü veya yüz ağı gibi bir kontrol referans görüntüsüne dayalı olarak yeni bir görüntü oluşturur. Model, yeni görüntünün düzeni ve kompozisyonu için kontrol görüntüsünü yapısal bir kılavuz olarak kullanırken metin istemi renk ve doku gibi ayrıntıları sağlar.

ImagenControlReference ile bir kontrol referansı tanımlayın ve bunu bir istemle birlikte editImage'ye ve ImagenEditingConfig ile editSteps sayısıyla birlikte sağlayın (daha yüksek bir değer kaliteyi artırabilir):

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
}

Stile göre özelleştirme

Bir referans resimdeki belirli bir stille (ör. desen, doku veya tasarım) eşleşen bir resim oluşturabilir ya da düzenleyebilirsiniz. Model, istenen estetiği anlamak için referans resmi kullanır ve bunu metin isteminde açıklanan yeni resme uygular. Örneğin, ünlü bir tablonun resmini sağlayarak o tablonun tarzında bir kedi resmi oluşturabilirsiniz.

ImagenStyleReference ile bir stil referansı tanımlayın ve bunu editImage ile birlikte bir istem ve ImagenEditingConfig ile editSteps sayısıyla (daha yüksek bir değer kaliteyi artırabilir) birlikte sağlayın:

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 
}

Sonraki adımlar