Przewodnik po generowaniu obrazów w przypadku Androida

Zadanie Generatora obrazów MediaPipe umożliwia generowanie obrazów na podstawie promptu tekstowego. W tym zadaniu używany jest model „tekst na obraz” do generowania obrazów przy użyciu technik dyfuzji.

Zadanie akceptuje jako dane wejściowe prompt tekstowy oraz opcjonalny obraz warunku, który model może uzupełnić i wykorzystać jako punkt odniesienia przy generowaniu. Generator obrazów może też generować obrazy na podstawie konkretnych koncepcji przekazanych modelowi podczas trenowania lub ponownego trenowania. Więcej informacji znajdziesz w artykule na temat dostosowywania 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 sekcji Omówienie.

Przykładowy kod

Przykładowy kod MediaPipe Tasks to podstawowa implementacja aplikacji Generator obrazów na Androida. Możesz użyć aplikacji jako punktu wyjścia dla własnej aplikacji na Androida lub odwołać się do niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod generatora obrazów jest hostowany na GitHub.

Pobieranie kodu

Z instrukcji poniżej 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 tak, aby używała rozproszonego procesu płatności, aby mieć tylko pliki z przykładową aplikacją Generator obrazów:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_generator/android
    

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

Kluczowe elementy

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

  • ImageGenerationHelper.kt: inicjuje zadanie i obsługuje generowanie obrazu.
  • DiffusionActivity.kt generuje obrazy, gdy wtyczki i wagi LoRA nie są włączone.
  • PluginActivity.kt: implementuje modele wtyczek, które umożliwiają użytkownikom podawanie obrazu warunku jako danych wejściowych.
  • LoRAWeightActivity.kt: uzyskuje dostęp do wag LoRA i obsługuje te wagi, które służą do dostosowywania modeli podstawowych i umożliwia im generowanie obrazów przedstawiających konkretne koncepcje.

Konfiguracja

W tej sekcji znajdziesz najważniejsze czynności, jakie musisz wykonać, aby skonfigurować środowisko programistyczne i projekty kodu związane z generatorem obrazów. Ogólne informacje o konfigurowaniu środowiska programistycznego na potrzeby zadań MediaPipe, w tym o wymaganiach dotyczących 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 (API 31) lub nowszym dodaj natywną zależność biblioteki OpenCL do AndroidManifest.xml. Więcej informacji znajdziesz w dokumentacji tagu uses-native-library.

Niektóre urządzenia z Androidem mogą wymagać dodatkowych bibliotek:

<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 generatora obrazów MediaPipe wymaga wytrenowanego modelu podstawowego, który jest zgodny z tym zadaniem. Po pobraniu modelu zainstaluj wymagane zależności i przekonwertuj model na odpowiedni format. Następnie wypchnij przekonwertowany model na urządzenie z Androidem.

Więcej informacji o dostępnych wytrenowanych modelach generatora obrazów znajdziesz w sekcji poświęconej modelom w omówieniu zadań.

Pobierz model podstawowy

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>

Przekaż przekonwertowany model 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 chcesz używać modelu wtyczki, sprawdź, czy trzeba go pobrać. W przypadku wtyczek wymagających dodatkowego modelu modele wtyczek muszą być połączone w pakiet APK lub pobierane na żądanie. Modele wtyczek są niewielkie (około 23 MB) i można je połączyć bezpośrednio w plik APK. Zalecamy jednak pobieranie modeli wtyczek na żądanie.

Jeśli dostosowałeś model przy użyciu LoRA, pobierz go na żądanie. Więcej informacji znajdziesz w artykule o modelu wtyczki dotyczącym wag LoRA.

Tworzenie zadania

Generator obrazów MediaPipe konfiguruje to zadanie za pomocą funkcji createFromOptions(). 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 aplikacji na Androida:

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

To zadanie obsługuje też modele wtyczek, które pozwalają użytkownikom umieszczać w danych wejściowych dotyczących zadania obrazy warunków, które model podstawowy może uzupełniać i wykorzystywać jako odniesienia do generowania. Takimi obrazami mogą być punkty orientacyjne twarzy, kontury krawędzi i oszacowania głębi, których model używa jako dodatkowego kontekstu i informacji do generowania obrazów.

Podczas dodawania modelu wtyczki do modelu podstawowego skonfiguruj również opcje wtyczek. Wtyczka punktów orientacyjnych twarzy Face korzysta z faceConditionOptions, wtyczka Canny Edge – edgeConditionOptions, a wtyczka Depth – depthConditionOptions.

Opcje Canny Edge

Skonfiguruj te opcje w edgeConditionOptions.

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

Więcej informacji o działaniu tych opcji konfiguracji znajdziesz w artykule na temat detektorów brzegowych Canny’ego.

Opcje punktu orientacyjnego

Skonfiguruj te opcje w faceConditionOptions.

Nazwa opcji Opis Zakres wartości Wartość domyślna
minFaceDetectionConfidence Minimalny stopień pewności, że wykrywanie twarzy zostanie uznane za udane. Float [0.0,1.0] 0.5
minFacePresenceConfidence Minimalny wskaźnik ufności wykrywania obecności twarzy w przypadku wykrywania punktów orientacyjnych twarzy. Float [0.0,1.0] 0.5
faceModelBaseOptions Obiekt BaseOptions wyznaczający ścieżkę modelu tworzącego obraz warunku. BaseOptions obiekt N/A
FacePluginModelBaseOptions Obiekt BaseOptions, który ustawia ścieżkę modelu wtyczki. BaseOptions obiekt N/A

Więcej informacji o działaniu tych opcji konfiguracyjnych znajdziesz w artykule o zadaniu Oznaczenie twarzy.

Opcje głębokości

Skonfiguruj te opcje w depthConditionOptions.

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

Utwórz tylko z użyciem 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 opcje podstawowe modelu wtyczki za pomocą elementu 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)
    

Utwórz z użyciem 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 (wymagana): łączna liczba iteracji wygenerowania obrazu. Dobry punkt wyjścia to 20.
  • seed (wymagany): losowy materiał użyty podczas generowania obrazu.
  • stan obrazu (opcjonalny): obraz, którego model używa jako odniesienia do generowania. Ma zastosowanie tylko w przypadku korzystania z modelu wtyczki.
  • condition type (typ warunku) (opcjonalnie): typ modelu wtyczki używany w zadaniu. Ma zastosowanie tylko w przypadku korzystania z modelu wtyczki.

Dane wejściowe tylko 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, i parametru sourceConditionImage, by 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 warunku. MPImage obiekt

Jeśli używasz modelu wtyczki, utwórz obraz stanu za pomocą obiektu createConditionImage:

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, ziarnem 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 jest w prompcie tekstowym, jeśli chcesz wygenerować obraz z konkretnym pojęciem reprezentowanym przez wagi.

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

Uruchamianie zadania

Aby wygenerować obraz za pomocą danych wejściowych z poprzedniej sekcji, użyj metody generate(). Powstanie jeden wygenerowany obraz.

Generowanie tylko z użyciem 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
}

Wygeneruj za pomocą wag LoRA

Proces generowania obrazów za pomocą modelu dostosowanego za pomocą wag LoRA jest podobny do procesu ze standardowym modelem podstawowym. Sprawdź, czy 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ż generować wygenerowane obrazy pośrednie podczas każdej iteracji, zgodnie z definicją w parametrze wejściowym iterations. Aby wyświetlić wyniki pośrednie, wywołaj metodę setInputs, a następnie 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 wartość ImageGeneratorResult, która zawiera wygenerowany obraz, sygnaturę czasową czasu ukończenia i obraz warunkowy, jeśli został on przesłany jako dane wejściowe.

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

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

Dane wejściowe:

  • Prompt: „kolorowy kreskówkowy szop pracz w luźnym kapeluszu z szerokim rondem trzymający kij idący przez las, animowany widok 3/4, obraz”
  • Początek: 312687592
  • Iterations: 20

Wygenerowany obraz: