
Заказчик контролирует технику безопасности на палубе судна: в рабочих зонах экипаж обязан быть в касках, спасательных жилетах и костюмах-поплавках. Визуальный контроль по камерам не масштабируется, оператор не сможет физически охватить все потоки за смену.
Задача: автоматически фиксировать нарушения ношения СИЗ (каски, спасательные жилеты, перчатки, костюмы-поплавки) в рабочих зонах на открытой палубе судна.
На входе: RTSP-потоки судовых камер
На выходе: подтвержденные инциденты.
Система анонимна: фиксирует факт нарушения, а не личность.
Одного кадра недостаточно
Нейросеть в таких задачах работает как сенсор: отдает рамку по конкретному кадру и ничего не знает о контексте вокруг него.
На объектив попадают брызги, работник в СИЗ может на секунду отвернуться, его фигуру может перекрыть другой работник или группа. Если генерировать алерт на каждый спорный кадр, журнал инцидентов за смену превращается в поток ложных тревог, который оператор быстро перестанет читать.
На палубе одновременно действует несколько источников нестабильности:
Оптика и погода. Дождь, снег, туман и морская пыль снижают контраст и порождают ложные мелкие объекты.
Оптические артефакты. Мокрый металл и лужи дают блики, которые модель принимает за светлые каски или куски жилета.
Физика. Ветер меняет форму одежды: капюшоны, воротники и костюмы-поплавки в соседних кадрах выглядят по-разному.
Геометрия. Качка и вибрация двигают границы зон безопасности и траектории людей.
Отдельная проблема ракурса: визуальное перекрытие на камере и реальное снятие экипировки дают на кадре одну и ту же картину: отсутствие рамки СИЗ. Детектор не может различить эти два случая по одному кадру.
Пример. Матрос в полной экипировке наклоняется над тросом. Каска спряталась за плечом, жилет перекрывается рукой. Человек защищён, но детектор на трёх кадрах подряд отдаёт "человек без каски". Система в этом случае не открывает нарушение сразу, а берёт паузу, так как трекер должен снова зацепиться за экипировку, когда работник сменит положение тела.
Архитектура: детекция отдельно, решение о нарушении отдельно
Систему разделили на два уровня: модель, которая отвечает только за наблюдения, и отдельный слой логики, который отвечает за события.
Пайплайн:
Детектор выдает рамки людей и СИЗ.
Ассоциатор решает, кому именно принадлежит каска или жилет.
Трекер удерживает ID человека между кадрами при перекрытиях.
ReID-галерея восстанавливает сквозной ID, если трекер сбросил локальный номер.
Статусная машина ведет состояние каждого элемента экипировки у каждого человека.
Менеджер событий принимает итоговое решение: открыть алерт, обновить существующий или подавить дубль.
IoU здесь не работает
Стандартный IoU для привязки каски к человеку не подходит: каска мала по отношению к рамке человека, поэтому скор всегда получается крошечным, даже при идеальной посадке. Вместо этого считаем долю площади СИЗ, попавшую внутрь рамки человека.
Этого тоже мало. На палубе тесно: один человек наклонился, другой прошел сзади — и чужая каска попала в чужую рамку. Добавили анатомические зоны: каску ожидаем только в верхней части рамки человека, жилет — по корпусу.
В интерфейсе оператора подтвержденные статусы выделены отдельным цветом на нейтральном фоне, это упрощает быстрый просмотр журнала за смену. Есть нижний физический порог: если каска в кадре меньше 40 пикселей, результат наблюдения отбрасывается. Ниже этой границы отсутствие детекции перестает быть доказательством нарушений.
ReID: как удержать ID человека при перекрытиях
Для менеджера событий ID человека — ключ к записи в базе. Если трекер меняет номер сотрудника каждый раз, когда люди проходят друг за другом, таймеры обнуляются, множатся дубли алертов.
Поверх трекера добавили галерею эмбеддингов. На качающейся палубе геометрия рамки нестабильна, и одного трекера по координатам не хватает, галерея даёт вторую точку опоры для восстановления ID. Правила галереи:
Сквозной ID. Если трекер потерял человека за оборудованием и вернул его с новым номером, галерея связывает новый локальный трек со старым.
Анти-свап. Когда рамки двух людей сильно перекрываются, их эмбеддинги не обновляются.
Привязка к месту. Если человек появился рядом с точкой, где он исчез, требования к совпадению эмбеддинга смягчаются.
Фильтр подозрительных обновлений. Одиночный эмбеддинг, резко отличающийся от усредненного портрета, не перезаписывает галерею сразу.
Логика алертов
Для каждого работника и каждого элемента СИЗ хранится отдельный объект состояния, основанный на недавней истории наблюдений.
Статус | Когда устанавливается |
| СИЗ видели недавно, кадр валиден, привязка к человеку уверенная. |
| СИЗ не виден, но таймер отсутствия еще не набрал порог. |
| СИЗ не виден дольше порога, человек наблюдается достаточно долго, кадры валидны. |
| Человек мал, обрезан, перекрыт, кадр плохой, идет сильный дождь/снег, объектив загрязнен. |
| СИЗ снова виден устойчиво несколько кадров подряд. |
Разница между absent и unknown принципиальна. Если человек далеко, каска занимает мало пикселей, а палубу заливает блик — отсутствие рамки каски не доказывает нарушение, это unknown. Если человек крупный, находится в рабочей зоне, голова видна, кадры валидны, а каска не появляется 15 секунд — это absent.
Если сотрудник 10 минут работает без жилета, это одно нарушение, а не 600 сообщений-алертов. За это отвечает менеджер событий, который отвечает только за ведение журнала.
Жизненный цикл события:
статус
absentпоявился, но еще проверяются антидубли и зона;событие записано в журнал, оператор получил уведомление, сохранены кадр и короткий клип;
нарушение продолжается, новые уведомления подавляются;
если нарушение длится слишком долго, отправляется повторное напоминание через большой интервал;
СИЗ снова виден устойчиво, или человек покинул зону по корректной траектории;
событие распознано как дубль уже открытого нарушения или как ошибка трекера.
Если ID сбился, но в той же части кадра уже есть активное событие “нет жилета”, новое событие не создается, обновляется существующее или подавляется дубль. Если человек ушел, вернулся в СИЗ и снова его снял — это новое событие, потому что восстановление сняло флаг “уже зафиксировано”.
Оценка качества кадра при плохой погоде
При плохой погоде напрашивается решение поднять threshold уверенности модели. Так отсекается часть ложных срабатываний, но заодно теряется часть реальных нарушений.
Поэтому вместо такого хода мы добавили отдельную оценку качества кадра перед обновлением статусов: размытие, пересветы, капли на объективе. Этот слой просто проверяет, годится ли кадр для доказательной базы или нет. Если кадр негодный, статус переходит в unknown. Так, сильный ливень не генерирует ложные нарушения, в слепой зоне нарушение не фиксируется.
Вывод
На этапе MVP зафиксировали планку Accuracy на уровне 60–70%. Часть задач вынесена за скобки: система проверяет только наличие СИЗ, а не правильность ношения. Расстегнутую куртку или капюшон поверх каски пока не обрабатываем — это требует отдельного сбора краевых случаев.
В рабочем процессе система снимает с оператора постоянный просмотр потока с камер: разбор идёт уже по отфильтрованным и подтвержденным событиям. Журнал алертов стал предсказуемым: одно длящееся нарушение — одна запись. Корректность ношения СИЗ и разбор нестандартных ситуаций остаются на сотруднике, который контролирует СИЗ и ТБ.
Коллеги, работал ли кто-то с подобной задачей? Не столько про СИЗы, сколько про детекцию и трекинг на подвижной платформе или в агрессивной среде. Интересно, как вы отделяли ошибку детектора от реального нарушения/события на одном кадре?
