Реализация сегментации изображений в мобильном приложении
Сегментация — самая вычислительно дорогая из задач компьютерного зрения на мобиле. Если детекция возвращает прямоугольник, сегментация возвращает маску попиксельно. На изображении 512×512 это 262 144 пикселя, каждый с классом — и всё это нужно обработать и отрисовать за 33 ms для 30 FPS.
Семантическая vs инстанс-сегментация: что выбрать
Семантическая сегментация — каждый пиксель получает один класс (небо, человек, дорога). Все люди в кадре — один класс «person». Модели: DeepLabV3+, MobileNetV3 Segmentation. TFLite-версия DeepLabV3+ с входом 257×257 работает за 22–35 ms на современных Android.
Инстанс-сегментация — каждый экземпляр объекта имеет отдельную маску. Три человека = три маски. Модели: Mask R-CNN, YOLOv8-seg. Значительно тяжелее: YOLOv8n-seg на TFLite — 80–120 ms на мобиле. Реальное real-time с такой моделью — только на флагманах с GPU-делегатом.
Для большинства потребительских кейсов (удаление фона, размытие фона на фото) достаточно семантической сегментации класса «person» или «background». Это закрывается ML Kit Selfie Segmentation — on-device, 30 FPS, отдельная нейронка обученная именно под этот кейс.
Наложение маски в реальном времени
Маска сегментации — это ByteArray или FloatArray с индексами классов. Наложить её на видеопоток за 33 ms — задача для GPU.
На iOS используем Metal для блендинга: маска конвертируется в CIImage через CIFilter.pixellate или кастомный Metal kernel, затем накладывается на оригинальный кадр через CIBlendWithMask. Весь рендеринг в Metal избегает копирования данных между CPU и GPU через MTLBuffer с shared storage mode.
На Android — RenderScript (deprecated API 31+) или Vulkan/OpenGL ES через SurfaceView. Для новых проектов: AGSL (Android Graphics Shading Language) начиная с Android 13, или Canvas.drawBitmap с Paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN) для простых случаев.
Частая ошибка: генерировать Bitmap из маски на CPU в цикле для каждого кадра. На Pixel 6 это ~18 ms только для аллокации + copy — убивает все 33 ms бюджета. Правильно: использовать Bitmap.copyPixelsFromBuffer с заранее аллоцированным ByteBuffer или передавать маску напрямую в шейдер.
ML Kit Selfie Segmentation на практике
Самый быстрый путь для «размытия фона» в видеозвонках или фоторедакторах:
val segmenter = Segmentation.getClient(
SelfieSegmenterOptions.Builder()
.setDetectorMode(SelfieSegmenterOptions.STREAM_MODE)
.enableRawSizeMask()
.build()
)
STREAM_MODE оптимизирован для видео — кэширует состояние между кадрами. enableRawSizeMask() возвращает маску в реальном разрешении, а не downsampled — нужно для качественного краевого сглаживания.
Кейс: корпоративное приложение для видеопрезентаций, виртуальный фон на iOS. Core Image CIBlendWithMask + ML Kit Selfie Segmentation (iOS SDK): 28 ms на iPhone 13 mini при 720p. На iPhone SE 2nd gen — 41 ms, что при 30 FPS приводило к dropped frames каждые 2–3 секунды. Решение: снизили разрешение обработки до 540p, маску upscale через билинейную интерполяцию — 24 ms, dropped frames исчезли.
Сроки
Интеграция ML Kit Selfie Segmentation с наложением эффекта — 5–7 дней. Кастомная сегментационная модель с рендерингом через Metal/OpenGL на реальном видеопотоке — 2–3 недели. Стоимость рассчитывается индивидуально.







