On-device ИИ в браузере: фоторедактор, который не отправляет снимок на сервер

Три рабочих модели для удаления фона и объектов с фото: загрузка на чужой сервер, generative fill с облачным GPU и полностью клиентский стек в браузере. Автор APIC-Web проверяет третий путь: Canvas, WebAssembly и on-device ML без upload. Для соло-разработчика, который собирает ML-интерфейс и не хочет тащить пользовательские снимки на сервер, этот разбор показывает, где заканчивается «магия нейросети» и начинается инженерия масок и текстур.
Три модели: upload, diffusion в облаке, inference на устройстве
Типичный онлайн-сервис удаления фона или объектов устроен одинаково: вы загружаете изображение, модель крутится на сервере, результат скачивается обратно. Фото уже покинуло устройство. Это не метафора, а архитектурный выбор.
Generative «умный ластик» уровня Photoshop Generative Fill или Galaxy AI object eraser опирается на diffusion-модели, обученные на больших датасетах. Автор прямо ставит границу: такое нельзя бесплатно отдать в статической HTML-странице без сервера и без бюджета на GPU-инференс.
Третий путь — эксперимент «насколько далеко можно зайти, оставаясь client-side-only». APIC-Web заявляет, что всё остаётся на стороне клиента: удаление фона, удаление объектов, фильтры, конвертация форматов и сжатие. Демо доступно бесплатно; технический разбор в посте сосредоточен на двух самых сложных частях: сегментации и object removal.
On-device inference здесь не лозунг про приватность, а ограничение стека. Браузер даёт Canvas, WASM и нативные ML-модели; всё остальное приходится собирать из классических алгоритмов.
On-device сегментация: почему жёсткая маска ломает волосы
Для удаления фона используется MediaPipe ImageSegmenter. У модели два принципиально разных режима вывода:
outputCategoryMask: true— жёсткая маска 0/1 по пикселям, края «лесенкой»;outputConfidenceMasks: true— float 0–1 на пиксель до порога, с неопределённостью на границе.
Жёсткая category mask не спасается постфактум blur'ом: мягкие края волос и плеч уже потеряны на этапе бинаризации. Confidence masks плюс постобработка дают заметно лучший край на той же модели, без смены весов, только за счёт пайплайна.
Постобработка выглядит так:
- smoothstep-контраст по маске;
- эрозия примерно на 1 px;
- separable box blur для feather.
Отдельный инженерный урок: число каналов confidence masks зависит от конкретной segmentation model. Нельзя хардкодить confidenceMasks[1]. Разные модели отдают background/foreground или единую foreground-probability.
При инициализации модели закладывается fallback: если GPU delegate не поднимается, переключение на CPU. Для любого client-side ML UI это обязательный сценарий, а не edge case на чужих машинах.
Удаление объектов без diffusion: exemplar fill вместо «магии»
Второй сложный блок — object removal. Здесь не используется generative/diffusion подход. Вместо этого — exemplar-based texture synthesis, content-aware fill «до эры генеративных моделей».
Алгоритм в общих чертах:
- Дыра в изображении режется на блоки 8×8.
- Заполнение идёт от границы внутрь: первым обрабатывается блок с максимумом уже известных соседей.
- Для каждого блока ищется патч в окрестности по SSD; копируются реальные пиксели текстуры, а не усреднение, иначе smear.
Сложность — O(размер_дыры × площадь_поиска). Оптимизации: padded bounding box вокруг маски, adaptive stride по размеру дыры. При ограниченной search area типичное заполнение укладывается well under a second — единственная количественная оценка скорости в материале, без сравнения с облачными сервисами.
Качество автор оценивает как «decent» для кожи, неба, ткани, стен, но это не замена generative fill.
Подводный камень, который легко пропустить при сборке UI: после background removal прозрачные пиксели (alpha = 0) могут хранить «мусорный» RGB. Наивная проверка is painted? ломает patch search. Решение — раздельные массивы isPainted и validSrc для прозрачных областей.
Паттерн: прозрачный пиксель ≠ «не закрашен»
validSrc отслеживает пригодность источника текстуры отдельно
Что переносится в соло-workflow с локальным inference
Материал не про IDE-ассистентов: в первоисточнике нет упоминаний агентов или vibe-coding workflow. Зато четыре приёма из разбора применимы к любому браузерному ML-интерфейсу, который вы собираете без облачного upload:
| Приём | Зачем |
|---|---|
| Confidence masks вместо жёсткой бинаризации | Сохранить мягкие края без смены модели |
| GPU → CPU fallback при инициализации | Не падать на машинах без рабочего delegate |
| Не хардкодить индексы масок модели | Разные segmentation models отдают разное число каналов |
| Разделять painted и valid source | Прозрачность после BG removal ломает наивный patch search |
WebGPU и Core ML в посте не названы, только GPU delegate у MediaPipe. Расширять стек за пределы источника не стоит.
Фильтры, конвертация форматов и сжатие в APIC-Web перечислены как часть «полного редактора», но без технического разбора в посте. Если вам нужен именно этот контур, смотрите демо и исходники по ссылке ниже.
Источники
- I built a full image editor that never uploads your photo — here's how the on-device AI parts actually work — автор @akhourianmolkumar, Dev.to, 24 августа 2026
- APIC-Web — демо — client-side image editor, доступ проверен 24 августа 2026