1. Wprowadzenie
Czym jest MediaPipe?
MediaPipe Solutions umożliwia stosowanie w aplikacjach rozwiązań wykorzystujących systemy uczące się. Udostępnia ona ramy do konfigurowania gotowych przepływów przetwarzania, które dostarczają użytkownikom natychmiastowych, atrakcyjnych i przydatnych danych wyjściowych. Możesz nawet dostosować wiele z tych rozwiązań za pomocą MediaPipe Model Maker, aby zaktualizować modele domyślne.
Generowanie tekstu na obraz jest jednym z kilku zadań ML, które oferuje MediaPipe Solutions.
W tym ćwiczeniu Codelab zaczniesz od prawie pustej aplikacji na Androida, a potem będziesz wykonywać kolejne czynności, aż będziesz w stanie generować nowe obrazy bezpośrednio na urządzeniu z Androidem.
Czego się nauczysz
- Jak zaimplementować generowanie tekstu na obraz lokalnie w aplikacji na Androida za pomocą MediaPipe Tasks.
Czego potrzebujesz
- Zainstalowana wersja Android Studio (ten warsztat został napisany i przetestowany za pomocą Android Studio Giraffe).
- Urządzenie z Androidem i co najmniej 8 GB pamięci RAM.
- podstawowa wiedza o programowaniu na Androida i umiejętność uruchamiania wcześniej napisanego skryptu Pythona;
2. Dodawanie zadań MediaPipe do aplikacji na Androida
Pobierz aplikację startową na Androida
To ćwiczenie w Codelab rozpocznie się od gotowego przykładu interfejsu użytkownika, który będzie używany w podstawowej wersji generowania obrazów. Tę aplikację startową znajdziesz w oficjalnym repozytorium przykładów MediaPipe tutaj. Skopiuj repozytorium lub pobierz plik zip, klikając Kod > Pobierz plik ZIP.
Zaimportuj aplikację do Android Studio
- Otwórz Android Studio.
- Na ekranie Witamy w Android Studio w prawym górnym rogu kliknij Otwórz.
- Przejdź do folderu, do którego skopiowano lub sklonowano repozytorium, i otwórz katalog codelabs/image_generation_basic/android/start.
- Na tym etapie aplikacja nie powinna się kompilować, ponieważ nie uwzględniono jeszcze zależności od MediaPipe Tasks.
Aby naprawić aplikację i uruchomić ją, otwórz plik build.gradle i przewiń w dół do sekcji // Krok 1. Dodaj zależność. Następnie dodaj ten wiersz i kliknij przycisk Synchronizuj teraz, który pojawi się na banerze u góry Androida Studio.
// Step 1 - Add dependency
implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'
Po zakończeniu synchronizacji sprawdź, czy wszystko zostało otwarte i zainstalowane prawidłowo. Aby to zrobić, w prawym górnym rogu Android Studio kliknij zieloną strzałkę uruchom ( ). Aplikacja powinna otworzyć się na ekranie z 2 przyciskami opcji i przyciskiem INITIALIZE (Inicjalizuj). Po kliknięciu tego przycisku powinieneś/powinnaś zostać przekierowany/a na osobny interfejs, który zawiera prompt tekstowy i inne opcje oraz przycisk GENERYTUJ.
To już wszystko, co dotyczy aplikacji startowej. Czas dowiedzieć się, jak ją dokończyć i rozpocząć generowanie nowych obrazów na urządzeniu.
3. Konfigurowanie generatora obrazów
W tym przykładzie większość pracy związanej z generowaniem obrazów będzie wykonywana w pliku ImageGenerationHelper.kt. Po otwarciu tego pliku zobaczysz u góry klasy zmienną o nazwie imageGenerator. To obiekt zadania, który wykona najcięższą pracę w aplikacji do generowania obrazów.
Tuż pod tym obiektem zobaczysz funkcję o nazwie initializeImageGenerator() z tym komentarzem: // Krok 2. Zainicjuj generator obrazów. Jak się zapewne domyślasz, tutaj zainicjujesz obiekt ImageGenerator. Zastąp ciało tej funkcji poniższym kodem, aby ustawić ścieżkę do modelu generowania obrazów i inicjializować obiekt ImageGenerator:
// Step 2 - initialize the image generator
val options = ImageGeneratorOptions.builder()
.setImageGeneratorModelDirectory(modelPath)
.build()
imageGenerator = ImageGenerator.createFromOptions(context, options)
Poniżej zobaczysz kolejną funkcję o nazwie setInput(). Przyjmuje ona 3 parametry: ciąg znaków prompt, który służy do definiowania wygenerowanego obrazu, liczbę iteracji, które zadanie ma wykonać podczas generowania nowego obrazu, oraz wartość seed, która może służyć do tworzenia nowych wersji obrazu na podstawie tego samego prompta, generując ten sam obraz, gdy używana jest ta sama wartość ziarna. Ta funkcja ma na celu ustawienie tych początkowych parametrów dla generatora obrazów, gdy próbujesz utworzyć obraz, który wyświetla etapy pośrednie.
Zastąp ciało funkcji setInput() (gdzie zobaczysz komentarz // Krok 3. Przyjmij dane wejściowe) tym wierszem:
// Step 3 - accept inputs
imageGenerator.setInputs(prompt, iteration, seed)
Na kolejnych 2 etapach odbywa się generowanie. Funkcja generate() przyjmuje te same dane wejściowe co setInput, ale tworzy obraz jako jednorazowy wywołanie, które nie zwraca żadnych obrazów pośrednich. Treść tej funkcji (w tym komentarz // Krok 4. Generuj bez wyświetlania iteracji) możesz zastąpić tym:
// Step 4 - generate without showing iterations
val result = imageGenerator.generate(prompt, iteration, seed)
val bitmap = BitmapExtractor.extract(result?.generatedImage())
return bitmap
Pamiętaj, że to zadanie jest wykonywane synchronicznie, więc musisz wywołać funkcję z wątku w tle. Więcej informacji na ten temat znajdziesz w późniejszej części tego Codelab.
Ostatnim krokiem w tym pliku jest wypełnienie funkcji execute() (oznaczonej jako Krok 5). Funkcja ta przyjmuje parametr określający, czy ma zwrócić obraz pośredni w pojedynczym kroku generowania, który zostanie wykonany za pomocą funkcji ImageGenerator execute(). Zastąp ciało funkcji tym kodem:
// 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
To wszystko na temat pliku pomocniczego. W następnej sekcji wypełnisz plik ViewModel, który obsługuje logikę w tym przykładzie.
4. Łączenie aplikacji
Plik MainViewModel będzie obsługiwać stany interfejsu użytkownika i inną logikę związaną z tą przykładową aplikacją. Otwórz go teraz.
U góry pliku powinien pojawić się komentarz // Krok 6. Ustaw ścieżkę modelu. Tutaj podajesz aplikacji, gdzie może znaleźć pliki modelu, które są niezbędne do generowania obrazów. W tym przykładzie ustawisz wartość na /data/local/tmp/image_generator/bins/.
// Step 6 - set model path
private val MODEL_PATH = "/data/local/tmp/image_generator/bins/"
Przewiń w dół do funkcji generateImage(). U dołu tej funkcji zobaczysz kroki 7 i 8, które będą używane do generowania obrazów z poszczególnymi iteracjami lub bez nich. Obie te operacje są wykonywane synchronicznie, więc są zawijane w korowinę. Zacznij od zastąpienia bloku kodu // Krok 7. Generuj bez wyświetlania iteracji wywołaniem funkcji generate() z pliku ImageGenerationHelper, a potem zaktualizuj stan interfejsu.
// Step 7 - Generate without showing iterations
val result = helper?.generate(prompt, iteration, seed)
_uiState.update {
it.copy(outputBitmap = result)
}
Krok 8 jest nieco trudniejszy. Funkcja execute() wykonuje tylko jeden krok, a nie wszystkie kroki potrzebne do wygenerowania obrazu, dlatego musisz wywoływać każdy krok osobno za pomocą pętli. Musisz też określić, czy użytkownikowi ma być wyświetlany bieżący krok. Na koniec zaktualizuj stan interfejsu, jeśli chcesz wyświetlić bieżącą iterację. Możesz to zrobić już teraz.
// 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)",
)
}
}
}
W tym momencie powinieneś zainstalować aplikację, zainicjować generator obrazów, a potem utworzyć nowy obraz na podstawie promptu tekstowego.
... z tym, że teraz aplikacja ulega awarii podczas próby zainicjowania generatora obrazów. Dzieje się tak, ponieważ musisz skopiować pliki modelu na urządzenie. Aby uzyskać aktualne informacje o modelach innych firm, które działają z MediaPipe, przekonwertować je na potrzeby tego zadania i skopiować na urządzenie, zapoznaj się z tą sekcją oficjalnej dokumentacji.
Oprócz kopiowania plików bezpośrednio na urządzenie programistyczne możesz też skonfigurować usługę Firebase Storage tak, aby pobieranie niezbędnych plików odbywało się bezpośrednio na urządzenie użytkownika w czasie wykonywania.
5. Wdrażanie i testowanie aplikacji
Po wykonaniu wszystkich tych czynności powinna powstać aplikacja, która może przyjmować prompt tekstowy i generować nowe obrazy całkowicie na urządzeniu. Wdróż aplikację na fizycznym urządzeniu z Androidem, aby ją przetestować. Pamiętaj, że musi to być urządzenie z co najmniej 8 GB pamięci.
- Aby uruchomić aplikację, na pasku narzędzi Android Studio kliknij Uruchom (
).
- Wybierz typ kroków generowania (ostateczne lub z iteracjami), a potem naciśnij przycisk INITIALZACJA.
- Na następnym ekranie ustaw dowolne właściwości i kliknij przycisk GENERATE (Generuj), aby zobaczyć, co narzędzie wygeneruje.
6. Gratulacje!
Udało się! Z tego ćwiczenia z programowania dowiesz się, jak dodać do aplikacji na Androida generowanie obrazu na podstawie tekstu na urządzeniu.
Dalsze kroki
Możesz też wykonać inne czynności związane z zadaniem generowania obrazów, w tym:
- za pomocą obrazu podstawowego strukturyzować wygenerowane obrazy za pomocą wtyczek lub wytrenować własne dodatkowe wagi LoRA za pomocą Vertex AI.
- Użyj usługi Firebase Storage, aby pobrać pliki modelu na urządzenie bez konieczności korzystania z narzędzi ADB.
Z niecierpliwością czekamy na wszystkie fajne rzeczy, które stworzysz dzięki temu eksperymentalnemu zadaniu. Zwróć uwagę na jeszcze więcej laboratoriów i treści od zespołu MediaPipe.