MediaPipe를 사용하여 Android에서 기기 내 이미지 생성

1. 소개

MediaPipe란 무엇인가요?

MediaPipe 솔루션을 사용하면 머신러닝(ML) 솔루션을 앱에 적용할 수 있습니다. 이 솔루션으로 제공되는 프레임워크를 통해 사용자에게 즉각적이고, 매력적이고, 유용한 출력을 제공하는 사전 빌드된 처리 파이프라인을 구성할 수 있습니다. MediaPipe Model Maker를 사용해서 이러한 솔루션을 맞춤설정하여 기본 모델을 업데이트할 수도 있습니다.

텍스트 이미지 변환 생성은 MediaPipe 솔루션이 제공하는 여러 ML 태스크 중 하나입니다.

이 Codelab에서는 거의 비어 있는 Android 앱으로 시작하여 Android 기기에서 직접 새 이미지를 생성할 수 있을 때까지 여러 단계를 진행합니다.

학습할 내용

  • MediaPipe 태스크를 사용하여 Android 앱에서 로컬로 실행되는 텍스트 이미지 변환을 구현하는 방법

필요한 항목

  • 설치된 버전의 Android 스튜디오 (이 Codelab은 Android 스튜디오 Giraffe로 작성 및 테스트됨)
  • RAM이 8GB 이상인 Android 기기
  • Android 개발에 관한 기본 지식과 사전 작성된 Python 스크립트를 실행하는 기능

2. Android 앱에 MediaPipe Tasks 추가

Android 시작 앱 다운로드

이 Codelab에서는 기본 버전의 이미지 생성에 사용되는 UI로 구성된 사전 제작된 샘플로 시작합니다. 시작 앱은 공식 MediaPipe 샘플 저장소 여기에서 확인할 수 있습니다. Code > Download ZIP을 클릭하여 저장소를 클론하거나 zip 파일을 다운로드합니다.

앱을 Android 스튜디오로 가져오기

  1. Android 스튜디오를 엽니다.
  2. Android 스튜디오 시작 화면에서 오른쪽 상단의 열기를 선택합니다.

a0b5b070b802e4ea.png

  1. 저장소를 클론하거나 다운로드한 위치로 이동하여 codelabs/image_generation_basic/android/start 디렉터리를 엽니다.
  2. 아직 MediaPipe Tasks 종속 항목을 포함하지 않았으므로 이 단계에서는 앱이 컴파일되지 않아야 합니다.

build.gradle 파일로 이동하여 // 1단계 - 종속 항목 추가로 스크롤하여 앱을 수정하고 실행합니다. 그런 다음 다음 줄을 포함하고 Android 스튜디오 상단의 배너에 표시되는 Sync Now 버튼을 누릅니다.

// Step 1 - Add dependency
implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'

동기화가 완료되면 Android 스튜디오의 오른쪽 상단에 있는 녹색 실행 화살표 ( 7e15a9c9e1620fe7.png)를 클릭하여 모든 항목이 열리고 올바르게 설치되었는지 확인합니다. 앱이 열리면 라디오 버튼 2개와 INITIALIZE라는 라벨이 지정된 버튼이 있는 화면이 표시됩니다. 이 버튼을 클릭하면 텍스트 프롬프트와 생성 라벨이 지정된 버튼과 함께 다른 옵션으로 구성된 별도의 UI로 즉시 이동합니다.

83c31de8e8a320ee.png 78b8765e832024e3.png

안타깝게도 시작 앱은 여기까지입니다. 이제 이 앱을 완성하고 기기에서 새 이미지를 생성하는 방법을 알아볼 차례입니다.

3. 이미지 생성기 설정

이 예시에서는 대부분의 이미지 생성 작업이 ImageGenerationHelper.kt 파일에서 실행됩니다. 이 파일을 열면 클래스 상단에 imageGenerator라는 변수가 표시됩니다. 이미지 생성 앱에서 많은 작업을 실행하는 Task 객체입니다.

이 객체 바로 아래에 initializeImageGenerator()라는 함수가 표시되며 다음과 같은 주석이 있습니다. // 2단계 - 이미지 생성기 초기화 짐작할 수 있듯이 여기에서 ImageGenerator 객체를 초기화합니다. 이 함수 본문을 다음 코드로 바꾸어 이미지 생성 모델 경로를 설정하고 ImageGenerator 객체를 초기화합니다.

// Step 2 - initialize the image generator
val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

imageGenerator = ImageGenerator.createFromOptions(context, options)

그 아래에는 setInput()이라는 또 다른 함수가 표시됩니다. 이 함수는 생성된 이미지를 정의하는 데 사용되는 프롬프트 문자열, 새 이미지를 생성하는 동안 태스크가 거쳐야 하는 반복 횟수, 동일한 시드를 사용할 때 동일한 이미지를 생성하는 동안 동일한 프롬프트를 기반으로 이미지의 새 버전을 만드는 데 사용할 수 있는 시드 값을 3개의 매개변수로 받습니다. 이 함수의 목적은 중간 단계를 표시하는 이미지를 만들려고 할 때 이미지 생성기에 이러한 초기 매개변수를 설정하는 것입니다.

setInput() 본문(// 3단계 - 입력 수락 주석이 표시됨)을 다음 줄로 바꿉니다.

// Step 3 - accept inputs
imageGenerator.setInputs(prompt, iteration, seed)

다음 두 단계에서 생성이 이루어집니다. generate() 함수는 setInput과 동일한 입력을 허용하지만 중간 단계 이미지를 반환하지 않는 일회성 호출로 이미지를 만듭니다. 이 함수의 본문(// 4단계 - 반복을 표시하지 않고 생성 주석 포함)을 다음과 같이 바꿀 수 있습니다.

// Step 4 - generate without showing iterations
val result = imageGenerator.generate(prompt, iteration, seed)
val bitmap = BitmapExtractor.extract(result?.generatedImage())
return bitmap

이 작업은 동기적으로 실행되므로 백그라운드 스레드에서 함수를 호출해야 합니다. 이 Codelab의 뒷부분에서 자세히 알아봅니다.

이 파일에서 수행할 마지막 단계는 execute() 함수를 채우는 것입니다 (5단계로 라벨이 지정됨). 이 함수는 ImageGenerator execute() 함수로 실행할 생성의 단일 단계에 중간 이미지를 반환해야 하는지 여부를 나타내는 매개변수를 허용합니다. 함수 본문을 다음 코드로 바꿉니다.

// Step 5 - generate with iterations
val result = imageGenerator.execute(showResult)

if (result == null || result.generatedImage() == null) {
    return Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888)
        .apply {
            val canvas = Canvas(this)
            val paint = Paint()
            paint.color = Color.WHITE
            canvas.drawPaint(paint)
        }
}

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

return bitmap

이제 도우미 파일은 완성되었습니다. 다음 섹션에서는 이 예시의 로직을 처리하는 ViewModel 파일을 작성합니다.

4. 앱 통합

MainViewModel 파일은 이 예시 앱과 관련된 UI 상태 및 기타 로직을 처리합니다. 지금 열어 보세요.

파일 상단에 // 6단계 - 모델 경로 설정 주석이 표시됩니다. 여기에서 앱에 이미지 생성에 필요한 모델 파일을 찾을 수 있는 위치를 알려줍니다. 이 예에서는 값을 /data/local/tmp/image_generator/bins/로 설정합니다.

// Step 6 - set model path
private val MODEL_PATH = "/data/local/tmp/image_generator/bins/"

그런 다음 generateImage() 함수까지 아래로 스크롤합니다. 이 함수 하단에는 반환된 반복이 있거나 없는 이미지를 각각 생성하는 데 사용되는 7단계와 8단계가 모두 표시됩니다. 두 작업 모두 동기식으로 실행되므로 코루틴으로 래핑됩니다. 먼저 // 7단계 - 반복을 표시하지 않고 생성하기를 이 코드 블록으로 바꾸어 ImageGenerationHelper 파일에서 generate()를 호출한 다음 UI 상태를 업데이트할 수 있습니다.

// Step 7 - Generate without showing iterations
val result = helper?.generate(prompt, iteration, seed)
_uiState.update {
    it.copy(outputBitmap = result)
}

8단계는 조금 더 까다롭습니다. execute() 함수는 이미지 생성의 모든 단계 대신 하나의 단계만 실행하므로 루프를 통해 각 단계를 개별적으로 호출해야 합니다. 또한 사용자에게 현재 단계를 표시해야 하는지 여부도 결정해야 합니다. 마지막으로 현재 반복을 표시해야 하는 경우 UI 상태를 업데이트합니다. 이제 이 모든 작업을 할 수 있습니다.

// Step 8 - Generate with showing iterations
helper?.setInput(prompt, iteration, seed)
for (step in 0 until iteration) {
    isDisplayStep =
        (displayIteration > 0 && ((step + 1) % displayIteration == 0))
    val result = helper?.execute(isDisplayStep)

    if (isDisplayStep) {
        _uiState.update {
            it.copy(
                outputBitmap = result,
                generatingMessage = "Generating... (${step + 1}/$iteration)",
            )
        }
    }
}

이제 앱을 설치하고, 이미지 생성기를 초기화한 다음, 텍스트 프롬프트를 기반으로 새 이미지를 만들 수 있습니다.

단, 이제 이미지 생성기를 초기화하려고 하면 앱이 비정상 종료됩니다. 모델 파일을 기기에 복사해야 하기 때문에 이 문제가 발생합니다. 작동하는 것으로 알려진 서드 파티 모델에 관한 최신 정보를 확인하고, 이 MediaPipe 작업에 맞게 변환하고, 기기에 복사하려면 공식 문서의 이 섹션을 검토하세요.

파일을 개발 기기에 직접 복사하는 것 외에도 Firebase Storage를 설정하여 런타임에 필요한 파일을 사용자 기기에 직접 다운로드할 수도 있습니다.

5. 앱 배포 및 테스트

완료하면 텍스트 프롬프트를 수락하고 기기에서 완전히 새 이미지를 생성할 수 있는 앱이 작동하게 됩니다. 앱을 실제 Android 기기에 배포하여 테스트합니다. 단, 메모리가 8GB 이상인 기기에서 테스트하는 것이 좋습니다.

  1. Android 스튜디오 툴바에서 Run(실행) 아이콘( 7e15a9c9e1620fe7.png)을 클릭하여 앱을 실행합니다.
  2. 생성 단계 유형 (최종 또는 반복 포함)을 선택한 다음 INITIALIZE 버튼을 누릅니다.
  3. 다음 화면에서 원하는 속성을 설정하고 생성 버튼을 클릭하여 도구가 생성한 결과를 확인합니다.

e46cfaeb9d3fc235.gif

6. 축하합니다.

축하합니다. 이 Codelab에서는 Android 앱에 기기 내 텍스트 대 이미지 생성을 추가하는 방법을 알아봤습니다.

다음 단계

이미지 생성 태스크로 할 수 있는 작업은 다음을 포함하여 더 많습니다.

  • 기본 이미지를 사용하여 플러그인을 통해 생성된 이미지를 구성하거나 Vertex AI를 통해 자체 LoRA 가중치를 추가로 학습할 수 있습니다.
  • Firebase Storage를 사용하여 ADB 도구를 사용하지 않고도 기기에서 모델 파일을 가져옵니다.

이 실험용 태스크로 만들어 보실 멋진 결과물을 기대하며 MediaPipe팀의 더 많은 Codelab과 콘텐츠도 기대해 주세요.