«Самое время пойти перекусить»

Как создать сервис, который предупреждает о «пробках» в корпоративных столовых

Менеджер интернет-проектов ЦУМ Марат Сафи опубликовал на Facebook заметку, где поделился с читателями идеей создания сервиса, который будет предупреждать пользователей об очередях в столовых больших компаний при помощи анализа изображений с камер наблюдения. Редакция vc.ru публикует материал с разрешения автора.

«Самое время пойти перекусить»

Так получилось, что я работаю в компании, где есть своя корпоративная столовая. «Ну офигеть теперь!» — воскликнет дорогой читатель. Но это не всё. Поток сотрудников в столовой может составлять более 1000 человек в сутки. Разумеется, бывают определённые «часы пик», когда в столовую лучше не ходить, ибо «пробки».

К счастью, внутри компании доступна трансляция с четырёх камер видеонаблюдения, благодаря которой можно оценить загрузку столовой и найти ответ на главный вопрос жизни, вселенной и всего такого, а именно: «Идти обедать сейчас или лучше подождать?».

Однажды за завтраком я подумал, что было бы интересно автоматически анализировать картинку с камер и хотя бы примерно оценивать степень загруженности. Так возникла идея попробовать сделать свои «Яндекс.Пробки», только «Столовая.Пробки».

Что есть на входе? В моём распоряжении оказалась виртуальная машина под Debian со всякими там PHP и MariaDB и статичное изображение с камеры, которое обновляется в реальном времени. Замечу, что изображение не самого хорошего качества.

Выбираем методику анализа

Первая мысль — улучшить картинку, поправив яркость и контраст, затем перевести её в черно-белое изображение, определить области, где нужно «мерить» поток, и в зависимости от того, чёрный пиксель или белый, считать наличие или отсутствие человека на маршруте.

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

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

Подготовка изображения

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

Исходное изображение довольно тусклое

С помощью imagefilter() добавим изображению 55 пунктов яркости и выкрутим контраст на -120.

Улучшаем исходное изображение

Теперь белый стал белым, а чёрные области действительно окрасились в радикально чёрный цвет. Роботу с плохим зрением будет проще понять, что тут вообще происходит. Далее разум подсказал «Нужно бооольше пикселей!», и я зачем-то их добавил. В принципе, это не обязательно. Так мне проще было понять «округлённые» пиксели, по которым будем определять границы областей для тестирования на инородные элементы.

Детали не нужны

Области для анализа

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

После этого в скрипте заводим три массива с координатами точек, которые будут проверяться на соответствие определённому цвету. Очевидно, что если в этих популярных для очереди местах цвета точек не будут соответствовать цвету соответствующих точек пустого кадра (тёмно-оранжевый, белый, светло-оранжевый), значит, кто-то их перекрывает. Главное, чтобы в компании не ввели дресс-код с оранжевыми шортами и белыми колготками — такие люди станут большой проблемой для моего скрипта.

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

Цветовые модели RGB и HSV (HSB)

В PHP, как и в Photoshop, тоже есть инструмент «пипетка», только вызывается он с помощью функции imagecolorat(). Натравив эту функцию на определённый пиксель, получим его цветовое RGB-значение, из которого можно выделить отдельно интенсивность красного, зеленого и синего каналов в диапазоне от 0 до 255.

Модель RGB не позволяет удобно указать диапазоны RGB-значений, которые соответствовали бы тому же оранжевому цвету с небольшими отклонениями, так как оттенок зависит от пропорций каждого из компонентов этой аддитивной модели. Другими словами, для описания различных вариаций оранжевого от темного до светлого и с различной насыщенностью пришлось бы изобретать формулу, а это как-то сложно. Гораздо проще использовать более подходящую цветовую модель.

HSV (HSB)

Эта модель имеет несколько другие координаты:

  • Тон (Hue) — оттенок со значениями от 0 до 360 градусов, который на словах звучит как «Каждыйохотникжелаетзнать…».
  • Насыщенность (Saturation) — сила цвета от 0 до 100, где 0 — это отсутствие цвета, а 100 — «Аааа, мои глазааа».
  • Яркость (Brightness) — от 0 до 100, где 0 — это чёрный цвет, и чем больше, тем ярче, вплоть до самого яркого (при насыщенности 0 получим белый цвет).
Наглядное представление моделей RGB и HSV

Вот тут нам есть где развернуться, и любой цвет можно описать очень просто. Например, для оранжевой области выделим такой сектор, который с запасом опишет возможные вариации цветов.

Определяем цвет и его диапазоны для отдельной области

Хорошо, модель нам подходит, поэтому смело конвертируем RGB в HSV и используем.

Таким образом, для каждой из областей у нас есть свои координаты точек для теста и условия проверки на принадлежность определённому диапазону цвета.

Считаем баллы

В моей первой версии всё довольно просто — есть 31 точка, которая проверяется на пустоту, далее смотрим, сколько из них не прошли тест, и записываем эти данные в таблицу каждые пять секунд.

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

Вывод информации

Не будем особо заморачиваться, просто возьмём светофорчики у «Яндекса», отразим по горизонтали, и вуаля — это уже не плагиат, использую где хочу, законом не запрещено, на 95% быстрее, чем рисовать самому.

Пример работы скрипта

Развитие сервиса

Это, конечно, всё замечательно, но кому интересно просто смотреть на меняющуюся цифру и цвет светофора? Гораздо полезнее добавить разных классных или не очень штук.

Уведомление о снижении загруженности по SMS

Отправка уведомлений по запросу. Здесь сервис будет проверять среднее значение загруженности за более длительный период и, если балл соответствует запросу пользователя, отправит SMS.

Это Serious Business и у нас уже достигнуты договорённости с операторами сотовой связи об использовании символьного SENDER-ID «safi.probki».

Бот для Telegram

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

Аналитика по дням и часам

Любопытно посмотреть статистику по загрузке столовой в разные дни и часы, строить графики, вот это вот всё. Собирая значения по дням с указанием времени, сделать это будет не сложно.

Улучшение точности

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

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

Монетизация

Какие варианты монетизации есть у сервиса? Да самые обширные. Конечно же, в первую очередь сервисом заинтересуется Олег Тиньков из Tinkoff Bank. Как мы знаем, сотрудники банка в последнее время слишком много едят и пьют кофе, не жалея денег акционеров.

Коллеги, я вижу, вы расслабились?! Напоминаю, что приём пищи (ака обед) у нас предусмотрен один раз и составляет один час.

— Олег Тиньков

Оборудовав столовую Олега нормальными камерами, вполне реально подключить Google Cloud Vision API и в режиме реального времени вести статистику, кто из коллег больше всех ест.

Также этот сервис может заинтересовать и «Рокетбанк». В этом случае можно было бы вести статистику по тем, кто слишком мало кушает или слишком мало ходит курить не группами.

Извините, но мне уже звонят. Спасибо за внимание и поменьше вам пробок.

12 комментариев

Тиньковпозвонит

11
Ответить

судя по всему, уже позвонил =)

Ответить

мда, все 30 человек, которые ждали окончания пробки, чтобы её избежать, прийдут почти одновременно по команде СМС, вот думаю, кто кого тут перехитрил.

7
Ответить

Извините за критику! Мне кажется, куда проще и эффективнее просто поставить веб камеру над очередью - кликнул, увидел, принял решение! Плюс можно сделать датчик на вход и выход - будет показывать сколько человек сейчас в столовой. Ну и конечно, каждый сотрудник может выбрать удобное время для обеда. Например на каждые полчаса есть 200 мест.

4
Ответить

У нас так и было, просто камера, в которую видно очередь.

ps. Лучше бы датчик свободного туалета сделали :)

2
Ответить

Скоро на VC будут статья с фрагментами кода на языках программирования :)

2
Ответить

Сбер и госусл вроде давно реализовали такое. Там прогнозы есть по часам и реккоменды.
Подозреваю что от дня ко дню будут похожие графики и у вас в столовой.

Народ привык ходить по часам.
Только люди ценящие время ходят после 14.30... :neutral_face:

1
Ответить