ИИ-контроль средств индивидуальной защиты (СИЗ) — уже классика среди задач прикладного компьютерного зрения. В открытых статьях на Habr уже подробно разбирают сбор датасета, разметку, сравнение YOLO, DETR и Faster R-CNN, работу с зонами и потоками камер. В научных публикациях 2024–2026 годов тоже видно то же направление: модели учатся распознавать каски, жилеты, очки, перчатки, а датасеты прямо содержат классы есть СИЗ и нет .
Зачем тогда нужна кастомная разработка? Раскроем тему на примере реального проекта.
Задача: автоматически фиксировать нарушения ношения СИЗ (каски, спасательные жилеты, костюмы-поплавки) в рабочих зонах. Место действия — открытая палуба судна. На входе RTSP-потоки судовых камер, на выходе — подтвержденные инциденты. Система должна работать анонимно, фиксируя факт нарушения, а не личность.
Обучить детектор и в прод? Не так сразу. На примере проекта четко увидели: одиночный кадр на палубе почти никогда не является доказательством нарушений.

Иллюзия идеального детектора
В промышленной системе и в реальной эксплуатации нейросеть —всего лишь сенсор, а не судья. Сенсор ошибается в силу того, что он находится не в идеальных лабораторных условиях: на объектив попали брызги, человек отвернулся, работники перекрывают друг друга в кадре. Если генерировать алерт на каждый спорный кадр, журнал инцидентов за смену превратится в свалку ложных тревог, которую оператор благополучно отправит в игнор.
На палубе одновременно действуют сразу несколько источников нестабильности, которые напрочь ломают наивную логику "нет рамки жилета = нарушение":
Оптика и погода: дождь, снег, туман и морская пыль снижают контраст и плодят ложные мелкие объекты.
Оптические артефакты: мокрый металл и лужи дают блики, которые нейросеть радостно принимает за светлые каски или куски жилетов
Физика: ветер постоянно меняет форму одежды. Капюшоны, воротники и костюмы-поплавки в соседних секундах выглядят совершенно по-разному.
Геометрия: Качка и вибрация приводят к тому, что границы зон безопасности и траектории людей начинают непредсказуемо "плыть".
Главная подлость палубного ракурса: для камеры визуальное перекрытие (ошибка детектора) внешне неотличимо от реального снятия экипировки (нарушения ТБ).
Разберем на практике. Матрос в полной экипировке наклоняется над тросом. Из-за ракурса каска прячется за плечом, а жилет перекрывается рукой. Физически человек защищен, но детектор на трёх кадрах подряд сигнализирует: "человек без каски".
Система воспринимает эту оптическую потерю как факт нарушения и присылает ложный алерт. Наша логика работает иначе: система берет паузу, чтобы трекер смог заново «зацепиться» за экипировку, когда человек сменит ракурс
Разделяй и властвуй: слой событий
Чтобы не сводить операторов алертами с ума, мы разделили систему на два уровня:
1. Модель, которая отвечает только за наблюдения
2. Отдельный инженерный слой логики отвечает за события.
Пайплайн выглядит так:
Детектор выдает рамки людей и СИЗ.
Ассоциатор решает, кому именно принадлежит каска или костюм.
Трекер удерживает ID между кадрами при перекрытиях.
ReID-галерея спасает ситуацию и восстанавливает сквозной ID, если трекер всё-таки сбросил локальный номер.
Статусная машина ведет состояние каждого элемента экипировки у каждого человека.
Менеджер событий принимает итоговое решение: открыть алерт, обновить старый или убить дубль.
Почему IoU здесь не работает
Для привязки каски к человеку стандартный IoU (Intersection over Union) использовать нельзя. Каска слишком мала по отношению к рамке человека, поэтому скор всегда будет крошечным, даже если она сидит идеально. Мы считаем долю площади СИЗ, попавшую внутрь рамки человека.
Но и этого мало. На палубе тесно. Один человек наклонился, другой прошел сзади, и вот уже чужая каска попала в твою рамку. Мы ввели анатомические зоны: система ожидает каску только в верхней части рамки, а жилет — по корпусу.
В интерфейсе оператора мы отказались от пестрых цветов и настроили строгую графитовую тему, где подтвержденные статусы подсвечиваются неоново-зелеными маркерами. Это позволяет глазу мгновенно выхватывать аномалии. К слову о лимитах: если каска в кадре меньше 40 пикселей, наблюдение отбрасывается. Это физическая граница, ниже которой отсутствие детекции перестает быть доказательством.
Память трекера и фокусы с ReID
Для менеджера событий ID человека — это ключ к базе данных. Если трекер меняет номер матроса каждый раз, когда люди проходят друг за другом, таймеры обнуляются и плодятся дубли алертов.
Поэтому поверх обычного трекера мы прикрутили галерею эмбеддингов. На качающейся палубе, где геометрия рамки нестабильна, это дает вторую точку опоры. Чтобы галерея не сошла с ума, мы написали несколько важных правил:
Сквозной ID: если трекер потерял человека за оборудованием и вернул его с новым номером, ReID галерея связывает новый локальный трек со старым.
Анти свап: когда рамки двух людей сильно перекрываются, мы не обновляем их эмбеддинги.
Привязка к месту: если человек появился рядом с точкой, где он исчез, требования к ReID слегка смягчаются.
Подозрительные обновления: одиночный эмбеддинг, резко отличающийся от усредненного портрета, не перезаписывает галерею сразу.
Логика алертов
Внутри системы для каждого человека и каждого элемента СИЗ хранится отдельный объект состояния. Он отвечает на вопрос: какой статус у этого элемента сейчас на основе всей недавней истории.
Базовые статусы:
Статус |
Когда устанавливается |
present |
СИЗ видели недавно, кадр валиден, привязка к человеку уверенная. |
suspect |
СИЗ не виден, но таймер отсутствия еще не набрал порог. |
absent |
СИЗ не виден дольше порога, человек наблюдается достаточно долго, кадры валидны. |
unknown |
Человек мал, обрезан, перекрыт, кадр плохой, идет сильный дождь/снег, объектив загрязнен. |
recovered |
СИЗ снова виден устойчиво несколько кадров подряд. |
Разница между absent и unknown принципиальна.
Если человек далеко, каска занимает мало пикселей, а палубу заливает блик, отсутствие рамки каски не доказывает нарушение. Это unknown.
Если человек крупный, находится в рабочей зоне, голова видна, кадры валидны, а каска не появляется 15 секунд - это absent.
Если человек десять минут работает без жилета, это одно нарушение, а не 600 сообщений.
Поэтому после статусной машины стоит менеджер событий. Он отвечает не за распознавание, а за поведение журнала.
У события есть жизненный цикл:
статус
absentпоявился, но еще проверяем антидубли и зонусобытие записано в журнал, оператор получил уведомление, сохранены кадр и короткий клип
нарушение продолжается, но новые уведомления подавляются
если нарушение длится слишком долго, можно отправить повторное напоминание через большой интервал
СИЗ снова виден устойчиво или человек покинул зону по корректной траектории
событие похоже на дубль уже открытого нарушения или на ошибку трекера.
Если ID сбился, но в той же зоне и в той же части кадра уже есть активное событие нет жилета, система не создает новое. Она обновляет существующее событие или подавляет дубль. Если человек ушел, вернулся в СИЗ и затем снова снял его, это уже новое событие, потому что восстановление сняло флаг "уже зафиксировано".

Как не утонуть в ложных срабатываниях при шторме
Первая мысль, что делать при плохой погоде — задрать threshold (порог уверенности модели). Но так мы просто пропустим реальные нарушения.
Мы пошли другим путем: мы оцениваем качество самого кадра перед обновлением статусов (размытие, пересветы, капли на объективе). Слой оценки не пытается распознать "дождь", он просто отвечает на вопрос: годится ли этот кадр как улика? Если нет — статус переходит в unknown. Сильный ливень не генерирует ложные нарушения, он просто ставит систему на паузу. Это честно: лучше промолчать в слепой зоне, чем обвинить матроса в том, чего он не делал.
Вывод
На этапе MVP мы осознанно зафиксировали планку Accuracy на уровне 60-70%. Мы не пытались объять необъятное. Например, система проверяет только наличие СИЗ, а не правильность его ношения. Расстегнутую куртку или надетый поверх каски капюшон мы отложили на следующие этапы, так как это требует долгого сбора краевых случаев.
Главный результат — журнал алертов стал предсказуемым. Видеоаналитика не заменяет инструктаж по ТБ, но она автоматизирует рутину, давая сильную доказательную базу. И самое главное — оператор перестал бороться с системой и начал ей доверять.
Каждый ложный алерт на производстве — это минус к доверию оператора, которое потом очень сложно вернуть. Наш подход со статусными машинами и оценкой качества кадра помог это доверие удержать.
Работали с подобной задачей? Поделитесь, как вы превращаете "сырые" детекции нейросети в осмысленные инциденты, когда камера работает в агрессивной среде? Как отсекаете визуальный мусор и фильтруете ошибки модели?