Я решил проблему с парковкой у дома с помощью машинного обучения
Рассказывает Адам Гайтги, разработчик из Калифорнии.
Я живу в прекрасном городе. Но как и в большинстве городов, поиски свободного места для парковки здесь всегда раздражают. Места быстро занимают, и даже если у вас есть закреплённое место, друзьям просто так к вам не заехать, ведь им придётся искать, где бы оставить машину.
Поэтому я решил разместить у окна камеру и с помощью глубокого обучения создать систему, дающую знать, когда у дороги появляется свободное место.
Можно подумать, что это сложно, но на деле всё довольно быстро и просто — надо лишь знать, где искать подходящие инструменты и как их объединить. Начнём!
Разбиваем проблему
Когда перед нами стоит сложная задача, которую мы хотим решить при помощи машинного обучения, первым делом нужно разбить её на несколько задач поменьше, а затем, словно доставая различные инструменты из ящика, решить каждую из них. Соединив всё в цепочку, мы получим систему, которой по зубам нечто сложное.
Процесс обнаружения свободных парковочных мест я разбил на следующие этапы:
Входные данные для машинного обучения даёт обычная веб-камера, смотрящая на улицу:
Каждый кадр мы пропустим по цепочке выше, один за раз.
- Первый шаг — найти в кадре все возможные места для парковки. Прежде чем определить, свободно ли место, нужно выяснить, где оно вообще.
- Второй шаг — найти в кадре все машины. Это позволит отследить движение каждого автомобиля от кадра к кадру.
- Третий шаг — установить, какие места заняты, а какие нет, для чего нужно объединить сведения, полученные на первом и втором шагах.
- Наконец, когда место освобождается, нужно отправить уведомление. Это мы сможем сделать, отследив изменение положения машины между кадрами.
Теперь же погрузимся в детали!
Распознаём места для парковки
Итак, вот вид с камеры:
Нам нужно исследовать это изображение и получить список участков, пригодных для стоянки.
Проще всего задать расположение каждого места вручную, но тогда, стоит нам, скажем, передвинуть камеру, придётся писать код заново. Это неудобно, поэтому давайте автоматизируем и этот процесс.
С одной стороны, можно ориентироваться по парковочным счётчикам, предположив, что место для парковки есть напротив каждого устройства.
Но тут есть ряд сложностей. Во-первых, не у каждого парковочного места есть счётчик (более того, мы зачастую ищем место, за которое не нужно платить). Во-вторых, расположение счётчика не указывает на точное расположение площадки для парковки, а только приближает к нему.
С другой стороны, можно построить модель, распознающую разметку.
Впрочем, и тут полно головной боли. Во-первых, полосы, размечающие места для парковки, в моём городе очень маленькие, их тяжело увидеть издалека; стало быть, и компьютеру будет непросто их разглядеть. Во-вторых, на улицах полно других линий и полос, поэтому отделить разметку парковочных мест от всей остальной будет сложно.
Когда перед вами сложная проблема, подумайте, можно ли подобраться к ней по другому пути, обойдя некоторые технические сложности. Что такое место для парковки? Место, где машина припаркована долго. А стоит ли вообще его распознавать? Почему бы просто не отыскать машины, которые долго не двигаются, и предположить, что они занимают парковочное место?
Иными словами, места для парковки — места, занятые стоящими автомобилями.
Распознаём машины
Существует немало техник машинного обучения, которые мы можем использовать для распознавания нужного объекта на картинке. Вот несколько самых расхожих алгоритмов, от «старой школы» к «новой»:
Гистограмма направленных градиентов. Это старая, не связанная с глубоким обучением техника работает довольно быстро, но не очень хорошо распознаёт машины с разных углов.
Свёрточная нейронная сеть. Этот подход точен, но не так эффективен, поскольку одно и то же изображение, чтобы выделить все машины, необходимо обработать несколько раз. И хотя такая сеть может с лёгкостью распознать автомобиль с разных углов, ей нужно гораздо больше данных для обучения, чем системе, строящейся на гистограмме.
- Нейросеть с архитектурой Mask R-CNN, Faster R-CNN или YOLO, которая объединяет точность свёрточной сети с хорошим исполнением и находками, в разы ускоряющими процесс распознавания. Эта система будет работать относительно быстро (на графическом процессоре) при условии, что у нас есть много данных для обучения модели.
В сущности, мы ищем самое простое решение, которое приведёт к желаемому результату, требуя при этом наименьшее количество данных для обучения; кроме того, мы не стремимся задействовать новейший алгоритм. Тем не менее в нашем случае разумный выбор — Mask R-CNN, несмотря на её очевидную помпезность и новизну.
Архитектура Mask R-CNN спроектирована так, что очень эффективно, с вычислительной точки зрения, распознаёт объекты на всём изображении. Словом, она работает быстро. На современном графическом процессоре система способна распознавать объекты на видео в высоком разрешении, обрабатывая несколько кадров в секунду. Должно хватить.
К тому же Mask R-CNN выдаёт различную информацию об обнаруженных объектах. Большинство алгоритмов распознавания на выходе дают лишь рамку, помечающую объект. А Mask R-CNN не только укажет на расположение каждого, но и сделает контур (или маску).
Для обучения Mask R-CNN нужно много изображений с предметами, которые мы собираемся распознавать. Можно выйти на улицу, поснимать машины и затем разметить фотографии, но это займёт как минимум пару дней. К счастью, немало людей связаны с распознаванием автомобилей, поэтому существует несколько открытых баз данных с нужными снимками.
Так, в базе COCO целых 12 тысяч изображений с машинами, на которые наложены маски. Вот она-то нам и подходит лучше всего.
А так как многие работают с моделями для распознавания, опираясь именно на COCO, в открытом доступе есть и обученные сети. Поэтому, вместо того чтобы заниматься обучением самостоятельно, я могу пустить в ход модель, которая может распознавать машины сразу после установки. В этом проекте мы задействуем реализацию Mask R-CNN от Matterport.
Сразу после установки модель распознаёт на изображении с камеры объекты, заданные в COCO по умолчанию:
Как видно, модель обнаружила не только машины, но и светофоры и людей. Забавно, что дерево система определила как «растение в горшке».
У каждого объекта теперь есть четыре маркера:
- Тип объекта. Модель, обученная на данных COCO, может распознавать 80 типов часто встречающихся объектов вроде машин или грузовиков. Полный список.
- Точность распознавания. Чем выше показатель, тем увереннее модель в том, что она не ошиблась, распознавая предмет.
- Двумерная рамка объекта.
- Растровая маска, указывающая, какие пиксели внутри рамки принадлежат собственно объекту. Данными маски позволяют выделить и контур объекта.
Ниже — код для определения рамок машин на основе задействованной нами модели от Matterport вместе с библиотекой OpenCV.
Запустив скрипт, вы получите изображение, на котором каждая распознанная машина отмечена зелёной рамкой.
Вы также получите координаты пикселей каждой машины:
Итак, мы распознали машины на изображении. Перейдём к следующему шагу.
Распознаём свободные парковочные места
Теперь мы знаем расположение пикселей каждой машины на изображении. И, глядя на несколько кадров подряд, мы с лёгкостью можем выяснить, какие машины стоят на месте, одновременно предположив, что под ними — места для парковки. Но как определить, когда машина покидает его?
Проблема в следующем: рамки машин на изображении частично пересекаются.
Если допустить, что каждая из этих рамок представляет место для парковки, может получиться так, что соседняя машина частично входит в рамку, даже когда место пустует. Поэтому нам нужно измерить пересечение двух объектов, чтобы отделить «по большей части пустые» рамки.
Величина, которую мы задействуем, называется пересечение над соединением (IoU); её значение равно числу пикселей в области пересечения двух объектов, поделённому на количество пикселей, занятых этими объектами.
Так мы узнаем, насколько велико пересечение рамки места для парковки рамкой автомобиля. Получив это значение, не составит труда определить, занято ли место. Если показатель мал, машина едва ли занимает парковочное место, наоборот — автомобиль занимает его большую часть, поэтому можно с уверенностью сказать: место занято.
А так как пересечение над соединением довольно часто используется в компьютерном зрении, оно будет реализовано в библиотеках, которые вы используйте. И действительно, библиотека Mask R-CNN содержит функцию mrcnn.utils.compute_overlaps(), поэтому можно просто положиться на неё.
Получив набор рамок, обозначающих парковочные места, очень легко узнать, есть ли внутри них машины:
Результат выглядит вот так:
В этом двумерном массиве каждый ряд обозначает одну из рамок места для стоянки, а каждая колонка — насколько сильно машины её пересекают. Если показатель равен единице, машина занимает участок полностью, если, например, 0,02 — машина только касается его.
Чтобы отделить незанятые места, нужно лишь проверить каждый ряд в массиве. Если все показатели равны нулю или очень малы, место с большой вероятностью не занято.
Помните, однако, что с потоковым видео распознавание не всегда работает хорошо. Несмотря на высокую точность Mask R-CNN, система время от времени упускает одну-две машины в кадре. Поэтому, перед тем как отмечать парковочное место пустым, нужно убедиться, что оно остаётся таким на протяжении небольшого промежутка времени. Хватит 5–10 кадров подряд.
Это не даст системе ошибиться со свободным местом после сбоя на одном кадре. Но как только становится ясным, что хотя бы одно место не занято в течение нескольких кадров, можно отправлять сообщение.
Отправляем уведомление
Последний шаг в цепочке — отправка SMS-сообщения.Тут на помощь приходит Twilio, популярный API, позволяющий отправлять SMS-сообщения едва ли не с любого языка программирования.
Разумеется, если вы предпочитаете другой сервис, можете использовать его. Просто мне Twilio первым приходит в голову.
Чтобы подключить Twilio, создайте пробную учётную запись и номер телефона, а также получите данные вашего аккаунта. Затем нужно установить клиентскую библиотеку:
А вот весь код на Python, необходимый для отправки сообщения (просто замените значения данными своей учётной записи):
Чтобы добавить эту опцию в скрипт, просто загрузите в него этот код. Сейчас, однако, система будет отправлять сообщения для каждого нового кадра, где место остаётся свободным. Чтобы избежать этого, установим метку, отслеживающую, отправлено ли сообщение, и проследим, что новое уведомление будет отправлено либо спустя какое-то время, либо пока не появится другое незанятое место.
Сборка
Соберём всё в один Python-скрипт. Полный код:
Чтобы его запустить, нужно сначала установить Python 3.6+, Matterport Mask R-CNN и OpenCV. Отмечу: я нарочно держал код максимально «голым». Так, предполагается, что все машины в первом кадре припаркованы.
Не бойтесь подстраивать код под разные ситуации. Заменив идентификаторы объектов, вы найдёте коду совершенно иное применение.
Представьте, что вы работаете на горнолыжном курорте. Пара поправок, и система будет самостоятельно распознавать вылетающих на рампе сноубордистов и делать серии снимков хороших прыжков. А если вы работаете в охотничьем заповеднике, можно сделать так, чтобы система считала пробегающих зебр. Веселитесь!
Чо он врет? Нет у него никаких друзей!
Я конечно дилетант, но если решать исключительно его локальную задачу, с данного ракурса проще было отслеживать сегмент видимого бардюра у тротуара и не заморачиваться на контурах машин и сложных алгоритмах. Но так бывает, хочется иногда пожарить яичницу с помощью лазера...
Ответ в самом тексте. Ручная оптимизация под текущую картинку уничтожит саму идею проекта.
В данной постановке можно включить камеру, направить ее на любой нужный участок и через день-два она начнет работать сама. А твоя система будет работать только там, где камера смотрит на бордюр. Другими словами эта система без переделок будет работать дома, в офисе, при смене работы или переезде фирмы, при пересадке внутри офиса, у друзей или на съемной квартире подружки, а твоя система потребует каждый раз полной переделки...
По хорошему система должна давать информацию по запросу о кол-ве свободных мест в данный момент (например, стоит ли вообще заезжать во двор, чтобы припарковаться). А ещё давать статистику в какое время больше парковочных мест. Можно спланировать своё рабочее время, исходя из этих данных.
Сомнительная история в плане выгоды, т.к. между получением СМС, реакцией на него и реальной возможностью занять парковочное место слишком большой промежуток времени. Обычно в плотной линии парковки если кто-то сваливает то не проходит и минуты чтобы не заехал другой водитель.
Просто смотри, сколько там свободных мест. Если одно, глупо на это расчитывать, но если их пять - вполне.
Хорошая штука. Перспективная.
Можно, например, отслеживать появление первого круассана в пекарне напротив, или почтальона...
Я в восторге!