Содержание статьи +
- TL;DR
- Почему Это Важно
- Что Такое «Размытие Фона» – Пиксели, Не Магия
- Модель MediaPipe Selfie Segmentation – Цифры, Которые Имеют Значение
- Почему WebGPU Меняет Арифметику
- Полный Пайплайн – От getUserMedia До WebRTC
- Кросс-Браузерная Реальность – Лестница Детекции Возможностей
- Численный Пример – Бюджет Кадра На 30 Fps Вебкамере
- Три Ошибки, Которые Мы Видим В Продакшене
- Build Versus Buy – Когда MediaPipe – Неверный Выбор
- Где Тут Фора Софт
- Ключевые Выводы
- Что Читать Дальше
TL;DR
ИИ-размытие фона – эффект, который скрывает комнату за вами на видеозвонке, размывая каждый пиксель, не относящийся к телу – стало базовым ожиданием для любого веб-видео-продукта. На 2026 год самый дешёвый, быстрый и архитектурно защитимый способ доставить его в браузер – это MediaPipe Image Segmenter с моделью selfie-сегментации на бэкенде WebGPU, скомпонованный через WebRTC Insertable Streams. Весь пайплайн весит около 450 KB модели плюс 200 KB WebAssembly-рантайма, работает на 30–60 кадрах в секунду на ноутбуке среднего класса, не требует сервера и аккуратно деградирует на WebGL в браузерах без WebGPU. Сложности – не в модели: они в рендер-пайплайне, в разрыве между Chrome и Safari, в дрожании краёв на плечах, которое уничтожает доверие пользователя, и в том, что посредственный статически-глубинный блюр Google Meet задал неверное ожидание. В этой статье разобраны модель, WebGPU-компоновщик, интеграция с WebRTC, лестница кросс-браузерных фолбэков и три ошибки, которые мы продолжаем видеть в продакшене.
Почему Это Важно
Если ваш продукт – это инструмент видеоконференций, приложение для телемедицины, асинхронный видеомессенджер, платформа для онлайн-репетиторства или что угодно, что выводит вебкамеру на экран, ваши пользователи ожидают, что они смогут размыть комнату за собой. Они ожидают, что это будет работать без установки софта, без потери частоты кадров, бесплатно и без того, чтобы звонок выглядел как телеведущий перед зелёным экраном с пушистым ореолом вокруг волос. Компании, которые делают это плохо – а некоторые крупные делают – теряют пользователей в пользу тех, кто делает хорошо. Пайплайн, описанный здесь, – это та же архитектура, что используется в Google Meet, в Zoom Web SDK, в виджетах комнат 100ms, Daily и LiveKit, и в каждом white-label-инструменте конференций, который мы построили с 2024 года. Эта статья предполагает, что вы прочитали урок 2.1 по предобработке для CV и урок 2.4 по SAM 2, потому что размытие фона – частный случай семантической сегментации, а примитивы из этих уроков лежат в основе любого эффекта, который мы сейчас опишем. К концу вы сможете специфицировать пайплайн, выбрать правильный backend рендеринга, спланировать кросс-браузерный фолбэк и избежать четырёх ошибок, на которые приходится почти каждая жалоба на качество блюра в продакшене.
Что Такое «Размытие Фона» – Пиксели, Не Магия
Эффект, который все зовут размытием фона, – это двухстадийный пайплайн обработки изображения. Первая стадия – семантическая сегментация: для каждого пикселя входного кадра небольшая нейросеть выдаёт вероятность от 0 до 1 того, что этот пиксель принадлежит человеку, а не комнате. Вторая стадия – компоновка: используя эту маску вероятностей, рендерер смешивает резкий оригинальный кадр (для пикселей человека) с гауссиано-размытой копией того же кадра (для пикселей комнаты). Результат выглядит как глубина резкости реальной камеры, но никакой камеры не было – размытие программное, глубина выведена нейросетью, а граница между резким и размытым диктуется маской 256×256 пикселей в градациях серого.
Полезная аналогия – ротоскопирование в традиционной анимации. Маска – это та же идея, что и художник, вырезающий силуэт из листа бумаги и накладывающий его на другой фон. Нейросеть – художник; всё остальное в пайплайне – это акт наложения силуэта на размытую копию комнаты. Модель – единственный «умный» компонент; всё остальное – это инфраструктура.
Современным эффект ощущается из-за модели. Пять лет назад сегментация человека от фона в реальном времени требовала либо камеры с глубиной (Microsoft Kinect, iPhone TrueDepth), либо серверного GPU. Мобильные архитектуры уровня смартфона, появившиеся между 2019 и 2022 годами – MobileNetV3 и её производные – сделали возможным запуск сегментации в реальном времени на том же CPU, который декодирует ваш вебкам-поток. Модель, используемая MediaPipe selfie segmentation, и в ML Kit, и в варианте блюра Google Meet, – одна из таких мобильных архитектур.
Модель MediaPipe Selfie Segmentation – Цифры, Которые Имеют Значение
MediaPipe selfie-сегментер – это бинарная сеть семантической сегментации с 106 000 параметров и размером файла 447 KB во float32, падающим до примерно 230 KB после INT8-квантизации. Архитектура – кастомный бэкбон MobileNetV3, модифицированный энкодер-декодерной структурой в стиле U-Net: бэкбон порождает многомасштабные признаки, которые апсемплируются и комбинируются в одноканальный выход той же высоты и ширины, что и вход. В model card описаны два варианта: general – принимает RGB-вход 256×256 и выдаёт маску 256×256, и landscape – принимает 144×256 и выдаёт маску 144×256. У landscape-модели примерно треть FLOPs от general-модели, и она работает пропорционально быстрее; именно этот вариант лежит за блюром фона в Google Meet.
Латентность, измеренная Google на Pixel 6 с GPU-бэкендом, – около 2 миллисекунд на кадр для general-модели и около 1 миллисекунды на кадр для landscape-модели. На современном ноутбучном CPU (Apple M2, Intel Core i7 12-го поколения) с бэкендом WebAssembly SIMD из пакета @mediapipe/tasks-vision та же модель работает 5–10 миллисекунд на кадр – достаточно быстро для 30 fps вебкамеры с запасом бюджета на стадию компоновки. На WebGPU-бэкенде модель работает 1–3 миллисекунды на кадр на том же железе, оставляя около 30 миллисекунд из 33 мс бюджета кадра на всё остальное.
Модель выдаёт 6-классовый выход (фон, волосы, кожа тела, кожа лица, одежда, прочее) в полной форме, но для размытия фона нам важна только одна ось: человек против не-человека. Большинство production-пайплайнов сворачивают 6-классовый выход в бинарную маску одним шагом softmax argmax, либо просто складывают пять каналов «человека» и сравнивают сумму с порогом.
У модели две известные слабости, и каждое production-развёртывание вынуждено их обходить. Первая: граница не острее, чем позволяет разрешение в 256 пикселей. Маска для потока с вебкамеры 1080p апсемплируется примерно в 4× по каждому измерению, и наивный билинейный апсемпл даёт мягкий край, который выглядит нормально на щеке, но плохо на отдельных прядях волос. Вторая: модель обучалась на одиночных людях, на съёмке «голова-плечи», в помещении, на consumer-расстоянии до камеры; она плохо обобщается на несколько людей, на экстремальные крупные планы, на back-lit-сюжеты и на широкоугольную съёмку с большого расстояния. Обе слабости устранимы, и фиксы мы разбираем ниже.
Почему WebGPU Меняет Арифметику
Раньше модель работала на WebGL. Она и сейчас может – и на 2026 год WebGL остаётся правильным бэкендом для пользователей Safari 17 и старше, для версий Firefox старше релизов с WebGPU 2025 года, и для примерно 8% пользователей Chrome в мире, чьё железо занесено в WebGPU-блоклист. WebGL работает потому, что сеть сегментации – стек свёрток, а fragment-шейдер можно заставить умножать матрицы, кодируя тензоры как текстуры и трактуя каждый draw call как dispatch вычисления. Это тот же тип обхода, что строила команда TensorFlow.js и что был в оригинальном веб-порте MediaPipe – и работает он от «достаточно быстро» до «больно» в зависимости от драйвера и GPU.
WebGPU был задуман для general compute, не для графики. Compute-шейдер имеет прямой доступ к буферам, разделяемую workgroup-память и явную синхронизацию; он может диспатчить workgroup 16×16×1 потоков на произвольный тензор, ни разу не притворяясь треугольным пайплайном. Практический эффект на сети selfie-сегментации – ускорение в 3–5 раз над WebGL на том же железе и снижение оверхеда GPU-трансферов памяти на 30–40%. Вендорские бенчмарки из обзора WebGPU 2026 на Sitepoint (Google, NVIDIA, Intel) показывают, что для ИИ-инференса в целом WebGPU даёт ускорение 15–30× над WebGL на трансформерных архитектурах – selfie-сегментация на нижнем краю этого диапазона, потому что это чисто-CNN-модель с маленькими активациями, но прирост всё равно существенный.
Вторая причина важности WebGPU – поддержка браузерами. Chrome и Edge включили WebGPU по умолчанию на десктопе в мае 2023 (версия 113) и на Android в 2024 (версия 121). Firefox 141, вышедший в середине 2025, включил его по умолчанию на Windows. Safari 18, релиз конца 2024, включил его по умолчанию на macOS, iPadOS и iOS. На май 2026 от 92% до 96% глобальных пользователей Chrome, 100% пользователей свежих Safari и большинство пользователей свежих Firefox имеют WebGPU. Этого достаточно, чтобы сделать WebGPU основным бэкендом, а WebGL – фолбэком, и именно эта инверсия мотивировала переписывание пайплайна.
Полный Пайплайн – От getUserMedia До WebRTC
Production-размытие фона – это не один вызов API. Это четырёхстадийный пайплайн, который начинается на камере и заканчивается на WebRTC peer connection.
Стадия 1 – захват. Вызов navigator.mediaDevices.getUserMedia() возвращает MediaStream с одним видео-MediaStreamTrack. Этот трек – источник для всех нижестоящих стадий. Для входа 720p при 30 fps кадры приходят как объекты VideoFrame 1280×720 через WebCodecs API.
Стадия 2 – инференс. Каждый кадр передаётся в MediaPipe Image Segmenter методом segmentForVideo(videoFrame, timestamp), который даунсемплирует вход до 256×256, прогоняет модель на WebGPU-бэкенде и возвращает объект MPMask. Маска по умолчанию на WebGPU – GPU-текстура, она не должна возвращаться в CPU-память, и в этом половина причины, почему пайплайн быстрый.
Стадия 3 – компоновка. WebGPU fragment-шейдер берёт три входа: оригинальный кадр 1280×720, его гауссиано-размытую копию в том же разрешении и маску 256×256. Для каждого выходного пикселя шейдер сэмплирует маску (с билинейной фильтрацией), использует её значение как вес смешивания резкого и размытого кадров и пишет результат на offscreen-canvas. Сам гауссиан-блюр – это два раздельных прохода (горизонтальный, потом вертикальный) одномерного 21-tap-ядра с сигмой под визуальный эффект продукта: сигма 8 для медленного Zoom-подобного блюра, сигма 16 для тяжёлого блюра, сигма 4 для эффекта «едва заметного» профессионального вида.
Стадия 4 – кодирование. Offscreen-canvas заворачивается в MediaStreamTrackGenerator (Chrome) или VideoTrackGenerator (Safari, Firefox через спецификационный API), который выдаёт MediaStreamTrack, выглядящий для WebRTC как обычный камера-трек. Этот трек добавляется в RTCPeerConnection через pc.addTrack(processedTrack, processedStream), и с точки зрения получателя разницы между размытым и неразмытым отправителем нет.
Машинерия Insertable Streams – это часть, которая склеивает стадии 2–4. MediaStreamTrackProcessor читает камера-трек как ReadableStream из VideoFrame; вы трансформируете эти кадры через стадии 2 и 3; и пишете результат в VideoTrackGenerator, чтобы получить WritableStream из VideoFrame обратно. Преобразование происходит полностью off-main-thread внутри Worker, что держит UI отзывчивым даже на 4-летнем ноутбуке.
// Скелет — внутри Worker, бэкенд WebGPU.
import { ImageSegmenter, FilesetResolver } from "@mediapipe/tasks-vision";
const vision = await FilesetResolver.forVisionTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/wasm",
);
const segmenter = await ImageSegmenter.createFromOptions(vision, {
baseOptions: {
modelAssetPath: "selfie_segmenter.tflite",
delegate: "GPU", // WebGPU в Chrome/Edge/Firefox/Safari
},
runningMode: "VIDEO",
outputCategoryMask: true,
outputConfidenceMasks: false,
});
const processor = new MediaStreamTrackProcessor({ track: cameraTrack });
const generator = new VideoTrackGenerator();
const reader = processor.readable.getReader();
const writer = generator.writable.getWriter();
while (true) {
const { value: frame, done } = await reader.read();
if (done) break;
const mask = segmenter.segmentForVideo(frame, performance.now()).categoryMask;
const composited = compositorRun(frame, mask, blurSigma); // WebGPU shader
await writer.write(composited);
frame.close();
mask.close();
}Полная реализация – примерно 350 строк TypeScript включая WebGPU-шейдер. Мы держим open-source-референс в GitHub-организации Фора Софт и поставляем этот же паттерн по умолчанию в наших обёртках клиента LiveKit и 100ms.
Кросс-Браузерная Реальность – Лестница Детекции Возможностей
Insertable Streams ещё не равномерно поддержанный API. Chrome и Edge поставляют пре-спек версии Google MediaStreamTrackProcessor и MediaStreamTrackGenerator в main-thread и в воркерах, для аудио- и видео-треков. Safari 18 Tech Preview и Firefox 141+ поставляют W3C-стандартные варианты – MediaStreamTrackProcessor и VideoTrackGenerator – но только внутри воркера и только для видео-треков. Стандартный вариант – то, к чему в итоге выровняется Chrome, а пре-спек-вариант всё ещё самый широко развёрнутый.
Правильный инженерный ответ – лестница детекции возможностей, выбирающая лучший доступный пайплайн в рантайме, а не жёсткая проверка версии браузера. Лестница выглядит так, сверху вниз:
| Уровень | Проверка возможностей | Пайплайн |
|---|---|---|
| 1 | WebGPU + Insertable Streams + Worker | WebGPU model + WebGPU composer + Worker – 1–3 мс модель, 30+ fps |
| 2 | WebGL + Insertable Streams + Worker | WebGL model + WebGL composer + Worker – 4–8 мс модель, 30 fps |
| 3 | WebGPU + canvas.captureStream() | WebGPU model + canvas re-capture – 30 fps, +16 мс латентности |
| 4 | WebAssembly CPU + canvas.captureStream() | WASM SIMD model + 2D canvas blur – 15 fps приемлемо, без GPU |
| 5 | Ничего | Отключить фичу, показать toast «ваш браузер не поддерживает» |
Почему лестница важна: попадание на уровень 4 для пользователя Safari 17 на десктопе даёт визуально худший результат, чем уровень 1 на пользователе Chrome на том же железе, и пользователи уровня 4 сообщат об этом как о баге. Мы научились показывать активный уровень пользователю в маленькой ненавязчивой подсказке UI – «размытие фона использует ваш CPU, качество может быть снижено» – потому что пользователи, понимающие компромисс, заводят меньше тикетов поддержки, чем те, кто не понимает.
Распространённая ошибка продакшена – выбрать уровень 1 без проверки, что GPU пользователя не в WebGPU-блоклисте Chrome. Около 8% десктопных пользователей Chrome имеют WebGPU как API, но он отключён в рантайме блоклистом (обычно более старые Intel HD Graphics на Windows). Детекция возможностей означает проверку, что запрос WebGPU-адаптера действительно успешен, а не просто что navigator.gpu определён.
Численный Пример – Бюджет Кадра На 30 Fps Вебкамере
Поток 30 fps даёт вам 33.33 миллисекунды на кадр, чтобы сделать всё: прочитать кадр, даунсемплировать, прогнать модель, апсемплировать маску, размыть кадр, скомпоновать и передать обратно в WebRTC. Что угодно, что выходит за бюджет, либо роняет кадры, либо добавляет латентность – пользователь замечает и то, и другое.
Рабочий пример на MacBook Pro M2 с Chrome 138 и входом с вебкамеры 1280×720. Модель работает на WebGPU и показывает медианное время инференса 1.5 мс на минутной записи. Даунсемпл с 1280×720 до 256×256 – 0.3 мс (один GPU draw). Гауссиан-блюр, два раздельных прохода сигмой 8 – 1.8 мс суммарно. Composite-шейдер – 0.4 мс. Шаг WebCodecs кодирования обратно в VideoFrame – около 0.6 мс. Итого: 4.6 мс на кадр. Composite браузера и WebRTC-кодировщик добавляют ещё ~5 мс, прежде чем кадр покинет машину, и в бюджете остаётся 23 мс запаса.
На 6-летнем ноутбуке с Intel Core i5 без дискретного GPU тот же пайплайн работает на WebGL уровень 2: 7 мс инференс, 1 мс даунсемпл, 4 мс блюр, 1 мс composite, 1 мс кодирование – 14 мс суммарно. Всё ещё в бюджете. На Safari 17 на том же железе срабатывает уровень 4: 18 мс модель на WASM SIMD CPU, 6 мс блюр на 2D canvas, 2 мс composite – 26 мс суммарно, почти без запаса и с заметно мягким краем маски.
Вывод: WebGPU-пайплайн не просто быстрее; это единственный пайплайн, оставляющий достаточно запаса, чтобы компоновщик сделал чистую работу. Уровень 4 работает, но визуальное качество ощутимо ниже.
Три Ошибки, Которые Мы Видим В Продакшене
Это три провальных режима, в которые мы наступали в поле и которые теперь проверяем в каждом code review до того, как фича размытия фона уезжает в релиз.
Первая ошибка – ореол на мягком крае. Маска 256×256, наивно билинейно апсемплированная до 1280×720, даёт полосу 3–4 пикселя вокруг силуэта, где значение маски лежит где-то между 0 и 1. В этой полосе компоновщик смешивает резкие и размытые пиксели, и результат читается как светлый ореол на тёмном фоне или тёмный ореол на светлом. Фикс – двухшаговый постпроцессинг самой маски: маленький гауссиан-блюр сигмой 2 (убирает ступенчатые артефакты), затем крутой sigmoid-remap, толкающий средние значения маски к 0 или 1 (mask = 1 / (1 + exp(-12 * (mask - 0.5)))). Оба шага живут в WebGPU-compositor-шейдере; они ничего не стоят в бюджете. Результат – однопиксельная переходная полоса, читающаяся как естественная глубина резкости, а не как флюоресцентный контур.
Вторая ошибка – дрожание волос. Модель обучалась на разрешении 256×256, и граница «волосы-фон» на этом разрешении – порядка одного пикселя. От кадра к кадру модель выдаёт чуть разные граничные маски даже на идеально статичных кадрах – результат читается как «мерцание» волос, когда пользователь сидит спокойно. Фикс – временное сглаживание: держим маленький ring buffer масок последних 3 кадров и выдаём среднее. Трёх кадров достаточно, чтобы убрать высокочастотное мерцание; больше пяти кадров вводит заметную задержку при движении. Стоимость – одна дополнительная сэмплировка текстуры на выходной пиксель на буферизованный кадр; на WebGPU это невидимо в бюджете.
Третья ошибка – сцены с несколькими людьми. Переговорная с двумя людьми рядом перед одной камерой показывает, что модель относит обоих к пикселям «человека» – нет instance-сегментации, нет разделения «человек слева» и «человек справа». Для размытия фона это обычно нормально – пользователи хотят оба лица резкими. Но как только продукт требует one-person сегментации (beauty-фильтр, применяющийся только к пользователю; аватар, заменяющий только одно лицо), правильный ответ – не чинить MediaPipe, а апгрейдить на SAM 2 (урок 2.4) с лицом пользователя как промптом. MediaPipe – для границы комната против людей; SAM 2 – для границы этот конкретный человек против всех остальных. Использование неправильного инструмента под неправильную задачу – самая частая архитектурная ошибка, которую мы видим в этой области.
Build Versus Buy – Когда MediaPipe – Неверный Выбор
Для большинства веб-видео-продуктов MediaPipe Image Segmenter на WebGPU – правильный примитив. Он бесплатен, имеет пермиссивную лицензию (Apache 2.0), работает полностью на устройстве пользователя (что означает нулевую облачную стоимость на пользователя и нулевой PHI / GDPR-data-exfiltration), и качество достаточно высокое, чтобы средний пользователь не отличил его от Zoom или Meet. Мы используем его по умолчанию в нашей стандартной референс-архитектуре веб-конференций.
Есть три ситуации, когда покупка коммерческого SDK (Krisp, NVIDIA Maxine, Banuba, Persona, расширение agora.io background-blur) имеет больше смысла, чем построение на MediaPipe.
Первая – когда вам также нужны real-time-шумоподавление, voice activity detection и ИИ-эхокомпенсация в том же продукте, и вы хотите одного вендора на их поддержку. Krisp поставляет размытие фона как часть того же SDK, что и шумоподавляющую модель; интеграционная экономия инженерного времени окупается, даже если качество фичи сопоставимо с MediaPipe.
Вторая – когда вам нужен hardware-accelerated-эффект в нативном десктопном приложении, а не в браузере. NVIDIA Maxine работает на RTX GPU пользователя через CUDA и даёт выше качества на поддерживаемом железе – но требует RTX-класс GPU, что отрезает длинный хвост ноутбуков и Mac. Для Windows-only-enterprise-десктоп-продукта, ориентированного на свежее RTX-железо, Maxine – легитимный выбор. Для кросс-платформенного веб-продукта – нет.
Третья – когда нужен подписанный, аудированный, AVA-сертифицированный блюр фона в регулируемом продукте (здравоохранение, оборонка, финансы). Коммерческие вендоры продают SOC 2-отчёты, HIPAA BAAs, EU AI Act conformance documents и индемнификацию по поведению модели. MediaPipe – Apache-лицензированный код; история аудита на вас. Для телемедицинского продукта, где вы согласуете контракты с закупками госпиталя, BAA от коммерческого вендора иногда стоит per-user-fee.
Для всего остального – а это подавляющее большинство продуктов – MediaPipe на WebGPU в 2026 – правильный ответ. Кросс-ссылка на урок 6.6 по build-vs-buy Krisp / Maxine / Dolby – там более детальный разбор по каждому вендору.
Где Тут Фора Софт
Фора Софт поставляет размытие фона как часть WebRTC-конференц-продуктов с 2021 года и поддерживает описанный в этой статье WebGPU-компоновщик как переиспользуемый компонент по всем проектам видеоконференций, телемедицины, e-learning и AR/VR. Мы выкатывали этот же пайплайн за whitelabel-конференц-инструментами для европейских телехелс-платформ (где on-device-обработка удовлетворяет GDPR-требованиям локальности данных), для онлайн-репетиторских продуктов для детей (где в фоне комнаты могут быть другие члены семьи, которых надо размыть), и для OTT post-production-флоу, где редакторы просматривают сырые интервью и хотят чистый превью без аренды студии. Если вы строите что-то из этого, build-паттерн один и тот же; разница – в вертикализации остальной части продукта.
Ключевые Выводы
- MediaPipe Image Segmenter на WebGPU – дефолт 2026 для браузерного размытия фона.
- Сама модель крошечная (447 KB, 106K параметров); инженерная работа – в WebGPU-компоновщике.
- WebGPU в 3–5× быстрее WebGL на том же железе и доступен большинству пользователей.
- Лестница детекции возможностей обязательна – Safari 17, blocklisted-Chrome, древние браузеры – всем нужен фолбэк.
- Три ошибки – ореол, мерцание волос, multi-person – имеют известные фиксы; либо отгружайте, либо ждите тикетов поддержки.
- Для большинства веб-продуктов MediaPipe выигрывает по цене, лицензии, латентности и приватности; коммерческие SDK – по bundling и аудиту.
Что Читать Дальше
- Multi-object tracking – DeepSORT, ByteTrack, OC-SORT – когда блюра недостаточно и надо следить за конкретными людьми между кадрами.
- Как размыть фон в Zoom, Teams, на iPhone – инженерный deep-dive – продуктовый взгляд на тот же пайплайн за брендированными интерфейсами.
- SAM 2 для видео – memory module, propagation, rotoscoping/ROI – более тяжёлый сегментер, на который вы переходите, когда качество границ MediaPipe недостаточно.