Рамки и маски: когда действительно нужна сегментация
Измерь, что маска даёт по сравнению с рамкой на реальном изображении, и реши, нужна ли твоему проекту форма объекта, исходя из требований потребителя результата.
Когда люди представляют компьютерное зрение на базе ИИ, многие думают именно о масках; на их разметку команды тратят больше всего средств. Маска показывает точную форму объекта, а рамка — только его расположение. Для одних продуктов это принципиально, а для большинства ничего не меняет.
Практические занятия
Что даёт маска#

Для каждого объекта задача Segment возвращает всё то же, что и детектор: класс, рамку и уверенность, — а также пиксели, принадлежащие объекту. Поэтому у каждой машины выше есть собственный контур, отдельный от автобуса и пешеходов. Маску можно представить как полигон (masks.xy) или бинарное изображение (masks.data).
Насколько форма меняет численные показатели? Сравни площадь рамки каждого объекта с площадью его маски:
from ultralytics import YOLO
model = YOLO("yolo26n-seg.pt")
result = model("https://ultralytics.com/images/bus.jpg", retina_masks=True, verbose=False)[0]
for box, mask in zip(result.boxes, result.masks.data):
x1, y1, x2, y2 = box.xyxy[0].tolist()
box_area = (x2 - x1) * (y2 - y1)
mask_area = float(mask.sum()) # pixels inside the object's mask
name, ratio = result.names[int(box.cls)], mask_area / box_area
print(f"{name:7} box={box_area:7.0f} px mask={mask_area:7.0f} px ({ratio:.0%})")person box= 97116 px mask= 49331 px (51%)
person box= 68102 px mask= 21316 px (31%)
bus box= 410093 px mask= 255265 px (62%)
person box= 55998 px mask= 33524 px (60%)
person box= 23690 px mask= 11109 px (47%)Автобус занимает лишь 62% своей рамки, а один человек — 31%. Любое число, вычисленное только по рамкам, например площадь нанесённой краски, размер разлива или свободная площадь полки, будет ошибочным на эту величину. Если продукт сообщает подобные числа, тебе нужны маски. Если продукт только считает объекты или определяет их расположение, дополнительные пиксели ничего не меняют.
Симптом: площади масок выглядят в 3–4 раза меньше площадей рамок. Причина: по умолчанию masks.data возвращает маски в размере инференса (здесь 640×480), а координаты рамок — в пикселях исходного изображения (1080×810). Решение: передай retina_masks=True, как описано выше, или самостоятельно пересчитай количество пикселей.
Принимай решение с учётом потребителя результата, а не демонстрации#
| Требования последующей обработки | Достаточно рамок? | Почему |
|---|---|---|
| Подсчитать объекты или проверить их наличие | Да | Расположение — это и есть весь ответ |
| Отправлять оповещение, когда объект входит в зону | Да | Достаточно, чтобы рамка пересекла линию |
| Отслеживать объекты между кадрами | Да | Трекеры сопоставляют рамки |
| Обрезать изображение для второго классификатора | Да | Для обрезки достаточно рамки |
| Измерять площадь или покрытие (сорняки, ржавчина, разливы) | Нет | Из-за неправильной формы площадь рамки не имеет смысла |
| Вырезать объект (удаление фона, AR) | Нет | Нужна точная граница |
| Проверять зазор или контакт (захват роботом, столкновение) | Нет | Рамка завышает размер объекта |
| Разделять соприкасающиеся объекты неправильной формы | Часто нет | Перекрывающиеся рамки мешают понять, кому принадлежат пиксели |
Если во всех нужных твоему продукту строках указано «да», запускай детектор. Используй сегментацию YOLO26, только когда преимущества точной формы оправдывают затраты.
Экземплярная и семантическая сегментация#
Экземплярная сегментация создаёт отдельную маску для каждого объекта, поэтому три перекрывающиеся машины остаются тремя машинами. Семантическая сегментация присваивает каждому пикселю только класс: все пиксели машин объединяются в одну область «машина», а подсчёт становится невозможен. Используй экземплярную сегментацию, чтобы считать или измерять отдельные объекты — клетки, фрукты, дефекты. Используй семантическую сегментацию, чтобы измерять покрытие областей — дорогу и тротуар, посевы и почву.
Сколько стоит разметка формы#
Чтобы разметить рамку, нужно два щелчка. На хороший полигон могут уйти десятки щелчков, и на каждой границе возможны разногласия между аннотаторами: относится ли сумка к человеку, является ли тень частью машины? Вместо того чтобы полагаться на общие оценки, измерь собственные затраты: засечь время разметки 20 объектов рамками и тех же 20 объектов полигонами, а затем умножь разницу на размер своего набора данных.
Инструменты с поддержкой ИИ значительно сокращают разницу. Умная разметка и пакетная разметка создаёт маску по щелчку или рамке, поэтому аннотаторы корректируют границы, а не обводят их с нуля, — но каждую границу всё равно должен проверить человек.
До начала разметки реши, как обрабатывать окклюзии, прозрачные объекты, тени, объекты, обрезанные краем кадра, и прикреплённые предметы (сумки, ручки, грузы), а затем раздай одну и ту же инструкцию разметчикам и проверяющим. В Рекомендациях по разметке описано, как обеспечить соблюдение правил; набор данных COCO-Seg показывает, как выглядят согласованные маски в большом масштабе.
При выборочной проверке масок ищи выход за границу (маска выходит за контур объекта), пропуски (внутренние области объекта не попали в маску), ложные контуры (маска повторяет артефакт JPEG) и неоднозначные части (должна ли ручка чемодана входить в его маску?).
Показать решение
Представь, что изображение с автобусной камеры используют два продукта: счётчик людей и отчёт о занятости улицы, который показывает, какую часть сцены занимают транспортные средства. Измерь оба показателя по результатам одного запуска:
from ultralytics import YOLO
model = YOLO("yolo26n-seg.pt")
result = model("https://ultralytics.com/images/bus.jpg", retina_masks=True, verbose=False)[0]
height, width = result.orig_shape
for name in sorted({result.names[int(c)] for c in result.boxes.cls}):
rows = [i for i, c in enumerate(result.boxes.cls) if result.names[int(c)] == name]
union = result.masks.data[rows].amax(dim=0) # merge masks so overlaps count once
box_union = sum(float((b[2] - b[0]) * (b[3] - b[1])) for b in result.boxes.xyxy[rows])
print(f"{name:6} {len(rows)} objects | masks cover {float(union.sum()) / (height * width):.0%} of the image, boxes {box_union / (height * width):.0%}")bus 1 objects | masks cover 29% of the image, boxes 47%
person 4 objects | masks cover 13% of the image, boxes 28%- Счётчик людей → рамки. В обоих случаях подсчёт равен 4; маски увеличивают затраты на разметку и ничего не меняют.
- Отчёт о занятости → маски. По рамкам автобус занимает 47% сцены, а на самом деле — 29%. Отчёт на основе рамок ошибся бы более чем в полтора раза.