Так получилось, что я работаю в компании, где есть своя корпоративная столовая. «Ну офигеть теперь!» — воскликнет дорогой читатель. Но это не всё. Поток сотрудников в столовой может составлять более 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 используем.
Таким образом для каждой из областей у нас есть свои координаты точек для теста и условия проверки на принадлежность определенному диапазону цвета.
Считаем баллы
В моей первой версии все довольно просто — есть 31 точка, которая проверяется на пустоту, далее смотрим сколько из них не прошли тест и записываем эти данные в таблицу каждые 5 секунд.
Для подсчета текущей загрузки все тоже довольно просто — берем 5 последних значений из базы, усредняем, приводим к десятибальной шкале, выводим округленное до целых число.
Вывод информации
Не будем особо заморачиваться, просто возьмем светофорчики у Яндекса, отразим по горизонтали, и ХОБАНА, это уже не плагиат, использую где хочу, законом не запрещено, на 95% быстрее, чем рисовать самому!
Развитие сервиса
Это, конечно, все замечательно, но кому интересно просто смотреть на меняющуюся цифру и цвет светофора? Гораздо полезнее добавить разных классных или не очень штук.
Уведомление о снижении загруженности по SMS
Отправка уведомлений по запросу. Здесь сервис будет проверять среднее значение загруженности за более длительный период, и, если балл соответствует запросу пользователя, отправит SMS.
Это Serious Business и у нас уже достигнуты договоренности с операторами сотовой связи об использовании символьного SENDER-ID «safi.probki»
Бот для Telegram
Особенности сервиса таковы, что получить информацию о загруженности через телефон нельзя — только внутренняя корпоративная сеть. Запустив бота, можно решить эту небольшую проблему, получая данные по запросу или автоматически, если пробки проходят определенные границы.
Аналитика по дням и часам
Любопытно посмотреть статистику по загрузке столовой в разные дни и часы, строить графики, вот это вот всё. Собирая значения по дням с указанием времени, сделать это будет не сложно.
Улучшение точности
Текущая реализация, на которую ушло несколько часов, имеет среднюю точность. Сервис просто берет количество точек, не прошедших тест. Хорошо было бы учитывать положение этих точек — человек в области сканирования, перед которым нет других людей, не должен вносить существенный вес в расчет загруженности. Также, итоговое значение в баллах должно строиться с некоторым учетом исторических данных за прошедшие 5 минут. Дополнительно можно было бы ввести определенные коэффициенты для разных точек.
Основная мера, по которой мы оцениваем очередь — это её длинна. На данный момент скрипт сканирует только одну камеру. Заметно улучшить качество оценки может подключение к другой камере, однако выставленный кадр не позволяет выделить области, где могут быть только люди из очереди. Но попробовать можно.
Монетизация
Какие варианты монетизации есть у сервиса? Да просто обширные! Конечно же в первую очередь сервисом заинтересуется менеджмент Тинькофф Банк. Как мы знаем, сотрудники Банка в последнее время слишком много едят и пьют кофе, не жалея денег акционеров.
Коллеги, я вижу, вы расслабились?! Напоминаю, что приём пищи (ака обед) у нас предусмотрен один раз и составляет один час.
— Олег Тиньков
Оборудовав столовую Олега нормальными камерами, вполне реально подключить Google Cloud Vision API и в режиме реального времени вести статистику кто из коллег больше всего жрет.
Также, этот сервис может заинтересовать и Рокетбанк. В этом случае можно было бы вести статистику по тем, кто слишком мало кушает или слишком мало ходит курить не группами.
Извините, но мне уже звонят. Спасибо за внимание и не тратьте время на пробки!
P.S. — Статью опубликовали на vc.ru, кажется, я стал успешным стартапером.
—
С уважением,
Президент аналитического центра «Сафи.Пробки»
Сафи Марат