Imagen은 이미지 생성 모델입니다. 사용자 프로필의 맞춤 아바타를 생성하거나 맞춤설정된 시각적 애셋을 기존 화면 흐름에 통합하여 사용자 참여도를 높이는 데 사용할 수 있습니다.
Imagen 모델에 Firebase AI Logic SDK 를 사용하여 Android 앱에서 액세스할 수 있습니다. Imagen 모델은 두 가지 Firebase AI Logic API 제공업체인 Gemini Developer API (대부분의 개발자에게 권장됨)와 Vertex AI를 사용하여 사용할 수 있습니다.
프롬프트 실험
이상적인 프롬프트를 만들려면 여러 번 시도해야 하는 경우가 많습니다. 프롬프트 디자인 및 프로토타입 제작을 위한 IDE인 Google AI Studio에서 이미지 프롬프트를 실험해 볼 수 있습니다. 프롬프트를 개선하는 방법에 관한 도움말은 프롬프트 및 이미지 속성 가이드를 검토하세요.
Firebase 프로젝트 설정 및 앱 연결
Firebase 문서의 단계에 따라 Android 프로젝트에 Firebase를 추가합니다.
Gradle 종속 항목 추가
build.gradle 파일에 다음 종속 항목을 추가합니다.
dependencies {
// Import the BoM for the Firebase platform
implementation(platform("com.google.firebase:firebase-bom:34.12.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 ), )
자바
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.getInstance(GenerativeBackend.googleAI()).imagenModel( "imagen-4.0-generate-001", config, new ImagenSafetySettings( ImagenSafetyFilterLevel.BLOCK_LOW_AND_ABOVE, ImagenPersonFilterLevel.BLOCK_ALL)) );
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()
자바
ListenableFuture<ImagenGenerationResponse<ImagenInlineImage>> futureResponse = model.generateImages( "A hyper realistic picture of a t-rex with a blue bagpack in a prehistoric forest"); try { ImagenGenerationResponse<ImagenInlineImage> imageResponse = futureResponse.get(); List<ImagenInlineImage> images = null; if (imageResponse != null) { images = imageResponse.getImages(); } if (images != null && !images.isEmpty()) { ImagenInlineImage image = images.get(0); Bitmap bitmapImage = image.asBitmap(); // Use bitmapImage } } catch (ExecutionException | InterruptedException e) { e.printStackTrace(); }
Imagen으로 이미지 수정
Firebase AI Logic SDK는 Imagen 모델을 통해 고급 이미지 수정 기능을 제공하므로 다음 작업을 할 수 있습니다.
- 마스크를 기반으로 이미지 수정 : 객체 삽입 또는 삭제, 이미지 콘텐츠를 원래 경계 너머로 확장, 배경 변경과 같은 작업이 포함됩니다.
- 이미지 맞춤설정 : 특정 스타일 (패턴, 질감 또는 아티스트 스타일)을 적용하거나, 다양한 피사체 (예: 제품, 사람 또는 동물)에 집중하거나, 다양한 컨트롤 (예: 손으로 그린 스케치, 캐니 윤곽선 이미지 또는 얼굴 메시)을 준수하여 이미지를 맞춤설정합니다.
모델 초기화
Imagen 편집 기능을 사용하려면 이미지 수정을 지원하는 Imagen 모델(예: imagen-3.0-capability-001)을 지정합니다.
val imagenModel = Firebase.ai(backend = GenerativeBackend.vertexAI()) .imagenModel("imagen-3.0-capability-001")
마스크 기반 수정
Imagen의 마스크 기반 수정을 사용하면 모델이 조작할 특정 영역을 정의하여 이미지를 수정할 수 있습니다. 이 기능을 사용하면 마스크 만들기 및 적용, 객체 삽입 또는 삭제, 이미지 콘텐츠를 원래 경계 너머로 확장하는 등 다양한 작업을 할 수 있습니다.
마스크 만들기
객체 삽입 또는 삭제와 같은 마스크 기반 수정을 실행하려면 모델에서 수정해야 하는 영역인 마스크 를 정의해야 합니다.
마스크를 만들려면
ImagenBackgroundMask() 또는 ImagenSemanticMask()를 사용하여 모델에서 마스크를 자동 생성하도록 할 수 있습니다. 클래스
ID를 전달합니다.
마스크 비트맵을 생성하고 이를 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 = createMaskBitmap(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 = Bitmap.createBitmap(sourceBitmap.width, sourceBitmap.height, Bitmap.Config.ARGB_8888) 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( referenceImages = listOf( ImagenRawImage(originalImage.toImagenInlineImage()), mask, ), prompt = prompt, // Define the editing configuration for inpainting and insertion. config = ImagenEditingConfig(ImagenEditMode.INPAINT_INSERTION) ) return editedImage }
객체 삭제
인페인팅을 사용하면 이미지에서 원치 않는 객체를 삭제할 수 있습니다. 이렇게 하려면 editImage 함수를 사용합니다. 삭제할 객체를 강조표시하는 원본 이미지와
마스크를 제공해야 합니다. 선택적으로 객체를 설명하는 텍스트 프롬프트를 포함할 수 있습니다. 이는 모델이 정확하게 식별하는 데 도움이 될 수 있습니다. 또한 ImagenEditingConfig 내에서 editMode를 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( referenceImages = listOf( ImagenRawImage(originalImage.toImagenInlineImage()), 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 = imagenModel.outpaintImage( originalImage.toImagenInlineImage(), Dimensions(1024, 1024), prompt = prompt, newPosition = ImagenImagePlacement.LEFT_CENTER ) return editedImage }
배경 바꾸기
전경 피사체를 유지하면서 이미지의 배경을 바꿀 수 있습니다. 이렇게 하려면 editImage 함수를 사용합니다. 원본 이미지, ImagenBackgroundMask 객체 (새 배경의 텍스트 프롬프트 포함), editMode 속성이 ImagenEditMode.INPAINT_INSERTION으로 설정된 ImagenEditingConfig를 전달합니다.
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( referenceImages = listOf( ImagenRawImage(originalImage.toImagenInlineImage()), ImagenBackgroundMask(), ), prompt = prompt, config = ImagenEditingConfig(ImagenEditMode.INPAINT_INSERTION) ) return editedImage }
맞춤설정
Imagen의 맞춤설정 기능 을 사용하여 피사체, 컨트롤 또는 스타일을 지정하는 참고 이미지를 기반으로 이미지를 생성하거나 수정할 수 있습니다. 이는 모델을 안내하기 위해 하나 이상의 참고 이미지와 함께 텍스트 프롬프트를 제공하여 달성됩니다.
피사체를 기반으로 맞춤설정
참고 이미지 (예: 제품, 사람 또는 동물)에서 특정 피사체의 새 이미지를 생성할 수 있습니다. 텍스트 프롬프트와 피사체의 참고 이미지를 하나 이상 제공하기만 하면 됩니다. 예를 들어 반려동물의 사진을 업로드하고 완전히 다른 환경에서 새 이미지를 생성할 수 있습니다.
이렇게 하려면 ImagenSubjectReference를 사용하여 피사체 참고를 정의한 다음 프롬프트와 함께 editImage에 전달합니다. 또한 editSteps 수를 지정하는 ImagenEditingConfig를 포함합니다. 일반적으로 editSteps 값이 높을수록 더 나은 품질의 결과가 생성됩니다.
suspend fun customizeCatImage(model: ImagenModel, referenceCatImage: Bitmap): ImagenGenerationResponse<ImagenInlineImage> { // Define the subject reference using the reference image. val subjectReference = ImagenSubjectReference( image = referenceCatImage.toImagenInlineImage(), 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( referenceImages = listOf(subjectReference), prompt = prompt, config = ImagenEditingConfig( editSteps = 50 // Number of editing steps, a higher value can improve quality ) ) return editedImage }
컨트롤을 기반으로 맞춤설정
이 기법은 손으로 그린 스케치('낙서'), 캐니 윤곽선 이미지 또는 얼굴 메시와 같은 컨트롤 참고 이미지를 기반으로 새 이미지를 생성합니다. 모델은 컨트롤 이미지를 새 이미지의 레이아웃 및 구성을 위한 구조적 가이드로 사용하며 텍스트 프롬프트는 색상 및 질감과 같은 세부정보를 제공합니다.
ImagenControlReference로 컨트롤 참고를 정의하고 프롬프트 및 editSteps 수가 포함된 ImagenEditingConfig와 함께 editImage에 제공합니다 (값이 높을수록 품질이 향상될 수 있음).
suspend fun customizeCatImageByControl(model: ImagenModel, referenceImage: Bitmap): ImagenGenerationResponse<ImagenInlineImage> { // Define the subject reference using the reference image. val controlReference = ImagenControlReference( image = referenceImage.toImagenInlineImage(), referenceId = 1, type = ImagenControlType.SCRIBBLE, ) val prompt = "A cat flying through outer space arranged like the scribble map[1]" val editedImage = model.editImage( referenceImages = listOf(controlReference), prompt = prompt, config = ImagenEditingConfig( editSteps = 50 ), ) return editedImage }
스타일을 기반으로 맞춤설정
참고 이미지의 특정 스타일(예: 패턴, 질감 또는 디자인)과 일치하도록 이미지를 생성하거나 수정할 수 있습니다. 모델은 참고 이미지를 사용하여 필요한 미적 감각을 파악하고 이를 텍스트 프롬프트에 설명된 새 이미지에 적용합니다. 예를 들어 유명한 그림의 이미지를 제공하여 해당 그림의 스타일로 고양이 이미지를 생성할 수 있습니다.
ImagenStyleReference로 스타일 참고를 정의하고 프롬프트 및 editSteps 수가 포함된 ImagenEditingConfig와 함께 editImage에 제공합니다 (값이 높을수록 품질이 향상될 수 있음).
suspend fun customizeImageByStyle(model: ImagenModel, referenceVanGoghImage: Bitmap): ImagenGenerationResponse<ImagenInlineImage> { // Define the style reference using the reference image. val styleReference = ImagenStyleReference( image = referenceVanGoghImage.toImagenInlineImage(), 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( referenceImages = listOf(styleReference), prompt = prompt, config = ImagenEditingConfig( editSteps = 50 // Number of editing steps, a higher value can improve quality ), ) return editedImage }
다음 단계
- Firebase 문서에서 Firebase AI Logic에 대해 자세히 알아보세요.
- Android AI 샘플 카탈로그를 살펴보세요.