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

1. 소개

MediaPipe란 무엇인가요?

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

Text-to-Image 생성은 MediaPipe 솔루션이 제공하는 여러 ML 작업 중 하나입니다.

이 Codelab에서는 기본적인 수준인 Android 앱으로 시작한 다음 Android 기기에서 직접 새 이미지를 생성할 수 있을 때까지 여러 단계를 진행합니다.

학습할 내용

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

필요한 항목

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

2. Android 앱에 MediaPipe 작업 추가

Android 시작 앱 다운로드

이 Codelab에서는 기본 버전의 이미지 생성에 사용할 UI로 구성된 미리 만들어진 샘플로 시작합니다. 공식 MediaPipe 샘플 저장소는 여기에서 확인할 수 있습니다. 저장소를 클론하거나 코드 > ZIP 파일을 다운로드합니다.

Android 스튜디오로 앱 가져오기

  1. Android 스튜디오를 엽니다.
  2. Welcome to Android Studio 화면에서 오른쪽 상단의 Open을 선택합니다.

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()이라는 다른 함수가 있습니다. 여기서는 생성된 이미지를 정의하는 데 사용할 prompt 문자열, 새 이미지를 생성하는 동안 태스크가 거쳐야 하는 반복 횟수, 동일한 시드를 사용할 때 동일한 이미지를 생성하면서 동일한 프롬프트를 기반으로 새 버전의 이미지를 생성하는 데 사용할 수 있는 시드 값 등 세 가지 매개변수가 허용됩니다. 이 함수의 목적은 중간 단계를 표시하는 이미지를 생성하려고 할 때 이미지 생성기에 이러한 초기 매개변수를 설정하는 것입니다.

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의 뒷부분에서 자세히 알아봅니다.

이 파일에서 실행할 마지막 단계는 5단계로 라벨이 지정된 run() 함수를 작성하는 것입니다. 이렇게 하면 ImageGenerator launch() 함수로 실행할 단일 단계 생성에 대해 중간 이미지를 반환해야 하는지 여부를 알려주는 매개변수가 허용됩니다. 함수 본문을 다음 코드로 바꿉니다.

// 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()를 호출하기 위한 반복을 표시하지 않고 Generate를 바꾼 다음 UI 상태를 업데이트할 수 있습니다.

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

8단계는 조금 더 까다로워집니다. launch() 함수는 이미지 생성을 위한 모든 단계가 아니라 한 단계만 수행하므로 루프를 통해 각 단계를 개별적으로 호출해야 합니다. 또한 사용자에게 현재 단계를 표시해야 하는지도 결정해야 합니다. 마지막으로, 현재 반복을 표시해야 하는 경우 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 저장소를 설정하여 런타임에 필요한 파일을 사용자의 기기에 직접 다운로드할 수도 있습니다.

5. 앱 배포 및 테스트

이러한 작업을 모두 수행하면 텍스트 프롬프트를 허용하고 기기 내에서 완전히 새로운 이미지를 생성할 수 있는 작동하는 앱이 있어야 합니다. 앱을 실제 Android 기기에 배포하여 테스트해 보세요. 단, 메모리가 8GB 이상인 기기에서 시도해 보는 것이 좋습니다.

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

e46cfaeb9d3fc235.gif

6. 축하합니다.

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

다음 단계

이미지 생성 작업으로 할 수 있는 작업은 다음과 같습니다.

  • 기본 이미지를 사용하여 생성된 이미지를 플러그인을 통해 구조화하거나 Vertex AI를 통해 자체 추가 LoRA 가중치를 학습시킵니다.
  • ADB 도구를 사용하지 않아도 Firebase 저장소를 사용하여 기기에서 모델 파일을 검색할 수 있습니다.

이 실험용 작업을 통해 멋진 결과물을 만들어 낼 수 있기를 기대하고 있습니다. MediaPipe팀에서 더 많은 Codelab과 콘텐츠를 기대해 주세요.