Przewodnik po generowaniu obrazów w przypadku Androida

Zadanie Generator obrazu MediaPipe umożliwia generowanie obrazów na podstawie promptu tekstowego. W tym zadaniu model zamiany tekstu w obraz służy 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 wykorzystać jako odniesienie do wygenerowania obrazu. Generator obrazów może też generować obrazy na podstawie konkretnych koncepcji dostarczonych modelowi podczas szkolenia lub ponownego szkolenia. 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 związanych z tym zadaniem znajdziesz w sekcji Omówienie.

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 tych 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 skonfiguruj instancję git, aby używać selektywnego sprawdzania, dzięki czemu będziesz mieć tylko pliki przykładowej aplikacji Image Generator:
    cd mediapipe
    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 Android Studio i uruchomić aplikację. Instrukcje znajdziesz w przewodniku konfiguracji Androida.

Kluczowe komponenty

Te pliki zawierają kluczowy kod aplikacji służącej do przykładowego generowania obrazów:

  • ImageGenerationHelper.kt: inicjuje zadanie i zarządza generowaniem obrazów.
  • DiffusionActivity.kt: generuje obrazy, gdy wtyczki lub wagi LoRA nie są włączone.
  • PluginActivity.kt implementuje modele wtyczki, które umożliwiają użytkownikom podanie obrazu warunku jako wejścia.
  • LoRAWeightActivity.kt: Dostęp do wag LoRA i obsługa wag LoRA, które są używane do dostosowywania modeli podstawowych i umożliwiają generowanie obrazów konkretnych pojęć.

Konfiguracja

W tej sekcji opisaliśmy najważniejsze kroki konfiguracji środowiska programistycznego i projektów kodu, które należy wykonać, aby korzystać 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 Generatora obrazów korzysta z biblioteki com.google.mediapipe:tasks-vision-image-generator. Dodaj tę zależność do pliku build.gradle aplikacji na Androida:

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

W przypadku urządzeń z Androidem 12 (poziom 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 zgodny z tym zadaniem. Po pobraniu modelu zainstaluj wymagane zależności i przekształć model w odpowiednim formacie. Następnie prześlij przekonwertowany model na urządzenie z Androidem.

Więcej informacji o dostępnych wytrenowanych modelach Image Generator znajdziesz w sekcji „Modele” w omówieniu zadania.

Pobieranie modelu podstawowego

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

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>

Przesyłanie 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

Pobierz modele wtyczki i dodaj wagi LoRA (opcjonalnie)

Jeśli chcesz użyć modelu wtyczki, sprawdź, czy musisz go pobrać. W przypadku wtyczek, które wymagają dodatkowego modelu, modele te muszą być załączone w pliku APK lub pobierane na żądanie. Modele w pluginach są lekkie (około 23 MB) i można je umieścić bezpośrednio w pliku APK. Zalecamy jednak pobieranie modeli wtyczek na żądanie.

Jeśli masz model niestandardowy z LoRA, pobierz go na żądanie. Więcej informacji znajdziesz w modelu wtyczki z wagami LoRA.

Tworzenie zadania

Do konfiguracji zadania generatora obrazów MediaPipe służy funkcja createFromOptions(). Funkcja createFromOptions() przyjmuje wartości opcji konfiguracji. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Opcje konfiguracji.

Opcje konfiguracji

W tym zadaniu dostępne są te opcje konfiguracji 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 dotyczy tylko modeli dostosowanych za pomocą LoRA. PATH
errorListener Ustawia opcjonalny odbiornik błędów. N/A

Zadanie obsługuje też modele wtyczek, co pozwala użytkownikom dołączać do danych wejściowych zadania obrazy warunków, które model podstawowy może rozszerzać i wykorzystywać jako odniesienie do generowania. Te obrazy 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.

Podczas dodawania modelu wtyczki do modelu podstawowego skonfiguruj też opcje wtyczki. Wtyczka punkty orientacyjne twarzy używa faceConditionOptions, wtyczka Canny Edge używa edgeConditionOptions, a wtyczka Depth używa depthConditionOptions.

Opcje Canny

Skonfiguruj te opcje na stronie edgeConditionOptions.

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

Więcej informacji o tym, jak działają te opcje konfiguracji, znajdziesz w artykule Canny edge detector.

Opcje punktów charakterystycznych twarzy

Skonfiguruj te opcje na stronie faceConditionOptions.

Nazwa opcji Opis Zakres wartości Wartość domyślna
minFaceDetectionConfidence Minimalny wynik ufności dla wykrywania twarzy, aby uznać go za udany. Float [0.0,1.0] 0.5
minFacePresenceConfidence Minimalny wynik ufności wykrywania obecności twarzy w detekcji punktów orientacyjnych twarzy. Float [0.0,1.0] 0.5
faceModelBaseOptions Obiekt BaseOptions, który ustawia ścieżkę do modelu tworzącego obraz warunku. BaseOptions obiekt N/A
FacePluginModelBaseOptions Obiekt BaseOptions, który ustawia ścieżkę do modelu wtyczki. BaseOptions obiekt N/A

Więcej informacji o tym, jak działają te opcje konfiguracji, znajdziesz w zadaniu dotyczącym usługi Face Landmarker.

Opcje głębokości

Skonfiguruj te opcje na stronie depthConditionOptions.

Nazwa opcji Opis Zakres wartości Wartość domyślna
depthModelBaseOptions Obiekt BaseOptions, który ustawia ścieżkę do modelu tworzenia obrazu warunku. BaseOptions obiekt N/A
depthPluginModelBaseOptions Obiekt BaseOptions, który ustawia ścieżkę do modelu wtyczki. BaseOptions obiekt N/A

Tworzenie z modelem podstawowym

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

imageGenerator = ImageGenerator.createFromOptions(context, options)

Tworzenie za pomocą wtyczek

Jeśli stosujesz opcjonalny model wtyczki, ustaw opcje podstawowe dla modelu wtyczki za pomocą setPluginModelBaseOptions. Jeśli model wtyczki wymaga dodatkowego pobranego modelu do utworzenia obrazu warunku, podaj ścieżkę w polu 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 za pomocą wag LoRA

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

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 (wymagany): losowe nasienie używane podczas generowania obrazu.
  • condition image (opcjonalnie): obraz, którego model używa jako odniesienia do generowania. Dotyczy tylko modelu wtyczki.
  • Warunek typu (opcjonalnie): typ modelu wtyczki używany w zadaniu. Dotyczy tylko modelu wtyczki.

Dane wejściowe z modelem podstawowym

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 warunku.

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

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

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

Po utworzeniu obrazu warunku dodaj 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 promptach tekstowych, jeśli chcesz wygenerować obraz z konkretną koncepcją reprezentowaną przez te wagi.

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

Uruchamianie zadania

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

Generowanie przy użyciu tylko 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 dostosowywanego za pomocą wag LoRA jest podobny do procesu z modelem standardowym. Upewnij się, że token jest uwzględniony w prośbie 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ż generować obrazy pośrednie w ramach każdej iteracji zgodnie z określonym parametrem wejściowym iterations. Aby wyświetlić te wyniki pośrednie, wywołaj metodę setInputs, a potem wywołaj execute(), aby wykonać każdy krok. Aby wyświetlić wyniki pośrednie, ustaw parametr showResult na true.

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ą z czasem ukończenia oraz obraz warunkowy, jeśli został podany jako dane wejściowe.

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

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

Wejścia:

  • Prompt: „kolorowy kreskówkowy szop pracz w szerokim kapeluszu trzymający kij i chodzący po lesie, animacja, widok z poziomu trzech czwartych, obraz”
  • Seed: 312687592
  • Powtórzeń: 20

Wygenerowany obraz: