تولید تصاویر با Imagen، تولید تصاویر با Imagen، تولید تصاویر با Imagen

ایمجین (Imagen) یک مدل تولید تصویر است که می‌توان از آن برای تولید آواتارهای سفارشی برای پروفایل‌های کاربران یا ادغام عناصر بصری شخصی‌سازی‌شده در جریان‌های صفحه نمایش موجود برای افزایش تعامل کاربر استفاده کرد.

شما می‌توانید با استفاده از Firebase AI Logic SDK از طریق برنامه اندروید خود به مدل‌های Imagen دسترسی داشته باشید . مدل‌های Imagen با استفاده از هر دو ارائه‌دهنده API Firebase AI Logic در دسترس هستند: Gemini Developer API (که برای اکثر توسعه‌دهندگان توصیه می‌شود) و Vertex AI.

نموداری که معماری یکپارچه‌سازی منطق هوش مصنوعی فایربیس را برای دسترسی به رابط برنامه‌نویسی نرم‌افزار توسعه‌دهنده جمینی نشان می‌دهد. یک برنامه اندروید از کیت توسعه نرم‌افزار اندروید فایربیس برای اتصال به فایربیس استفاده می‌کند. سپس فایربیس با رابط برنامه‌نویسی نرم‌افزار توسعه‌دهنده جمینی تعامل می‌کند که به جمینی پرو و ​​فلش در فضای ابری دسترسی دارد.
شکل ۱. دسترسی به مدل‌های Imagen با استفاده از Firebase AI Logic

با دستورالعمل‌ها آزمایش کنید

ایجاد دستورالعمل‌های ایده‌آل اغلب نیاز به چندین تلاش دارد. می‌توانید دستورالعمل‌های تصویری را در Google AI Studio ، یک IDE برای طراحی و نمونه‌سازی دستورالعمل، آزمایش کنید. برای نکاتی در مورد چگونگی بهبود دستورالعمل‌های خود، راهنمای ویژگی دستورالعمل و تصویر را مرور کنید.

تصویری از رابط کاربری استودیوی هوش مصنوعی گوگل، که چهار تصویر تولید شده از یک تی-رکس با کوله پشتی آبی در یک جنگل ماقبل تاریخ را نشان می‌دهد.
شکل ۲. گوگل هوش مصنوعی استودیو می‌تواند به شما در اصلاح دستورالعمل‌های تولید تصویر کمک کند.

یک پروژه Firebase راه‌اندازی کنید و برنامه خود را متصل کنید

برای افزودن Firebase به پروژه اندروید خود، مراحل موجود در مستندات Firebase را دنبال کنید.

وابستگی 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")
}

ایجاد یک تصویر

برای تولید یک تصویر در برنامه اندروید خود، با نمونه‌سازی یک ImagenModel با یک پیکربندی اختیاری شروع کنید.

شما می‌توانید از پارامتر generationConfig برای تعریف یک اعلان منفی، تعداد تصاویر، نسبت ابعاد تصویر خروجی، فرمت تصویر و افزودن واترمارک استفاده کنید. می‌توانید از پارامتر safetySettings برای پیکربندی فیلترهای ایمنی و شخص استفاده کنید.

کاتلین

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

جاوا

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 تصاویر را تولید کنید:

کاتلین

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

جاوا

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 مراجعه کنید.

درج اشیاء

شما می‌توانید یک شیء یا محتوای جدید را در یک تصویر موجود وارد کنید، که به آن inpainting نیز می‌گویند. مدل، محتوای جدید را تولید و در ناحیه ماسک‌شده مشخص‌شده وارد می‌کند.

برای رسیدن به این هدف، از تابع 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
}

حذف اشیاء

با استفاده از Inpainting می‌توانید اشیاء ناخواسته را از تصویر حذف کنید. برای انجام این کار، از تابع 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() یک تصویر را فراتر از مرزهای اصلی آن، که به عنوان outpainting شناخته می‌شود، گسترش دهید. این تابع به تصویر اصلی و 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 تعریف کنید و آن را به همراه یک prompt و ImagenEditingConfig با تعداد editSteps (مقدار بالاتر می‌تواند کیفیت را بهبود بخشد) در اختیار editImage قرار دهید:

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 تعریف کنید و آن را به همراه یک prompt و ImagenEditingConfig با تعداد editSteps (مقدار بالاتر می‌تواند کیفیت را بهبود بخشد) در اختیار editImage قرار دهید:

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 
}

مراحل بعدی