Ultralytics YOLO27: Встать в лист ожидания.
Get Started
Основы компьютерного зрения·Выбери задачу·Урок 3/10
Урокначинающий

Разберись в детекции объектов

Научись читать выходные данные детектора — класс, рамку и уверенность — и выбирать пороги уверенности и IoU с учетом цены каждой ошибки.

Большинство работающих в производственной среде систем компьютерного зрения — это системы детекции с дополнительной логикой: счетчики, трекеры, оповещения о зонах, размытие для защиты конфиденциальности. Когда что-то работает не так, причина обычно не в модели, а в пороге, который никто не выбирал осознанно. Если точно знать, что возвращает детектор и какие два параметра формируют этот список, можно отладить почти любую систему, построенную на его основе.

Результат

Читай результаты детекции YOLO26 в коде и выбирай conf и iou с учетом цены пропуска объекта и ложного срабатывания.

Ускоренное прохождение
Если ты уже освоился, вот краткая версия.
  1. Каждая детекция состоит из класса, рамки и оценки уверенности.

  2. conf отбрасывает рамки с низкой оценкой (по умолчанию 0.25); iou определяет, когда NMS считает две рамки дубликатами (по умолчанию 0.7).

  3. Пропуски обходятся дорого? Понизь conf. Ложные срабатывания заметны? Повышай его.

  4. Соседние объекты пропадают? Повышай iou.

  5. Уверенность ранжирует рамки, но это не калиброванная вероятность.

Практические занятия

Что возвращает детектор#

Детекции Ultralytics YOLO на набережной: люди, два велосипедиста, собака и две машины; на каждой рамке указаны класс и оценка уверенности

Каждая метка на этом изображении — это одна строка выходных данных: название класса, оценка уверенности и рамка вокруг объекта. Модель детекции возвращает именно такой список:

  • Класс — целочисленный индекс, сопоставленный с названием через result.names (0 — это person, а 5 — это bus).
  • Рамка — четыре числа, задающие положение объекта; xyxy возвращает координаты верхнего левого и нижнего правого углов в пикселях.
  • Уверенность — оценка от 0 до 1, используемая для ранжирования и фильтрации детекций.

Подсчет объектов, оповещения, треккинг и размытие — это код, который ты пишешь поверх этих строк.

from ultralytics import YOLO

model = YOLO("yolo26n.pt")
result = model("https://ultralytics.com/images/bus.jpg", verbose=False)[0]

for box in result.boxes:
    name = result.names[int(box.cls)]
    x1, y1, x2, y2 = box.xyxy[0].tolist()
    print(f"{name:8} conf={float(box.conf):.2f} box=({x1:.0f}, {y1:.0f}, {x2:.0f}, {y2:.0f})")
bus      conf=0.88 box=(0, 230, 803, 751)
person   conf=0.87 box=(49, 398, 240, 902)
person   conf=0.86 box=(223, 405, 345, 861)
person   conf=0.85 box=(670, 395, 810, 880)
person   conf=0.65 box=(0, 553, 60, 871)

Разберем по порядку: рамка автобуса начинается с x=0, потому что автобус выходит за левый край; уверенность для трех человек — 0.85–0.87; у четвертого человека, обрезанного левым краем, оценка всего 0.65 — модель видит половину тела. Низкая уверенность у частично обрезанных объектов — обычное явление, и именно здесь порог проявляет себя в первую очередь.

Каждая рамка представлена в одном из четырех форматов; используй тот, который ожидает твой код для последующей обработки:

АтрибутФорматТипичное применение
boxes.xyxyКоординаты углов в пикселях (x1, y1, x2, y2)Кадрирование, отрисовка, правила перекрытия
boxes.xywhКоординаты центра в пикселях, ширина и высотаФильтры по размеру, движение
boxes.xyxynКоординаты углов, нормализованные в диапазон 0–1Правила, сохраняющие работоспособность при смене разрешения
boxes.xywhnКоординаты центра и размеры, нормализованные в диапазон 0–1Файлы меток YOLO

От кандидатов к итоговому списку#

Внутри модель оценивает множество рамок-кандидатов для каждого объекта. Два фильтра превращают их в список, который ты видишь:

Фильтр уверенности. conf отбрасывает рамки ниже порога; значение по умолчанию при предсказании — 0.25. На изображении автобуса число детекций быстро меняется:

confРамки на bus.jpg
0.107
0.255
0.505
0.754

Фильтр дубликатов. Подавление немаксимумов (NMS) оставляет рамку с наибольшей уверенностью и отбрасывает другие рамки того же класса, если они перекрывают ее больше, чем на iou (по умолчанию 0.7). Перекрытие измеряется как пересечение над объединением: общая площадь, деленная на площадь объединения.

Пересечение над объединением на изображении птицы: перекрывающиеся предсказанные рамки и рамки эталонной разметки, а также соответствующие маски; IoU — это площадь перекрытия, деленная на площадь объединения

iouРамки на bus.jpgЭффект
0.35Строгий: пересекающиеся рамки объединяются
0.75По умолчанию
0.958Мягкий: почти дубликаты сохраняются

Выбирай пороги, исходя из цены ошибок#

Если…То…
Пропуск обходится дорого (предупреждения о безопасности, дефекты)Понизь conf и смирись с некоторыми ложными срабатываниями
Ложные срабатывания заметны пользователям (поиск, разметка тегами)Повысь conf
Ты сообщаешь количество объектовПроверь разные значения conf на валидационных изображениях и выбери то, при котором ошибка подсчёта минимальна
Настоящие соседние объекты пропадают в толпеПовысь iou, например с 0.7 до 0.8
Для одного объекта появляются две рамкиПонизь iou
Классы различаются по сложностиИспользуй минимальное необходимое значение conf, а затем фильтруй результаты по классам в коде

Мониторинг безопасности на складе — классический пример, где нужен низкий порог; в разделе режим Predict перечислены все аргументы инференса.

Подводные камни#

Воспринимать уверенность как вероятность

Симптом: «модель на 88% уверена, что это автобус», а пороги выбирают интуитивно. Решение: воспринимай уверенность как оценку для ранжирования. В YOLO26 одна оценка учитывает и «объект существует», и «это объект данного класса», но она не калибрована — выбирай порог по валидационным данным, а не по смыслу числа.

Не хватает одного из двух соседних объектов? Проверь NMS

Когда два человека стоят плечом к плечу, их рамки сильно перекрываются, и NMS может удалить реального человека как «дубликат». Увеличь iou, и вторая рамка появится. В YOLO26 также есть сквозная голова, которой совсем не нужен NMS; передай nms=False, чтобы использовать её.

Настройка на одном изображении

Симптом: порог, который идеально работает на демонстрационном изображении, не подходит для реальной камеры. Решение: проверь разные пороги на валидационной выборке с камеры, где будет развёрнута модель; одно изображение показывает лишь то, как работают настройки.

Четыре способа ошибиться#

СбойЧто не такТипичное исправление
Правильный класс, неточная рамкаЛокализацияУстанови более строгие и согласованные правила разметки рамок; используй более высокое значение imgsz для маленьких объектов
Хорошая рамка, неверный классКлассификацияДобавь больше примеров похожей пары или объедини классы
Рамки нет вовсеПолнотаДобавь больше примеров таких условий: освещение, размер, перекрытие
Рамка на фонеТочностьДобавь изображения со сложными отрицательными примерами, которые ввели модель в заблуждение

Два списка помогают быстро найти причину: истинно положительные объекты с низкой уверенностью (модель сомневается в реальных объектах) и ложноположительные результаты с высокой уверенностью (модель уверена в неверном ответе). Для них нужны разные исправления.

Попробовать

Запусти решение с conf=0.05 и открой сохранённое изображение. Отметь каждую рамку ниже 0.5 как истинно или ложноположительную и укажи причину каждого ложноположительного результата. Затем запиши значение conf, которое ты выберешь для счётчика пешеходов на этой камере, и обоснуй выбор одним предложением.

Критерии готовности
Урок считается завершённым, если выполнены все условия ниже.
  • У тебя есть список всех рамок ниже 0.5 на bus.jpg; каждая отмечена как истинно или ложноположительная с указанием причины.

  • Ты записал значение conf для счётчика пешеходов и ошибку, от которой оно защищает.

  • Ты можешь объяснить с помощью таблицы IoU, почему повышение iou возвращает подавленный соседний объект.

Показать решение
from ultralytics import YOLO

model = YOLO("yolo26n.pt")
result = model("https://ultralytics.com/images/bus.jpg", conf=0.05, save=True, verbose=False)[0]

for box in sorted(result.boxes, key=lambda b: -float(b.conf)):
    name, conf = result.names[int(box.cls)], float(box.conf)
    x1, y1, x2, y2 = box.xyxy[0].tolist()
    print(f"{conf:.2f} {name:10} ({x1:.0f}, {y1:.0f}, {x2:.0f}, {y2:.0f})")
0.88 bus        (0, 230, 803, 751)
0.87 person     (49, 398, 240, 902)
0.86 person     (223, 405, 345, 861)
0.85 person     (670, 395, 810, 880)
0.65 person     (0, 553, 60, 871)
0.18 person     (0, 600, 40, 871)
0.12 stop sign  (0, 252, 35, 326)
0.08 handbag    (43, 732, 78, 812)
0.07 skateboard (669, 822, 808, 881)
0.06 handbag    (225, 634, 291, 705)

Все рамки ниже 0.5 — ложноположительные. Рамка с person 0.18 дублирует рамку человека с оценкой 0.65, частично обрезанного левым краем. Объект с stop sign 0.12 — настоящий дорожный знак, которому присвоен неверный класс. Сумки и скейтборд находятся на руках и обуви. Оценка всех реальных объектов выше 0.6, поэтому conf=0.5 сохраняет всех четырёх людей и отбрасывает весь шум — для счётчика пешеходов это защищает от двойного подсчёта. Перед запуском проверь это на валидационном наборе с реальной камеры: частично обрезанный человек с оценкой 0.65 показывает, насколько близко реальные объекты могут оказаться к порогу.

Что дальше

Далее: когда прямоугольной рамки недостаточно и нужна точная форма объекта.

Войди, чтобы сохранять прогресс