Przewodnik po generowaniu obrazów w przypadku Androida

Zadanie MediaPipe Image Generator umożliwia generowanie obrazów na podstawie prompta tekstowego. To zadanie wykorzystuje model zamiany tekstu na obraz do generowania obrazów za pomocą technik dyfuzji.

Zadanie przyjmuje jako dane wejściowe prompt tekstowy oraz opcjonalny obraz warunkowy, który model może rozszerzyć i użyć jako odniesienia do generowania. Generator obrazów może też generować obrazy na podstawie konkretnych koncepcji dostarczonych do modelu podczas trenowania lub ponownego trenowania. Więcej informacji znajdziesz w artykule Dostosowywanie za pomocą LoRA.

Przykładowy kod opisany w tych instrukcjach jest dostępny na GitHub. Więcej informacji o możliwościach, modelach i opcjach konfiguracji tego zadania znajdziesz w tym artykule.

Przykładowy kod

Przykładowy kod MediaPipe Tasks to podstawowe wdrożenie aplikacji Image Generator na Androida. Możesz użyć tej aplikacji jako punktu wyjścia do utworzenia własnej aplikacji na Androida lub skorzystać z niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod generatora obrazów jest hostowany na GitHub.

Pobieranie kodu

Z poniższych instrukcji dowiesz się, jak utworzyć lokalną kopię przykładowego kodu za pomocą narzędzia wiersza poleceń git.

Aby pobrać przykładowy kod:

  1. Sklonuj repozytorium Git za pomocą tego polecenia:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Opcjonalnie możesz skonfigurować instancję Git, aby używać rzadkiego wyewidencjonowania, dzięki czemu będziesz mieć tylko pliki przykładowej aplikacji Image Generator:
    cd mediapipe-samples
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_generation/android
    

Po utworzeniu lokalnej wersji przykładowego kodu możesz zaimportować projekt do Androida Studio i uruchomić aplikację. Instrukcje znajdziesz w przewodniku po konfiguracji na Androida.

Kluczowe komponenty

Te pliki zawierają kluczowy kod dla tej przykładowej aplikacji do generowania obrazów:

  • ImageGenerationHelper.kt: Inicjuje zadanie i obsługuje generowanie obrazu.
  • DiffusionActivity.kt: Generuje obrazy, gdy wtyczki lub wagi LoRA nie są włączone.
  • PluginActivity.kt Implementuje modele wtyczek, które umożliwiają użytkownikom podanie obrazu warunkowego jako danych wejściowych.
  • LoRAWeightActivity.kt: Dostęp do wag LoRA i ich obsługa. Wagi te służą do dostosowywania modeli podstawowych i umożliwiają generowanie obrazów przedstawiających określone koncepcje.

Konfiguracja

W tej sekcji opisujemy najważniejsze kroki, które należy wykonać, aby skonfigurować środowisko programistyczne i projekty kodu do korzystania z Generatora obrazów. Ogólne informacje o konfigurowaniu środowiska programistycznego do korzystania z zadań MediaPipe, w tym wymagania dotyczące wersji platformy, znajdziesz w przewodniku konfiguracji na Androida.

Zależności

Zadanie Generator obrazów korzysta z biblioteki com.google.mediapipe:tasks-vision-image-generator. Dodaj tę zależność do pliku build.gradle w aplikacji na Androida:

dependencies {
    implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'
}

W przypadku urządzeń z Androidem 12 (API 31) lub nowszym dodaj zależność od natywnej biblioteki OpenCL. Więcej informacji znajdziesz w dokumentacji dotyczącej tagu uses-native-library.

Dodaj do pliku AndroidManifest.xml te tagi uses-native-library:

<uses-native-library android:name="libOpenCL.so" android:required="false" />
<uses-native-library android:name="libOpenCL-car.so" android:required="false"/>
<uses-native-library android:name="libOpenCL-pixel.so" android:required="false" />

Model

Zadanie MediaPipe Image Generator wymaga wytrenowanego modelu podstawowego, który jest z nim zgodny. Po pobraniu modelu zainstaluj wymagane zależności i przekonwertuj model do odpowiedniego formatu. Następnie przenieś przekonwertowany model na urządzenie z Androidem.

Więcej informacji o dostępnych wytrenowanych modelach Generatora obrazów znajdziesz w sekcji Modele w omówieniu zadania.

Pobieranie modelu podstawowego

Generator obrazów wymaga, aby model podstawowy był zgodny z formatem modelu stable-diffusion-v1-5/stable-diffusion-v1-5 EMA-only, na podstawie tego modelu: stable-diffusion-v1-5/stable-diffusion-v1-5 EMA-only.

Instalowanie zależności i konwertowanie modelu

$ pip install torch typing_extensions numpy Pillow requests pytorch_lightning absl-py

Uruchom skrypt convert.py:

$ python3 convert.py --ckpt_path <ckpt_path> --output_path <output_path>

Przekazywanie przekonwertowanego modelu na urządzenie

Przekaż zawartość folderu <output_path> na urządzenie z Androidem.

$ adb shell rm -r /data/local/tmp/image_generator/ # Remove any previously loaded weights
$ adb shell mkdir -p /data/local/tmp/image_generator/
$ adb push <output_path>/. /data/local/tmp/image_generator/bins

Pobieranie modeli wtyczek i dodawanie wag LoRA (opcjonalnie)

Jeśli zamierzasz używać modelu wtyczki, sprawdź, czy model musi zostać pobrany. W przypadku wtyczek, które wymagają dodatkowego modelu, modele wtyczek muszą być dołączone do pliku APK lub pobierane na żądanie. Modele wtyczek są lekkie (ok. 23 MB) i można je dołączyć bezpośrednio do pliku APK. Zalecamy jednak pobieranie modeli wtyczek na żądanie.

Jeśli masz model dostosowany za pomocą LoRA, możesz pobrać go na żądanie. Więcej informacji znajdziesz w artykule Wagi LoRA modelu wtyczki.

Tworzenie zadania

Zadanie MediaPipe Image Generator używa funkcji createFromOptions() do skonfigurowania zadania. Funkcja createFromOptions() akceptuje wartości opcji konfiguracji. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Opcje konfiguracji.

Opcje konfiguracji

To zadanie ma te opcje konfiguracji w przypadku aplikacji na Androida:

Nazwa opcji Opis Zakres wartości
imageGeneratorModelDirectory Katalog modelu generatora obrazów, w którym są przechowywane wagi modelu. PATH
loraWeightsFilePath Ustawia ścieżkę do pliku wag LoRA. Opcjonalne i ma zastosowanie tylko wtedy, gdy model został dostosowany za pomocą LoRA. PATH
errorListener Ustawia opcjonalny odbiornik błędów. N/A

Zadanie obsługuje też modele wtyczek, które umożliwiają użytkownikom dodawanie do danych wejściowych obrazów warunkowych, które model podstawowy może rozszerzać i wykorzystywać jako odniesienie do generowania. Obrazy warunków mogą zawierać punkty orientacyjne twarzy, kontury krawędzi i szacunki głębi, które model wykorzystuje jako dodatkowy kontekst i informacje do generowania obrazów.

Gdy dodajesz model wtyczki do modelu podstawowego, skonfiguruj też opcje wtyczki. Wtyczka Face landmark używa faceConditionOptions, wtyczka Canny edge używa edgeConditionOptions, a wtyczka Depth używa depthConditionOptions.

Opcje wykrywania krawędzi metodą Canny

Skonfiguruj te opcje w edgeConditionOptions.

Nazwa opcji Opis Zakres wartości Wartość domyślna
threshold1 Pierwszy próg procedury histerezy. Float 100
threshold2 Drugi próg procedury histerezy. Float 200
apertureSize Rozmiar przysłony operatora Sobela. Typowy zakres to 3–7. Integer 3
l2Gradient Określa, czy do obliczania wielkości gradientu obrazu ma być używana norma L2 zamiast domyślnej normy L1. BOOLEAN False
EdgePluginModelBaseOptions Obiekt BaseOptions, który ustawia ścieżkę dla modelu wtyczki. BaseOptions obiekt N/A

Więcej informacji o działaniu tych opcji konfiguracji znajdziesz w artykule Wykrywacz krawędzi Canny’ego.

Opcje punktów charakterystycznych twarzy

Skonfiguruj te opcje w faceConditionOptions.

Nazwa opcji Opis Zakres wartości Wartość domyślna
minFaceDetectionConfidence Minimalny poziom ufności, przy którym wykrywanie twarzy jest uznawane za udane. Float [0.0,1.0] 0.5
minFacePresenceConfidence Minimalny poziom ufności wykrycia twarzy. Float [0.0,1.0] 0.5
faceModelBaseOptions Obiekt BaseOptions, który ustawia ścieżkę dla modelu tworzącego obraz warunkowy. BaseOptions obiekt N/A
FacePluginModelBaseOptions Obiekt BaseOptions, który ustawia ścieżkę dla modelu wtyczki. BaseOptions obiekt N/A

Więcej informacji o działaniu tych opcji konfiguracji znajdziesz w sekcji Zadanie Face Landmarker.

Opcje głębi

Skonfiguruj te opcje w depthConditionOptions.

Nazwa opcji Opis Zakres wartości Wartość domyślna
depthModelBaseOptions Obiekt BaseOptions, który ustawia ścieżkę dla modelu tworzącego obraz warunkowy. BaseOptions obiekt N/A
depthPluginModelBaseOptions Obiekt BaseOptions, który ustawia ścieżkę dla modelu wtyczki. BaseOptions obiekt N/A

Tworzenie tylko za pomocą modelu podstawowego

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

imageGenerator = ImageGenerator.createFromOptions(context, options)

Tworzenie za pomocą wtyczek

Jeśli stosujesz opcjonalny model wtyczki, ustaw podstawowe opcje modelu wtyczki za pomocą setPluginModelBaseOptions. Jeśli model wtyczki wymaga dodatkowego pobranego modelu do utworzenia obrazu warunku, określ ścieżkę w BaseOptions.

Punkt orientacyjny twarzy

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

val faceModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("face_landmarker.task")
    .build()

val facePluginModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("face_landmark_plugin.tflite")
    .build()

val faceConditionOptions = FaceConditionOptions.builder()
    .setFaceModelBaseOptions(faceModelBaseOptions)
    .setPluginModelBaseOptions(facePluginModelBaseOptions)
    .setMinFaceDetectionConfidence(0.3f)
    .setMinFacePresenceConfidence(0.3f)
    .build()

val conditionOptions = ConditionOptions.builder()
    .setFaceConditionOptions(faceConditionOptions)
    .build()

imageGenerator =
    ImageGenerator.createFromOptions(context, options, conditionOptions)
    

Canny Edge

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

val edgePluginModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("canny_edge_plugin.tflite")
    .build()

val edgeConditionOptions = EdgeConditionOptions.builder()
    .setThreshold1(100.0f)
    .setThreshold2(100.0f)
    .setApertureSize(3)
    .setL2Gradient(false)
    .setPluginModelBaseOptions(edgePluginModelBaseOptions)
    .build()

val conditionOptions = ConditionOptions.builder()
    .setEdgeConditionOptions(edgeConditionOptions)
    .build()

imageGenerator =
    ImageGenerator.createFromOptions(context, options, conditionOptions)
    

Głębokość

val options = ImageGeneratorOptions.builder()
    .setImageGeneratorModelDirectory(modelPath)
    .build()

val depthModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("depth_model.tflite")
    .build()

val depthPluginModelBaseOptions = BaseOptions.builder()
    .setModelAssetPath("depth_plugin.tflite")
    .build()

val depthConditionOptions =
    ConditionOptions.DepthConditionOptions.builder()
        .setDepthModelBaseOptions(depthModelBaseOptions)
        .setPluginModelBaseOptions(depthPluginModelBaseOptions)
        .build()

val conditionOptions = ConditionOptions.builder()
    .setDepthConditionOptions(depthConditionOptions)
    .build()

imageGenerator =
    ImageGenerator.createFromOptions(context, options, conditionOptions)
    

Tworzenie z wagami LoRA

Jeśli uwzględniasz wagi LoRA, użyj parametru loraWeightsFilePath, aby wskazać ścieżkę.

val options = ImageGeneratorOptions.builder()
    .setLoraWeightsFilePath(weightsPath)
    .setImageGeneratorModelDirectory(modelPath)
    .build()

imageGenerator = ImageGenerator.createFromOptions(context, options)

Przygotuj dane

Generator obrazów akceptuje te dane wejściowe:

  • prompt (wymagany): prompt tekstowy opisujący obraz, który ma zostać wygenerowany.
  • iterations (wymagane): łączna liczba iteracji potrzebnych do wygenerowania obrazu. Dobrym punktem wyjścia jest 20.
  • seed (wymagane): losowy klucz używany podczas generowania obrazu.
  • condition image (opcjonalnie): obraz, którego model używa jako odniesienia do generowania. Ma zastosowanie tylko w przypadku korzystania z modelu wtyczki.
  • condition type (opcjonalnie): typ modelu wtyczki używanego w przypadku zadania. Ma zastosowanie tylko w przypadku korzystania z modelu wtyczki.

Dane wejściowe zawierające tylko model podstawowy

fun setInput(prompt: String, iteration: Int, seed: Int) {
    imageGenerator.setInputs(prompt, iteration, seed)
}

Wejścia z wtyczkami

Jeśli stosujesz opcjonalny model wtyczki, użyj też parametru conditionType, aby wybrać model wtyczki, oraz parametru sourceConditionImage, aby wygenerować obraz warunkowy.

Nazwa opcji Opis Wartość
conditionType Model wtyczki zastosowany do modelu podstawowego. {"FACE", "EDGE", "DEPTH"}
sourceConditionImage Obraz źródłowy użyty do utworzenia obrazu warunkowego. MPImage obiekt

Jeśli używasz modelu wtyczki, użyj createConditionImage, aby utworzyć obraz warunku:

fun createConditionImage(
    inputImage: MPImage,
    conditionType: ConditionType
): Bitmap {
    val result =
        imageGenerator.createConditionImage(inputImage, conditionType)
    return BitmapExtractor.extract(result)
}

Po utworzeniu obrazu warunkowego uwzględnij go jako dane wejściowe wraz z promptem, wartością ziarna i liczbą iteracji.

imageGenerator.setInputs(
    prompt,
    conditionalImage,
    conditionType,
    iteration,
    seed
)

Dane wejściowe z wagami LoRA

Jeśli używasz wag LoRA, upewnij się, że token znajduje się w prompcie tekstowym, jeśli chcesz wygenerować obraz z określonym pojęciem reprezentowanym przez wagi.

fun setInput(prompt: String, iteration: Int, seed: Int) {
    imageGenerator.setInputs(prompt, iteration, seed)
}

Uruchamianie zadania

Użyj generate(), aby wygenerować obraz na podstawie danych wejściowych podanych w poprzedniej sekcji. W ten sposób powstaje jeden wygenerowany obraz.

Generowanie tylko za pomocą modelu podstawowego

fun generate(prompt: String, iteration: Int, seed: Int): Bitmap {
    val result = imageGenerator.generate(prompt, iteration, seed)
    val bitmap = BitmapExtractor.extract(result?.generatedImage())
    return bitmap
}

Generowanie za pomocą wtyczek

fun generate(
    prompt: String,
    inputImage: MPImage,
    conditionType: ConditionType,
    iteration: Int,
    seed: Int
): Bitmap {
    val result = imageGenerator.generate(
        prompt,
        inputImage,
        conditionType,
        iteration,
        seed
    )
    val bitmap = BitmapExtractor.extract(result?.generatedImage())
    return bitmap
}

Generowanie za pomocą wag LoRA

Proces generowania obrazów za pomocą modelu dostosowanego za pomocą wag LoRA jest podobny do procesu z użyciem standardowego modelu podstawowego. Upewnij się, że token jest uwzględniony w prompcie, i uruchom ten sam kod.

fun generate(prompt: String, iteration: Int, seed: Int): Bitmap {
    val result = imageGenerator.generate(prompt, iteration, seed)
    val bitmap = BitmapExtractor.extract(result?.generatedImage())
    return bitmap
}

Generowanie iteracyjne

Generator obrazów może też wyświetlać wygenerowane obrazy pośrednie podczas każdej iteracji, zgodnie z parametrem wejściowym iterations. Aby wyświetlić te wyniki pośrednie, wywołaj metodę setInputs, a potem wywołaj execute(), aby uruchomić każdy krok. Ustaw parametr showResult na true, aby wyświetlić wyniki pośrednie.

fun execute(showResult: Boolean): Bitmap {
    val result = imageGenerator.execute(showResult)

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

    return bitmap
}

Obsługa i wyświetlanie wyników

Generator obrazów zwraca obiekt ImageGeneratorResult, który zawiera wygenerowany obraz, sygnaturę czasową zakończenia i obraz warunkowy, jeśli został podany jako dane wejściowe.

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

Ten obraz został wygenerowany na podstawie tych danych wejściowych przy użyciu tylko modelu podstawowego.

Dane wejściowe:

  • Prompt: „kolorowy kreskówkowy szop w kapeluszu z szerokim rondem trzymający kij i idący przez las, animacja, widok z trzech czwartych, obraz”
  • Seed: 312687592
  • Iteracje: 20

Wygenerowany obraz:

Wygenerowany obraz szopa pracza zgodny z promptem