Посмотреть как Markdown

Удаление фона

Удаление фона отделяет объект от всего, что находится за ним. В LibreYOLO это задача matte: она возвращает мягкое значение альфы на каждый пиксель, а не жёсткую маску переднего плана.

Определение

Задача matte предсказывает по одному значению альфы на пиксель из одного RGB-изображения: 1 — полностью передний план, 0 — полностью фон. Значение непрерывное, а не бинарное, и в этом весь смысл задачи. До жёсткой маски отсюда один шаг — порог 0.5, а мягкое матте дополнительно несёт частичное покрытие на волосах, шерсти и смазанных движением краях, которое бинарная маска выбрасывает.

Предсказание заполняет result.matte — объект Matte с массивом (H, W) float32 в [0, 1] на холсте исходного изображения, доступным как NumPy через .array. result.cutout() объединяет исходное изображение с этой альфой в массив RGBA (H, W, 4) uint8, а result.save(path) записывает то же самое в PNG с прозрачным фоном. result.boxes остаётся пустым, поэтому conf, iou и max_det ни на что не влияют.

Модели

За matte отвечают два семейства, и прямой проход у них общий.

BiRefNet — сеть с билатеральной привязкой, вокруг которой построена задача; здесь она опубликована одним чекпойнтом уровня Swin-L.

FeyNobg — углублённый вариант от Feyn Inc.: архитектура BiRefNet, у которой третья стадия Swin выросла с 18 до 24 блоков, после чего модель переобучили. LibreYOLO переиспользует для него прямой проход, предобработку и однологитный выход BiRefNet, поэтому предсказание, валидация и работа с чекпойнтами ведут себя одинаково; веса и принадлежность к семейству у FeyNobg свои.

Лицензии на веса у них разные. Обе указаны на страницах моделей, а решающей считается лицензия в репозитории Hugging Face конкретного чекпойнта.

Предсказание

Веса скачиваются с Hugging Face при первом запуске и кэшируются локально.

Предсказание матте
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreBiRefNetl-matte.pt")result = model(SAMPLE_IMAGE) matte = result.matteprint(matte.array.shape, matte.array.dtype)   # (H, W) float32 в [0, 1]
Запись прозрачного PNG
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreBiRefNetl-matte.pt")result = model(SAMPLE_IMAGE) # save() совмещает исходное изображение с матте как альфа-каналом.result.save("subject.png") rgba = result.cutout()   # тот же массив (H, W, 4) uint8 в памятиprint(rgba.shape)
Наложение на новый фон
import numpy as npfrom libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreBiRefNetl-matte.pt")result = model(SAMPLE_IMAGE) rgba = result.cutout()alpha = rgba[..., 3:4].astype(np.float32) / 255.0backdrop = np.full_like(rgba[..., :3], 255)          # белыйcomposited = (rgba[..., :3] * alpha + backdrop * (1 - alpha)).astype(np.uint8)print(composited.shape)

Оба семейства работают на фиксированном родном холсте 1024x1024 и масштабируют матте обратно под исходное изображение. Другое разрешение не поддерживается: таблицы относительных позиций в бэкбоне Swin привязаны к этому размеру, и при несовпадении ошибки не будет — они просто плохо интерполируются. Results.save() определён только для матте-результатов, и ему нужно исходное изображение: если не передать его явно, метод перечитает изображение по Results.path. Об источниках, стриминге и обработке результатов — в разделе предсказание.

Формат датасета

При валидации матте каждому RGB-изображению сопоставляется одноканальное эталонное альфа-матте (ground truth) с тем же именем без расширения, где 0 — фон, а 255 — передний план.

my-matte-dataset/
  images/
    subject.jpg
  mattes/
    subject.png

Достаточно передать этот корень как data=: каталог с матте определяется автоматически среди mattes/, matte/, gt/, masks/, mask/ и alpha/. Альтернатива — YAML-файл датасета: path задаёт корень, а val_images и val_mattes — каталоги относительно него:

yaml
path: my-matte-dataset
val_images: images
val_mattes: mattes
nc: 1
names: {0: matte}

nc и names — заглушки схемы; матте-модель возвращает Results.matte, а не детекции. Значения матте читаются как альфа в [0, 1] делением на 255, а матте, форма которого отличается от холста предсказания, билинейно масштабируется под него. Полный контракт — в разделе форматы датасетов.

Обучение

Ни у одного из матте-семейств нет реализации обучения: train() в обоих случаях выбрасывает NotImplementedError, а поддержка матте покрывает только предсказание, валидацию и экспорт. На странице каждой модели указан исходный проект, в котором есть код обучения, и скрипт конвертации, который переносит чекпойнт обратно.

Валидация

val() вызывает собственный predict модели, поэтому валидация использует ровно ту предобработку, что и семейство, а обе метрики считаются на холсте исходного изображения.

Валидация и чтение ключей метрик
from libreyolo import LibreYOLO model = LibreYOLO("LibreBiRefNetl-matte.pt") # Вместо YAML-файла датасета подойдёт каталог, в котором лежат images/ и# каталог с матте.metrics = model.val(data="my-matte-dataset/") print(metrics["metrics/MAE"])        # меньше — лучшеprint(metrics["metrics/Smeasure"])   # fitness, больше — лучше

metrics/MAE — средняя абсолютная ошибка относительно эталонной альфы, в [0, 1], и меньше — лучше. metrics/Smeasure — S-measure из работы Fan et al. (ICCV 2017), структурное сходство, которое учитывает, насколько верно переданы форма объекта и отверстия в нём, чего попиксельное усреднение само по себе не видит; больше — лучше. S-measure заодно служит значением fitness — числом, по которому выбирается лучший чекпойнт. Ни одна из метрик не зависит от разрешения.

Экспорт

Экспортированная матте-модель загружается обратно через LibreYOLO() по суффиксу файла, поэтому артефакт ведёт себя как чекпойнт и возвращает те же Results.

Экспорт
from libreyolo import LibreYOLO model = LibreYOLO("LibreBiRefNetl-matte.pt")model.export(format="torchscript")
Запуск экспортированного файла
from libreyolo import LibreYOLO, SAMPLE_IMAGE # Фабрика выбирает загрузчик по суффиксу файла, поэтому экспортированный# артефакт загружается как обычный чекпойнт и возвращает тот же Results.model = LibreYOLO("LibreBiRefNetl-matte.torchscript")result = model(SAMPLE_IMAGE) print(result.matte.array.shape)

Проверенный путь для этой задачи — TorchScript. Конвертация в ONNX проходит, но не дотягивает до той же планки паритета, а остальные форматы недоступны. Покрытие по форматам — на страницах BiRefNet и FeyNobg, а также в полной матрице экспорта.

Проверено с LibreYOLO v1.5.0.