Магазин самообслуживания работает без кассиров. Покупатель входит по QR-коду, берёт товар, рассчитывается и уходит. Внутри никого из персонала нет. Чтобы система работала без злоупотреблений, краж, нарушений и с нормальной аналитикой, владельцу такого магазина нужно владеть информацией: кто зашёл, как долго находится, в каких зонах стоял, и не произошло ли ничего нештатного.
Камера в зале одна. Потолочная fisheye-камера. Угол обзора — 180 градусов, весь зал виден "как на ладони" без "слепых" зон. Это типичный выбор для небольшого ритейла: дешевле, чем ставить четыре обычные камеры, проще в обслуживании. Камера уже висит. Менять её заказчик не собирается.
Проблема возникает тогда, когда заказчик принимает решение о внедрении видеоаналитики для контроля магазина. Стандартные алгоритмы трекинга людей на fisheye-камерах работают плохо. Это архитектурная несовместимость. Как мы с ней работали читайте в статье.
Почему fisheye — это не просто «широкоугольная камера»
Обычная камера проецирует пространство линейно. Fisheye — нет. Объектив проецирует сферическую сцену на плоский сенсор через нелинейное отображение. В результате пространство на краях кадра сжато не так, как в центре: один и тот же человек у центра и у края выглядит по-разному.
У центра — нормальный силуэт сверху. У края — вытянутый, искривлённый. Смещение на 50 пикселей в центре и у края кадра — это разные реальные расстояния.
Для трекинга в видеоаналитике это создаёт три вызова:
- Форма bounding box начинает "плыть". Когда человек идёт от центра к краю, его рамка меняет пропорции — от почти квадратной до вытянутого прямоугольника. Трекеры, которые ориентируются на IoU (пересечение рамок между кадрами), воспринимают такое изменение как потерю объекта и создают новый трек.
- Камера смотрит строго вниз. Люди ходят друг за другом — один полностью перекрывает другого. IoU между детекциями падает до нуля за один кадр.
- Модель движения некорректна. Классические трекеры предсказывают следующую позицию объекта по его предыдущей траектории — предполагая евклидово пространство. На fisheye пространство неевклидово, и предсказание ломается.

Как отслеживать людей в видеопотоке и почему стандартные алгоритмы трекинга не справились
Чтобы система понимала, кто где находится, ей нужно не просто обнаруживать людей на каждом кадре, но и связывать их между кадрами: понимать, что человек на кадре 101 — это тот же человек, что на кадре 100, а не новый. Эта задача называется трекингом, и для неё существуют готовые алгоритмы.
Логичным выбором казались SORT и DeepSORT — наиболее распространённые решения в этом классе задач. Их механика такая: алгоритм смотрит, где человек был, предсказывает, где он окажется на следующем кадре, и сверяет предсказание с тем, что видит детектор. Если рамки совпали — это тот же человек, ID сохраняется. SORT делает это через геометрию рамок. DeepSORT добавляет сверху «отпечаток внешности» — математический вектор, по которому можно узнать конкретного человека даже если он ненадолго пропал из кадра.
На fisheye оба механизма ломаются одновременно. Геометрия рамок ненадёжна: из-за нелинейных искажений объектива одна и та же рамка меняет форму и размер просто от того, что человек прошёл от центра к краю кадра — алгоритм воспринимает это как исчезновение одного объекта и появление другого. Предсказание позиции тоже не работает: оно предполагает, что пространство равномерное, а на fisheye это не так. А при перекрытии одного человека другим — на потолочной камере это происходит постоянно — алгоритм теряет ID и не восстанавливает его.
Мы прогнали оба на реальной записи с торгового зала. При первом же скоплении людей — примерно через 30–40 секунд — идентификаторы начали перемешиваться: система переставала понимать, кто есть кто. Счётчик посетителей после этого не восстанавливался. Чинить старые алгоритмы под fisheye-геометрию — тупик. Нужна другая архитектура.
Как это работает
Мы построили систему видеоаналитики для магазина самообслуживания на основе конвейера из шести компонентов. Каждый делает своё и передаёт результат следующему: от сырого видео с fisheye-камеры до структурированного события в базе данных: кто вошёл, когда, в какой зоне находился и не произошло ли ничего нештатного.
Шаг первый: детекция.
На вход поступает RTSP-поток с fisheye-камеры — обычный видеопоток, как с любой IP-камеры. Детектор на базе YOLO смотрит каждый кадр и находит людей: рисует вокруг каждого прямоугольную рамку и передаёт её координаты дальше.
Важный момент: детектор работает прямо на искажённом fisheye-кадре, без предварительного «выпрямления» геометрии. Мы тестировали вариант с выпрямлением — когда кадр сначала программно растягивается до нормальных пропорций, а уже потом подаётся в детектор. Выигрыша это не дало. Нейросеть детектора обучена на достаточно разнообразных данных, чтобы справляться с искажёнными силуэтами. Лишний шаг только тормозил pipeline.
Выпрямление координат осталось только в одном месте — когда система считает скорость передвижения. Пиксель в центре fisheye-кадра и пиксель у края — это разные реальные расстояния. Чтобы перевести смещение в метры в секунду, нужно сначала пересчитать координаты в нормальное пространство. Но это точечная математическая операция над координатами, а не рендер всего кадра.
Шаг второй: трекинг.
Детектор нашёл людей на одном кадре. Трекер — OC-SORT с ReID-эмбеддингами — связывает их между кадрами: решает, кто из найденных на кадре 102 соответствует кому из найденных на кадре 101.
Принципиальное отличие OC-SORT от классических алгоритмов: он обновляет «мнение» о треке по тому, что реально видит, а не по тому, куда объект должен был прийти по математической модели движения. В толпе, где люди резко меняют направление или останавливаются, предсказание траектории постоянно ошибается — OC-SORT на него не полагается.
Под fisheye-условия параметры подобраны нестандартно. Решение о том, тот ли это человек, на 85% принимается по сходству внешности и только на 15% — по геометрии рамок. Это потому что рамки на fisheye постоянно меняют форму и размер при движении — доверять им нельзя. Порог пересечения рамок снижен с обычных 0.3–0.5 до 0.05: в скоплении людей их рамки накладываются друг на друга, и высокий порог систематически склеивал двух разных людей в один трек. Время, в течение которого трек «держится живым» без нового обнаружения, — около 7–10 секунд при стандартной частоте камеры. Достаточно, чтобы не терять человека, когда он на несколько секунд скрылся за стеллажом.
Шаг третий: ReID-менеджер.
Это слой поверх трекера, который занимается восстановлением потерянных идентификаторов и защитой от путаницы. Он решает три задачи.
- Накопление «портретов». Для каждого человека в кадре система хранит не одно фото, а очередь из последних 30 математических векторов внешности. На их основе строится усреднённый портрет — чем дольше человек в кадре, тем точнее его описание.
- Восстановление ID после исчезновения. Когда трекер создаёт новый трек — видит нового человека — менеджер сравнивает его внешность с портретами тех, кого потеряли раньше. Если совпадение достаточно близкое и человек появился примерно там, где пропал, старый номер возвращается. Это позволяет не множить счётчик посетителей каждый раз, когда кто-то на несколько секунд скрылся и вышел обратно.
- Защита от перепутывания. Классическая ошибка трекеров: два человека идут навстречу, их рамки на секунду сливаются, и после расхождения они меняются номерами. На fisheye с видом сверху это происходит постоянно. Защита работает через проверку внешности: если внешность трека резко изменилась — значит, к нему «прилип» чужой человек. Два таких подозрительных события подряд — система останавливает обновление портрета и восстанавливает его по последним надёжным наблюдениям.
Отдельно обрабатываются ситуации, когда один человек физически закрывает другого. Если трек пропал, а у соседнего трека резко выросла площадь рамки — это слияние. Когда люди расходятся, система ищет потерянный трек по расстоянию между центрами и размеру рамок и пытается вернуть ему исходный номер.

Что система отдает на выходе
Финальное звено — бизнес-логика. Она получает список детекций с координатами и рассчитанными скоростями и генерирует семь типов событий:
- вход посетителя в зону магазина;
- выход из зоны;
- вход в зону кассы;
- резкое движение — скорость выше 5 м/с, возможный признак агрессии или вандализма;
- длительная неподвижность — скорость ниже 0.005 м/с дольше пяти секунд;
- долгое пребывание в зоне — больше 30 секунд;
- групповой вход — трое и более за пять секунд.
Выход из зоны не фиксируется мгновенно: реализован механизм задержки PendingExit. Если человек вышел за границу полигона и вернулся — это не засчитывается как выход. Без этой логики любое случайное касание края зоны порождало ложное событие.
Все данные пишутся в базу в структурированном виде и подтягиваются в аналитику магазина через API.
Что потребовало дополнительных настроек после установки системы в магазинах клиента
Две проблемы проявились уже на реальном потоке, когда система начала работать в живом магазине.
Счётчик посетителей считал одного человека несколько раз. Покупатель зашёл, сразу шагнул за стеллаж и на секунду пропал из поля зрения камеры. Система фиксировала его исчезновение, а когда он появлялся снова — записывала как нового посетителя. За один визит один человек мог засчитаться трижды. Для аналитики посещаемости это катастрофа: цифры расходились с реальностью.
Решение — ввести «период подтверждения»: система фиксирует нового посетителя только если человек присутствует в кадре устойчиво, несколько секунд подряд. Случайные мелькания за стеллажами перестали влиять на счётчик. Побочный эффект — небольшая задержка до пяти секунд между фактическим входом и записью в базу. Для аналитики это несущественно.
Ложные срабатывания на "выход из зоны". Магазин поделён на зоны: вход, торговый зал, касса. Система отслеживает, сколько времени человек провёл в каждой. Проблема возникла там, где граница зоны проходила прямо по маршруту движения: покупатель на долю секунды выходил за контур зоны — алгоритм фиксировал «выход», хотя человек просто шёл мимо. В итоге время пребывания в зоне считалось неверно, а аналитика по кассовой зоне давала ложные тревоги.
Причина оказалась в том, как операторы рисовали зоны: границу прокладывали вплотную к стеллажам и проходу, не оставляя запаса. Для камеры и трекера это слишком жёстко — достаточно небольшого отклонения траектории, и человек формально оказывается «снаружи». Закрыли данный вопрос документацией: зона должна перекрывать типичный маршрут с запасом, не обрезая его по краю. После перерисовки зон под реальные планировки ложные тревоги прекратились.
Зачем такая видеоанатика магазину самообслуживания и что она дает
Магазин без персонала — это не просто другая модель обслуживания. Это другая модель контроля: никто не стоит у входа, не считает покупателей, не замечает, что кто-то застрял у стеллажа уже двадцать минут или вышел, не подойдя к кассе. Всё это либо остаётся невидимым, либо требует ручного просмотра записей постфактум.
Система видеоаналитики закрывает этот пробел в реальном времени. Пока магазин работает, она непрерывно отвечает на несколько вопросов: сколько человек сейчас внутри, как долго каждый из них находится в зале, подходил ли к кассе, не происходит ли ничего нештатного. Все данные пишутся в базу автоматически и доступны в аналитике — без участия оператора.
- Посещаемость по часам и дням — без ручного подсчёта. Время пребывания каждого визита — видно, есть ли проблема с навигацией или выкладкой.
- Тепловые карты зон активности — понятно, куда покупатели ходят, а куда нет.
- Автоматические тревоги: человек не подошёл к кассе перед выходом, кто-то стоит неподвижно дольше пяти минут, в магазин вошла группа без сканирования карты.
- Оператор подключается только тогда, когда система подняла флаг. Просматривать часы записи вручную, чтобы выяснить, что произошло в 14:23, больше не нужно.
- Техническая сторона: система работает в реальном времени на стандартном видеопотоке с камеры и обрабатывает до 15 кадров в секунду на GPU уровня RTX 3060 — это потребительская видеокарта среднего класса, не промышленный сервер.
Где по-прежнему нужен человек
- Перед запуском оператор один раз размечает зоны под конкретную планировку зала — вход, торговый зал, касса. Это занимает час-два и делается не повторяется.
- Нестандартные инциденты — например, человек долго стоит на одном месте — система фиксирует и сигнализирует, но решение принимает человек: это задумчивый покупатель или что-то серьёзнее.
Где это работает и где нет
Система рассчитана на небольшие магазины самообслуживания с одной потолочной fisheye-камерой, которая покрывает весь зал. Это типичная конфигурация для торговых точек площадью до 80–100 м²: один объектив с углом обзора 180° закрывает всё пространство без мёртвых зон.
Стабильно работает при одновременном нахождении до 15 человек в зале. Это нормальная загрузка для магазина у дома или корпоративной точки самообслуживания.
При постоянном скоплении 20 и более человек с активным перемещением точность идентификации снижается. Алгоритм справляется с временными скоплениями, но если зал постоянно плотно заполнен — часть треков теряется. Для таких объектов нужна другая конфигурация: несколько камер с перекрывающимися зонами покрытия.
Главное с точки зрения внедрения: мы не требовали замены оборудования.
Заказчик пришёл с уже установленной fisheye-камерой — система построена под неё. Замена камеры на «более удобную для алгоритмов» стоила бы дополнительных денег и простоя. Вместо этого мы адаптировали архитектуру под реальные условия: детекцию и трекинг в искажённом пространстве, восстановление идентификаторов после перекрытий, защиту от перепутывания людей. Оборудование осталось то же — аналитика появилась поверх него.
Стек, технические нюансы развернули подробнее в статье на Habr ---> ЧИТАТЬ
