Маску сегментации нельзя менять как фотографию: nearest при resize

Команда уменьшает фотографии и маски перед обучением сегментации. Для изображения билинейная интерполяция даёт плавный результат, поэтому ту же настройку копируют на маску. После подготовки в разметке внезапно появляется класс с номером 1, хотя исходные классы были только 0 и 2. Модель начинает учиться на артефакте обработки, а ошибки на границах объекта выглядят необъяснимо.

Пиксель маски — это метка, а не цвет

В семантической маске число в пикселе обозначает категорию. Между классами 0 и 2 нет «половинного» класса 1. Интерполяция BILINEAR усредняет соседние значения, как если бы это были яркости. NEAREST выбирает ближайшую исходную метку и сохраняет словарь классов. Для фотографии и маски нужны разные способы изменения размера, хотя геометрические размеры должны совпадать.

import numpy as np
from PIL import Image

mask = Image.fromarray(np.array([[0, 2], [2, 0]], dtype=np.uint8))
nearest = np.asarray(mask.resize((6, 6), Image.Resampling.NEAREST))
bilinear = np.asarray(mask.resize((6, 6), Image.Resampling.BILINEAR))
print("nearest классы:", np.unique(nearest).tolist())
print("bilinear классы:", np.unique(bilinear).tolist())
assert set(np.unique(nearest)) == {0, 2}
assert 1 in np.unique(bilinear)

После увеличения учебной маски nearest оставляет только классы 0 и 2. Bilinear создаёт значение 1. Код проверяет оба факта. Если в вашей маске хранятся идентификаторы объектов, а не классов, усреднение ещё опаснее: промежуточный номер может совпасть с идентификатором другого объекта и незаметно смешать их.

Проверяйте весь маршрут геометрии

Применяйте одинаковые кроп, поворот и отражение к изображению и маске, но при ресемплинге выбирайте подходящий режим для каждого типа данных. После преобразования сравните np.unique маски со списком допустимых ID, проверьте совпадение размеров и наложите маску на изображение. Последняя проверка ловит сдвиг, который список классов не покажет.

Осторожно с палитровыми PNG: видимый цвет может быть лишь представлением индекса класса. Не превращайте такую маску в RGB и обратно без явной таблицы цветов, иначе точные ID исчезнут. При бинарной сегментации усреднённую серую маску иногда порогуют, но это меняет геометрию границы; для исходных дискретных меток проще сразу использовать nearest. Для soft mask, где пиксель действительно хранит вероятность, логика другая — проверьте формат до выбора интерполяции.

Оценку качества тоже проводите после восстановления маски в координаты эталона. Разбор IoU и пустых масок помогает не скрыть ошибки неправильным усреднением. Если словарь классов и размер уже проверены, падение IoU можно связывать с моделью и разметкой, а не с созданными при resize псевдоклассами.

Nearest сохраняет допустимые ID, но не гарантирует сохранение каждого маленького объекта. При сильном уменьшении тонкая линия может полностью исчезнуть, потому что ни один выходной пиксель не выбрал её исходную точку. Посчитайте площадь ключевых классов до и после преобразования и найдите изображения, где класс исчез. Для таких случаев может понадобиться другая исходная резолюция или правило подготовки тайлов. Это отдельная проблема от промежуточных псевдоклассов, которые создаёт bilinear.

В курсе «Computer Vision Engineer: от детекции и Doc-AI до продакшна» вы готовите разметку для сегментации, обучаете модели и измеряете IoU/Dice. Проверка масок после каждого преобразования делает эти метрики осмысленными. Посмотрите программу курса.

Продолжить на практике

  • Computer Vision Engineer: от детекции и Doc-AI до продакшна ↗

    Практический курс по Computer Vision. Соберёте продакшн-сервис: датасет → обучение (YOLO/RT-DETR, SAM), трекинг, OCR/Doc-AI, веб-приложение (UI+API) и мониторинг. Экспорт в ONNX/TensorRT/OpenVINO, батчинг/квантование под CPU/GPU. Плюс профессиональные блоки: mAP/IoU/Dice и калибровка доверия, QA разметки и аугментации, p95/стоимость, дрейф данных и алерты, guardrails (NMS/правила), A/B-тесты, Triton/gRPC/FastAPI.