1. Введение
Что такое МедиаПайп?
MediaPipe Solutions позволяет применять решения машинного обучения (ML) к вашим приложениям. Он предоставляет основу для настройки предварительно созданных конвейеров обработки, которые обеспечивают немедленный, привлекательный и полезный вывод для пользователей. Вы даже можете настроить многие из этих решений с помощью MediaPipe Model Maker для обновления моделей по умолчанию.
Генерация текста в изображение — одна из нескольких задач машинного обучения, которые может предложить MediaPipe Solutions.
В этой Codelab вы начнете с практически чистого приложения для Android, а затем пройдете несколько этапов, пока не сможете создавать новые изображения непосредственно на своем устройстве Android.
Что вы узнаете
- Как реализовать генерацию текста в изображение, выполняемую локально в приложении Android с помощью MediaPipe Tasks .
Что вам понадобится
- Установленная версия Android Studio (эта кодовая лаборатория была написана и протестирована с помощью Android Studio Giraffe).
- Устройство Android с объемом оперативной памяти не менее 8 ГБ.
- Базовые знания разработки под Android и умение запускать готовый скрипт Python.
2. Добавьте задачи MediaPipe в приложение Android.
Загрузите стартовое приложение для Android
Эта лаборатория кода начнется с готового образца пользовательского интерфейса, который будет использоваться для базовой версии создания изображений. Вы можете найти это стартовое приложение в официальном репозитории MediaPipe Samples здесь . Клонируйте репозиторий или загрузите zip-файл, нажав «Код» > «Загрузить ZIP».
Импортируйте приложение в Android Studio.
- Откройте Android-студию.
- На экране «Добро пожаловать в Android Studio» выберите «Открыть» в правом верхнем углу.
- Перейдите туда, где вы клонировали или загрузили репозиторий, и откройте каталог codelabs/image_generation_basic/android/start .
- На этом этапе приложение не должно компилироваться, поскольку вы еще не включили зависимость задач MediaPipe.
Вы исправите приложение и запустите его, зайдя в файл build.gradle и прокрутив вниз до // Шаг 1 — Добавление зависимости. Оттуда добавьте следующую строку, а затем нажмите кнопку «Синхронизировать сейчас» , которая появляется на баннере в верхней части Android Studio.
// Step 1 - Add dependency
implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'
После завершения синхронизации убедитесь, что все открылось и установлено правильно, нажав зеленую стрелку запуска ( ) в правом верхнем углу Android Studio. Вы должны увидеть открытое приложение на экране с двумя переключателями и кнопкой с надписью INITIALIZE . Если вы нажмете на эту кнопку, вы сразу же попадете в отдельный пользовательский интерфейс, состоящий из текстового приглашения и других параметров рядом с кнопкой с надписью СОЗДАТЬ .
К сожалению, это все, что касается стартового приложения, поэтому пришло время узнать, как завершить работу над этим приложением и начать создавать новые изображения на своем устройстве!
3. Настройка генератора изображений
В этом примере большая часть работы по созданию изображения будет выполняться в файле ImageGenerationHelper.kt . Открыв этот файл, вы заметите переменную в верхней части класса под названием imageGenerator. Это объект Task, который будет выполнять тяжелую работу в вашем приложении для создания изображений.
Чуть ниже этого объекта вы увидите функцию инициализацииImageGenerator() со следующим комментарием: // Шаг 2 — инициализация генератора изображений. Как вы могли догадаться, именно здесь вы будете инициализировать объект ImageGenerator . Замените тело этой функции следующим кодом, чтобы задать путь к модели создания изображения и инициализировать объект ImageGenerator :
// Step 2 - initialize the image generator
val options = ImageGeneratorOptions.builder()
.setImageGeneratorModelDirectory(modelPath)
.build()
imageGenerator = ImageGenerator.createFromOptions(context, options)
Ниже вы увидите еще одну функцию с именем setInput(). Он принимает три параметра: строку приглашения , которая будет использоваться для определения сгенерированного изображения, количество итераций , которые Задача должна пройти при создании нового изображения, и начальное значение, которое можно использовать для создания новых версий изображения на основе в том же приглашении при создании того же изображения, когда используется одно и то же начальное значение. Цель этой функции — установить эти начальные параметры для генератора изображений, когда вы пытаетесь создать изображение, которое отображает промежуточные шаги.
Идите дальше и замените тело 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
Важно знать, что эта задача выполняется синхронно , поэтому вам нужно будет вызвать функцию из фонового потока. Вы узнаете больше об этом чуть позже в этой лаборатории кода.
Последний шаг, который вы сделаете в этом файле, — это заполнение функции выполнения() (помеченной как Шаг 5). Он примет параметр, который сообщает, должен ли он возвращать промежуточное изображение или нет для одного шага генерации, который будет выполняться с помощью функции выполнения() ImageGenerator . Замените тело функции следующим кодом:
// 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 будет обрабатывать состояния пользовательского интерфейса и другую логику, связанную с этим примером приложения. Идите и откройте его сейчас.
В верхней части файла вы должны увидеть комментарий // Шаг 6 — установите путь к модели. Здесь вы сообщите своему приложению, где оно может найти файлы моделей, необходимые для создания изображений. В этом примере вы установите значение /data/local/tmp/image_generator/bins/.
// Step 6 - set model path
private val MODEL_PATH = "/data/local/tmp/image_generator/bins/"
Оттуда прокрутите вниз до функцииgenerageImage(). В нижней части этой функции вы увидите шаг 7 и шаг 8, которые будут использоваться для создания изображений с возвращаемыми итерациями или без них соответственно. Поскольку обе эти операции выполняются синхронно , вы заметите, что они заключены в сопрограмму. Вы можете начать с замены // Шаг 7 — Генерация без показа итераций этим блоком кода для вызова методаgenerate() из файла ImageGenerationHelper , а затем обновить состояние пользовательского интерфейса.
// Step 7 - Generate without showing iterations
val result = helper?.generate(prompt, iteration, seed)
_uiState.update {
it.copy(outputBitmap = result)
}
Шаг 8 становится немного сложнее. Поскольку функция выполнения() выполняет только один шаг вместо всех шагов создания изображения, вам придется вызывать каждый шаг индивидуально в цикле. Вам также необходимо будет определить, должен ли текущий шаг отображаться для пользователя. Наконец, вы обновите состояние пользовательского интерфейса, если текущая итерация должна отображаться. Вы можете сделать все это сейчас.
// 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 Storage для загрузки необходимых файлов непосредственно на устройство пользователя во время выполнения.
5. Разверните и протестируйте приложение.
После всего этого у вас должно быть работающее приложение, которое может принимать текстовые запросы и генерировать новые изображения полностью на устройстве! Разверните приложение на физическом устройстве Android, чтобы протестировать его, но помните, что вам нужно будет попробовать это на устройстве с объемом памяти не менее 8 ГБ.
- Нажмите «Выполнить» (
) на панели инструментов Android Studio, чтобы запустить приложение.
- Выберите тип шагов генерации (окончательный или с итерациями) и нажмите кнопку ИНИЦИАЛИЗИРОВАТЬ .
- На следующем экране установите любые свойства, которые вы хотите, и нажмите кнопку СОЗДАТЬ, чтобы увидеть, что выдаст инструмент.
6. Поздравляем!
Вы сделали это! В этой лабораторной работе вы узнали, как добавить генерацию текста в изображение на устройстве в приложение Android.
Следующие шаги
С задачей создания изображения вы можете сделать больше, в том числе
- используйте базовое изображение для структурирования сгенерированных изображений с помощью плагинов или тренируйте свои собственные дополнительные веса LoRA с помощью Vertex AI.
- Используйте Firebase Storage для получения файлов моделей на вашем устройстве без использования инструмента ADB.
Мы с нетерпением ждем возможности увидеть все интересные вещи, которые вы сделаете с помощью этой экспериментальной задачи, и следите за новыми разработками и контентом от команды MediaPipe!