1. Введение
Что такое MediaPipe?
MediaPipe Solutions позволяет применять решения на основе машинного обучения (ML) к вашим приложениям. Он предоставляет фреймворк для настройки предварительно созданных конвейеров обработки, которые обеспечивают немедленный, привлекательный и полезный результат для пользователей. Вы даже можете настроить многие из этих решений с помощью MediaPipe Model Maker , чтобы обновить модели по умолчанию.
Преобразование текста в изображение — одна из нескольких задач машинного обучения, которые предлагает MediaPipe Solutions.
В этом практическом занятии вы начнете с практически пустого Android-приложения, а затем пройдете несколько этапов, пока не сможете генерировать новые изображения непосредственно на своем Android-устройстве.
Что вы узнаете
- Как реализовать генерацию текста в изображение, работающую локально в Android-приложении с использованием задач MediaPipe .
Что вам понадобится
- Установленная версия Android Studio (данный практический пример был написан и протестирован с использованием Android Studio Giraffe).
- Устройство Android с объемом оперативной памяти не менее 8 ГБ.
- Базовые знания в области разработки под Android и умение запускать готовые скрипты на Python.
2. Добавьте задачи MediaPipe в приложение для Android.
Скачайте стартовое приложение для Android.
Этот практический урок начнётся с готового примера пользовательского интерфейса, который будет использоваться для базовой версии генерации изображений. Вы можете найти это базовое приложение в официальном репозитории MediaPipe Samples здесь . Клонируйте репозиторий или скачайте ZIP-архив, нажав Code > Download ZIP.
Импортируйте приложение в Android Studio.
- Откройте Android Studio.
- На экране «Добро пожаловать в Android Studio» выберите «Открыть» в правом верхнем углу.

- Перейдите в папку, куда вы клонировали или скачали репозиторий, и откройте каталог codelabs/image_generation_basic/android/start .
- На данном этапе приложение не должно компилироваться, поскольку вы еще не добавили зависимость MediaPipe Tasks.
Чтобы исправить приложение и запустить его, перейдите в файл build.gradle и прокрутите вниз до раздела // Шаг 1 - Добавить зависимость. Затем добавьте следующую строку и нажмите кнопку «Синхронизировать сейчас» , которая появится в баннере вверху Android Studio.
// Step 1 - Add dependency
implementation 'com.google.mediapipe:tasks-vision-image-generator:latest.release'
После завершения синхронизации убедитесь, что все открылось и установилось правильно, нажав на зеленую стрелку запуска .
) в правом верхнем углу Android Studio. Вы должны увидеть, как приложение откроется на экране с двумя переключателями и кнопкой с надписью INITIALIZE . Если вы нажмете на эту кнопку, вы сразу перейдете к отдельному интерфейсу, состоящему из текстового поля и других параметров, а также кнопки с надписью GENERATE .


К сожалению, на этом возможности стартового приложения практически заканчиваются, поэтому пришло время узнать, как его доработать и начать создавать новые изображения на своем устройстве!
3. Настройка генератора изображений
В этом примере большая часть работы по генерации изображений будет выполняться в файле ImageGenerationHelper.kt . Открыв этот файл, вы заметите в верхней части класса переменную с именем imageGenerator. Это объект Task, который будет выполнять основную работу в вашем приложении для генерации изображений.
Чуть ниже этого объекта вы увидите функцию с именем initializeImageGenerator() со следующим комментарием: // Шаг 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
Важно понимать, что эта задача выполняется синхронно , поэтому вам потребуется вызвать функцию из фонового потока. Подробнее об этом вы узнаете чуть позже в этом практическом занятии.
Последний шаг, который вы выполните в этом файле, — это заполнение функции execute() (обозначенной как Шаг 5). Она будет принимать параметр, указывающий, должна ли она возвращать промежуточное изображение или нет для единственного шага генерации, который будет выполнен с помощью функции execute() 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/"
Далее прокрутите вниз до функции generateImage(). В нижней части этой функции вы увидите Шаг 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 немного сложнее. Поскольку функция execute() выполняет только один шаг вместо всех шагов генерации изображения, вам потребуется вызывать каждый шаг по отдельности в цикле. Вам также нужно будет определить, следует ли отображать текущий шаг для пользователя. Наконец, вы обновите состояние пользовательского интерфейса, если необходимо отобразить текущую итерацию. Все это вы можете сделать сейчас.
// 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!