При разработке мобильного приложения для видеозвонков клиенты часто сталкиваются с проблемой: стандартная реализация виртуального фона через сервер даёт задержки и артефакты. На одном проекте заказчик использовал облачный AI от AWS Rekognition — каждый кадр уходил в облако, возвращался через 60–80 мс. В результате контур флуктуировал, пользователи жаловались на качество.
Мы решили её, перенеся сегментацию на устройство. Серверная обработка добавляет 40–80 мс на каждый кадр, что при 30 fps приводит к заметному разрыву контура и «призраку» при быстрых движениях. On-device сегментация укладывается в 8–28 мс, экономя до 80% времени по сравнению с облачным инференсом. Ключевое преимущество — сегментация на устройстве, а не в облаке. Это не только снижает затраты на инфраструктуру, но и обеспечивает конфиденциальность пользовательских данных. На каждом кадре видеопотока нейросеть выделяет силуэт человека, применяет фон (изображение, видео или размытие) и возвращает результат в пайплайн энкодера — всё без передачи данных на сервер. Типичный бюджет времени — 33 мс на кадр, и on-device решение легко в него укладывается. Для бюджетных устройств мы используем лёгкие модели, понижаем частоту кадров до 24 fps — это позволяет добиться стабильной работы без перегрева.
Почему on-device AI-виртуальный фон быстрее?
Задача — выделить силуэт человека на каждом кадре видеопотока (30 fps), применить фон и вернуть результат в пайплайн до энкодирования. Это означает бюджет ~33 мс на кадр включая захват, инференс модели, постобработку и рендеринг.
Серверный вариант: захват → отправка → инференс → ответ → рендеринг. Даже при идеальной сети roundtrip добавляет 40–80 мс. На практике — рывки контура, «призрак» при движении.
На устройстве: захват → инференс → рендеринг. Всё в одном пайплайне. Стоимость инфраструктуры при серверном подходе высока — нужны GPU-сервера. On-device подход полностью устраняет эти затраты. Экономия на серверных GPU-вычислениях может достигать $2000 в месяц для приложения с 10 000 активных пользователей. На другом проекте экономия составила $3000 в месяц за счёт отказа от дорогостоящих GPU-инстансов.
Принцип работы on-device сегментации
Мы используем нейросети, оптимизированные для мобильных чипов (Neural Engine, GPU, DSP). Инференс выполняется локально, никакие данные не покидают устройство — это одновременно решает вопросы конфиденциальности и задержки.
iOS: MLKit + CoreImage или Vision
На iOS используем Vision фреймворк с моделью VNGeneratePersonSegmentationRequest. Apple добавила её в iOS 15 и новее — работает на Neural Engine без явной загрузки модели. Точность хорошая для фронтальной камеры, но начинает давать рваный контур при сложных причёсках и прозрачных элементах одежды.
// Настройка сегментации
let request = VNGeneratePersonSegmentationRequest()
request.qualityLevel = .balanced // .accurate даёт лучший контур, но тяжелее
request.outputPixelFormat = kCVPixelFormatType_OneComponent8
// В обработчике кадров AVFoundation
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:])
try handler.perform([request])
guard let mask = request.results?.first?.pixelBuffer else { return }
// mask — CVPixelBuffer 8-bit, применяем через CIBlendWithMask
CIBlendWithMask с CIContext(options: [.workingColorSpace: NSNull()]) — рендерим в Metal, избегая конвертации цветового пространства. Без этого каждый кадр добавляет ~5 мс только на конвертацию.
Для более качественной сегментации — конвертируем TFLite модель DeepLab v3 или MediaPipe SelfieSegmentation в Core ML через coremltools и загружаем через MLModel. MediaPipe даёт стабильный контур даже при размытых краях. Apple Vision VNGeneratePersonSegmentationRequest
Android: MLKit Selfie Segmentation
val segmenter = Segmentation.getClient(
SelfieSegmenterOptions.Builder()
.setDetectorMode(SelfieSegmenterOptions.STREAM_MODE) // оптимизировано для видео
.enableRawSizeMask()
.build()
)
// В обработчике CameraX ImageAnalysis
override fun analyze(imageProxy: ImageProxy) {
val inputImage = InputImage.fromMediaImage(imageProxy.image!!, imageProxy.imageInfo.rotationDegrees)
segmenter.process(inputImage)
.addOnSuccessListener { segmentationMask ->
val mask = segmentationMask.buffer
// Применяем фон через RenderScript или Vulkan compute shader
applyBackground(mask, imageProxy)
}
.addOnCompleteListener { imageProxy.close() }
}
STREAM_MODE критичен — он держит внутренний стейт между кадрами и работает быстрее SINGLE_IMAGE_MODE. На Pixel 6 с Tensor G2 инференс занимает 8–12 мс. На бюджетных устройствах (Snapdragon 695) — 20–28 мс. Для постобработки маски — RenderScript (deprecated в API 31+) или Vulkan compute shader через RenderEffect на Android 12+. MLKit Selfie Segmentation
Сравнение моделей сегментации
| Модель | Платформа | Задержка (мс) | Качество контура |
|---|---|---|---|
| Vision (Apple) | iOS | 12–20 | Хорошее |
| MLKit Selfie Segmentation | Android | 8–12 | Отличное |
| MediaPipe | Кроссплатформа | 15–25 | Среднее |
| Core ML (DeepLab) | iOS | 20–30 | Высокое |
Сравнение подходов: серверный vs on-device
| Параметр | Серверная сегментация | On-device сегментация |
|---|---|---|
| Задержка | 150–300 мс (roundtrip) | 8–28 мс (инференс) |
| Зависимость от сети | Критическая | Отсутствует |
| Конфиденциальность | Данные уходят на сервер | Данные остаются на устройстве |
| Точность | Высокая (большая модель) | Хорошая (оптимизированные модели) |
| Стоимость инфраструктуры | Высокая (GPU-сервера) | Нулевая (только ПО) |
Применение фона: три варианта
Статичное изображение — простейший случай. CIBlendWithMask на iOS, PorterDuff compositing на Android.
Размытие (blur) — фильтр CIGaussianBlur с radius 12–20 применяется к исходному кадру, затем маска выбирает между оригиналом и размытым. На Android — RenderEffect.createBlurEffect (API 31+) или собственный blur через Vulkan.
Видеофон — нужен декодер, синхронизированный с таймингом видеозвонка. На iOS — AVPlayerItemVideoOutput + Metal текстура. Тяжело по памяти: буфер видеофона + буфер камеры + буфер маски + результат. На iPhone 12 с 4 GB это ок, на iPhone SE 2nd gen (3 GB) нужен aggressive buffer reuse.
Интеграция в WebRTC-пайплайн
Большинство мобильных решений для звонков строятся на WebRTC — через LiveKit, Daily.co, Agora или нативный WebRTC. Все они предоставляют механизм кастомного VideoSource/VideoProcessor для подмены кадров до энкодирования.
В LiveKit SDK для iOS это VideoProcessor протокол:
class BackgroundReplacementProcessor: VideoProcessor {
func process(frame: RTCVideoFrame) -> RTCVideoFrame? {
// Сегментация + применение фона
// Возвращаем новый RTCVideoFrame с обработанным буфером
}
}
room.localParticipant?.videoTracks.first?.processor = BackgroundReplacementProcessor()
Важно: RTCVideoFrame работает в CVPixelBuffer с форматом kCVPixelFormatType_420YpCbCr8BiPlanarFullRange. Конвертация в RGB для ML-инференса и обратно — это потери. Если модель принимает YUV — оставляем формат нетронутым.
Критерии выбора модели сегментации
Выбор модели зависит от целевых устройств и требований к качеству. Для iOS с A12+ подходит Vision — встроенная модель, не требует дополнительных ресурсов. Для Android с Tensor G2 или Snapdragon 8 Gen 1 — MLKit даёт лучшее качество. На слабых устройствах (Snapdragon 695, A11) используем MediaPipe или понижение fps.
Оптимизация для слабых устройств
На устройствах с ограниченными ресурсами мы снижаем частоту кадров до 24 fps и используем лёгкие модели (MediaPipe). Также применяем динамическое масштабирование входного кадра: уменьшаем разрешение до 480p перед инференсом, затем upscale маски. Это сокращает время обработки на 30-40% без заметной потери качества.
Какие результаты вы получите?
После завершения проекта вы получаете полностью интегрированную функцию замены фона, протестированную на 20+ реальных устройствах. В состав deliverables входят:
- Исходный код модуля сегментации и обработки фона.
- Подробная техническая документация по интеграции и кастомизации.
- Обучение вашей команды работе с кодом и конфигурациями.
- Месяц поддержки после запуска для исправления возможных багов.
- Рекомендации по оптимизации для новых версий ОС.
Сколько времени занимает интеграция?
- Аудит текущего WebRTC-стека и пайплайна кадров.
- Выбор модели сегментации под качество/скорость (Vision, MLKit, Core ML, MediaPipe).
- Разработка прототипа с замером производительности на 10+ устройствах.
- Интеграция в существующий WebRTC-пайплайн через VideoProcessor.
- Оптимизация постобработки маски (antialiasing, feathering).
- Тестирование на граничных условиях (сложный фон, быстрые движения).
- Документация и обучение команды заказчика.
Ориентиры по срокам
Базовая реализация с размытием фона (одна платформа) — 2–3 недели. Полная реализация с поддержкой статичных изображений и видеофонов, двух платформ, интеграция в существующий WebRTC-стек — 5–8 недель.
Мы имеем 8+ лет опыта в мобильной разработке, выполнили 50+ проектов с видео- и AI-функциями. Гарантируем стабильную работу на устройствах старше пяти лет.
Свяжитесь с нами для оценки вашего проекта. Получите консультацию инженера.







