Pull to refresh
138.98

Как мы отличали тележку от прораба — видеоаналитика для кассовой зоны гипермаркета (и продолжение про кота-терминатора)

Reading time 6 min
Views 30K
В одном строительном гипермаркете есть 18 касс, и надо уметь делать так, чтобы кассиры открывали их вовремя, чтобы очередь не была больше 4 человек. Ну, и чтобы лишние кассы не простаивали открытыми. Это распознавание людей (подсчёт покупателей) с видео, аналитика по погоде и другим факторам и предсказание потока. Плюс много другой забавной статистики.


Пример очереди перед кассой — картинка обрезанная и замыленная по просьбе безопасников, по факту очередь мы видим длиннее, чем на фото.

В рознице первым вопросом стало то, как отличить прораба от тележки. И это было ничуть не смешно.

Да, и тем, кто переживал за кота-терминатора из прошлого поста — его поймали. Детали в конце.

До этого мы делали нечто подобное для касс пригородных электричек и самих электричек. В случае с кассами длина очереди отлично распознавалась, и кассиры стали работать куда оптимальнее. А вот на перронах дешевле оказалось фиксировать зайцев не камерами, а просто ставить вохру.

Кластеры покупателей


На входе у нас данные с камер, смотрящих вертикально вниз на кассы. Картинка с них распознаётся ПО Synesis CasRetail, и мы имеем уже не видеопоток, а данные о том, во сколько пришёл какой объект и во сколько он покинул зону действия.


Наконец-то у нас появилась полная законченная история аналитики, которую можно рассказать.

Вот пример лога (расшифровывать не стал, и так вроде должно быть понятно):

{
      "camera" : "22f961d5-9cfc-4214-8870-65edb79fe373",
      "start" : "2016-09-11T14:28:03+03:00",
      "end" : "2016-09-11T14:29:00+03:00",
      "rules" : [
      // данные для линии  
      {
         "counter" : 12,
         "rule" : "36da29cf-7858-4bc6-9b11-55ff129aeaa7",
         "extendedStatistics" : [ "2015-02-11T14:28:04+03:00", "2015-02-11T14:28:04+03:00", "2015-02-11T14:28:12+03:00"] // (optional)
      },
      // данные для зоны 
      {
         "counter" : 0,
         "histogram":[57.61533203125003,0.0, .., 0.0,0.0], // total 256 items
         "lifetimeHistogram" : [],
         "lifetimeHistogramStep" : 60,
         "lostObjectsCounter" : 2,
         "bornObjectsCounter" : 0,
         "objectsAtEndInterval" : 12,
         "rule" : "ea473652-2f7d-49fc-bce0-e6d93e472c17"
      }
   ]
}

Данные из касс по чекам мы брать не могли — они напрямую соединены с Европой по VPN, и, увы и ах, нужно преодолеть сразу два законодательства по персональным данным. В общем, если мы не хотим ждать год (а мы не хотим), этих данных на практике нет.

ПО обрабатывает картинку 640х480 и, кстати, для задачи подсчета покупателей больше и не нужно. Система справляется легко…. Да-да, downsample почти в 3 раза и это увеличивает скорость обработки изображения. Тут не нужно много мегапикселей, так как человек может занимать в кадре всего 30-40 пикселей.

Проблема определения количества людей по логу никак не решалась, и вот почему:

  • Покупатель может прийти толпой (например, семьёй). По факту будет 3-4 человека, но реально — один чек. А данные про чек в европейской стране, и если вы не хотите ждать год… ну, вы поняли.
  • Может прийти прораб, набрать стройматериалов в 3-4 тележки и уйти. Система отфиксирует группу объектов, но покупатель будет опять же один.
  • Мать с коляской и тележкой — это 3 непонятных объекта.

Мы пришли к тому, что прямо на кассе такая задача не решается быстро, без копания в низком уровне распознавания, никак. Промышленно, конечно, можно профилировать тележки и другие объекты, но мы вспомнили дядьку Дейкстру с его историей с железнодорожными вагонами и решили ещё понаблюдать.

Через несколько дней наблюдений за повадками тележек выяснилось, что они льнут к людям. И группа людей, сделавшая один чек, практически одновременно уходит из кассовой зоны. То есть задача сводилась к подсчёту кластеров объектов, выходящих за виртуальную линию кассы (на картинке — tripwire_11) — а это решается крайне просто. Кстати, линия нужна для того, чтобы корректно понимать, когда человек ушел из кассы. ведь если он вышел из зоны, то он просто мог уйти из очереди назад в зал (например, психанул, не стал ждать).

То есть система в реальном времени выдаёт статистику «два объекта ≈ один покупатель» и из этого показывает длину очереди. А с задержкой 1 минуту валидирует себя и уточняет, сколько покупателей было по факту на основе того, как они повели себя за кассой.

Это было суперкруто. Мы решили почти все проблемы такой системой с ошибкой в 2-5% (зависит от количества тележек, уборщиц, охранников и прочих отклонений от статистического среднего).

Сюрпризы распознавания


Итак, мы:

  • Знаем входящий поток людей за каждый день и знаем его в реальном времени.
  • Знаем длину очереди на каждой кассе.
  • Умеем делать в реальном времени уведомления о том, что надо открывать ещё кассу (где-то очередь длиннее 4-5 человек).
  • Умеем закрывать кассы, если они пустые.
  • Начинаем собирать данные для аналитики для предсказания расписания касс.

Сейчас системе уже полгода, и она работает с хорошим уровнем составления расписания, но тогда исторических данных у нас не было. Поэтому для начала мы посчитали за пару недель загрузку касс. Выводы получились парадоксальные:

  • Да, есть моменты, когда нужно больше кассиров.
  • Да, есть моменты, когда магазин несёт потери из-за простаивающих касс (сотни тысяч рублей в месяц).
  • Самое весёлое — при пиках на кассах 10-18 кассы 1-3 могут быть не загружены.

Про последнее скажу особо: оказывается, люди не умеют грамотно распределяться по кассам. И вполне возможны ситуации, когда какие-то кассы простаивают, а какие-то загружены. Умелое распределение позволяет сильно сэкономить по факту, и магазин этому научился.


Результаты анализа динамики максимальной и средней длин очереди по зонам обслуживания на одну из дат

Ход проекта


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

Минимальная смена кассира из аутстаффа (внешней компании, предоставляющей кассиров) — 4 часа. Чем раньше кассир будет заказан, тем дешевле. Поэтому дальше задача сводится, во-первых, к прогнозированию (нужно знать, сколько кассиров и когда надо, алгоритм, нужно сказать, не из простых — для тех, кто в теме — это блендинг из 6 моделей от классических ARIMA до RandomForest (любителям kaggle — и без xgBoost можно точно прогнозировать). А во-вторых, к оптимизации на основе прогнозных данных, а именно — к минимизации общей стоимости персонала при соблюдении необходимого уровня сервиса и кучи технических ограничений (например, аутстафф кассира нельзя выдернуть меньше чем на полдня).

Через месяц мы решили эту задачу без учёта сезонных пиков:

  • Исторические данные по дням дают точную загрузку по часам.
  • Есть профили для каждого дня недели.
  • Есть спецпрофили для ситуаций «осадки», «праздник», «день перед выходными», «день перед 3 выходными» — это очень важные ситуации для аналитики. Дождь, например, даёт минус 18 процентов к покупателям, а день перед 3 выходными — плюс 14%.
  • Есть данные о погоде.
  • Есть корреляты с других проектов (известные графики коллег со всего мира) — там просто 3-4 замера за день, но они очень полезны иногда, когда данных нет (например, будут полезны на Новый год).
  • Мы знаем конверсию, то есть с какой вероятностью зашедший в магазин станет покупателем. Это просто множитель к выходному потоку.
  • Для людей, заходящих через кассы, мы тоже знаем примерные коэффициенты — их пришлось считать руками, но они вносят очень малую погрешность.

Всё это вместе просто компонуется как модификаторы (каждый профиль — это график, то есть матрица), и суперпозиция векторов в каждые полчаса даёт прогнозируемую нагрузку. А затем на это накладывается ограничение по длительности смены и допустимая погрешность — и составляется расписание.

Система может учиться, и сама себя верифицировать по схеме план-факт. Плюс можно прикрутить email-уведомления, собирать статистику.

Дальше


В целом система работает. Маркетологи счастливы. К ней сейчас присматривается и прошлый заказчик из истории с котом. Есть в том числе интерес у их европейских коллег для ряда объектов, считаем сейчас и для них.

А это результаты нашего теста или «шуточного» сервиса под названием «пробки в столовой». Тоже отлично работает уже пару лет. Для того, чтобы им воспользоваться, достаточно зайти в корпоративную соцсеть, где в реальном времени можно посмотреть текущую загруженность нашей офисной столовой, а также прогноз времени, необходимого для того, чтобы отстоять очередь в кассу и пообедать в зависимости от того, когда подойти. И что самое интересное – совсем недавно такую систему себе захотели внедрить два внешних заказчика. Один из них, например, как оказалось, уже 2 года безрезультатно бился с огромными очередями в столовой.





Про кота


Напомню, в прошлом посте про распознавание лиц на входе на объект фигурировал кот, наносящий убытка магазину на 50-100 тысяч рублей в месяц. Этот неутомимый охотник отметился на видеонаблюдении тенью, прыгающей сверху на самые жирные мешки с кормом и вскрывающей их в поисках тёплых сочных внутренностей. А ещё на него списывали много дорогого алкоголя.

Кот уходил от погони 4 года. Даже когда за него (живого) давали награду 5 тысяч рублей, его не могли поймать в течение нескольких месяцев. Но после прошлого поста животное постиг хабраэффект: сотрудники организовались и выследили дикого зверя. Пойманный кот теперь живёт в ближайшей к магазину воинской части (в роли талисмана) и привыкает к людям. Вот его хитрая рожа:


Ещё проекты


Tags:
Hubs:
+53
Comments 42
Comments Comments 42

Articles

Information

Website
croc.ru
Registered
Founded
Employees
1,001–5,000 employees
Location
Россия