Компьютерное зрение как альтернатива офисным пропускам
Сегодня я расскажу, как мы делали в офисе пропускную систему на основе сервиса распознавания лиц Vision. Сначала небольшая предыстория. Как в любом почтовом сервисе, мы создали систему антиспама. Такие системы сейчас делаются на основе машинного обучения, у нас им занимается мощная команда. А где машинное обучение, там и компьютерное зрение. Поэтому сервис Vision возник вполне органично и естественно.
Параллельно с этим несколько лет назад мы запустили Облако — надёжное хранилище файлов с геораспределением по дата-центрам, которым могут пользоваться как частные лица, так и компании. Со временем у нас появилось «Облако для бизнеса», которое не только хранит файлы, но и позволяет заказывать виртуальные машины. Постепенно это превратилось в MCS — Mail.ru Cloud Solutions, куда в качестве одного из сервисов очень органично вписался Vision.
Наши нейросети способны распознавать далеко не только лица, но и разные предметы, объекты и сцены, в том числе достопримечательности. Сейчас они могут распознавать около 10 тыс. категорий, и машинное зрение иной раз работает лучше человеческого.
Это моя дочь в 2012-м, в 2015-м и 2018-м. Если бы я не знал ее лично, то, наверное, не сразу понял, что это один и тот же человек. А нейронная сеть смогла сопоставить и понять.
Здесь девочка отвернулась и прищурилась, а мальчик вообще в фуражке с тенью на половину лица. Но при этом нейронная сеть точно их распознала, даже несмотря на такие сложные условия. Естественно, что технология, которая развивается внутри компании, не могла не найти поддержку во внутренних сервисах.
Наш интранет называется sys. Это своего рода социальная сеть (у нас же их мало). В ней сотрудники выкладывают фотографии с разных мероприятий.
Когда с мероприятия выкладывается несколько сотен фотографий, то найти себя там достаточно сложно. Поэтому у нас к этим альбомам подключено машинное зрение, которое прямо в интранете, в едином месте показывает фотографии, на которых я изображён. Вот тут система меня увидела на одном из летних корпоративов.
Нейросеть распознала меня даже в полумраке в профиль, и на фотографии ещё множество людей.
Позднее мы сделали стойки для конференций. Я писал софт для iPad, который установлен внутри стойки, но вообще я iOS-разработчик и к компьютерному зрению никакого отношения не имею, просто по-дружески помогаю.
В чем суть этой стойки? В течение всего мероприятия — митапа, конференции, корпоратива, да хоть дня рождения — вас фотографирует фотограф. Он время от времени сбрасывает накопившиеся снимки в Облако. Вы в любой момент можете подойти к стойке, сфотографироваться и нажать на кнопку «Найти меня». И стойка либо сразу выведет все фотографии, на которых вы запечатлены, либо скажет, что пока ничего не найдено, если система еще не успела проиндексировать снимки, и предложит ввести e-mail. И после мероприятия вам на почту придёт ссылка на папку в Облаке со всеми фотографиями, на которых вы есть. Это одно из применений сервиса Vision.
Естественно, такие возможности по распознаванию лиц захотелось использовать не только для поисков своей физиономии на снимках с корпоративов, но и для чего-то более практичного. Например, для автоматической пропускной системы. Прикладывать пропуск при каждом входе на свой этаж не очень удобно: пропуск часто забываешь, а девушкам летом в лёгкой одежде пропуск даже некуда крепить.
Поэтому мы решили поэкспериментировать. Для этого у нас есть все условия: не нужно ни у кого просить разрешения, очень отзывчивый административный отдел, который со вздохом говорит: «Ладно. Прикрепляйте свои камеры. Только не на дверь. Двери относятся к пожарной безопасности». Мы такие: «Ну ладно. Мы сбоку прикрепим». А ещё у нас терпеливые коллеги, они от нас натерпелись.
На первый взгляд, архитектура пропускной системы видится очень простой: камера снимает, отправляет в Vision, а Vision открывает дверь. Но когда мы начали расписывать с коллегами, как же это на самом деле сделать, то получилась вот такая схема:
Блок справа мы называем «камерой» — это модуль, который висит на двери. Он состоит из трёх частей. Raspberry Pi принимает видеосигнал с USB-камеры, кодирует с помощью FFmpeg и отправляет. Мы протестировали несколько IP-камер разумного ценового диапазона, и у всех оказалась ощутимая задержка примерно в 0,5 с. А поскольку у нас есть задержки и на других этапах, то когда человек подходит, смотрит в камеру и в течение нескольких секунд ничего не происходит, ему уже хочется приложить пропуск. Поэтому мы сокращали задержки, где только возможно, и Raspberry Pi c USB-камерой оказалась быстрее, чем многие коммерческие IP-камеры. Также к Raspberry подключена маленькая Arduino с разноцветным светодиодом и пищалкой. Светодиод по умолчанию светится красным. Когда человек подходит и распознан, загорается зеленый.
Итак, Raspberry Pi передаёт видеопоток, который по проводному Ethernet попадает в серверную. У нас на каждом этаже есть серверная, в которой стоят свичи, коммутирующие кабели к столам сотрудников, и штатная СКУД — система контроля и управления доступом.
Мы поставили в серверной ещё одну Raspberry Pi, которая получает видеопоток в реальном времени и прогоняет его через OpenCV. Зачем нам еще OpenCV? Нам нужно определить, есть ли на картинке лицо. Нейронная сеть, которая определяет человека на фотографии, работает чуть-чуть дольше, и постоянно скармливать ей поток видеоданных слишком затратно. Поэтому мы через OpenCV определяем наличие лица, и если оно появилось, тогда отправляем в Vision. Сервис либо отвечает, что не нашел этого сотрудника, либо отправляет идентификатор сотрудника в базе данных HR. С этим идентификатором сотрудника мы идем в интранет, который завязан со СКУД, и он возвращает нам идентификатор пропуска. Дальше этот идентификатор пропуска мы закидываем в Arduino, которая передаёт его в СКУД. Для системы контроля доступа это равносильно тому, что человек приложил пропуск. То есть мы никак не изменяем СКУД, она по-прежнему журналирует вход и выход сотрудников.
Как мы интегрировали свою систему со СКУД? У нас в офисе применяются устройства Bolid C2000–2.
Это отечественная система контроля доступа. К этим приборам, скорее всего, можно подключаться через 485-й интерфейс, но мы подключились через протокол Wiegand.
К считывателю пропусков, установленному рядом с дверью, мы подключили Arduino, который выступает в роли прокси.
На фото показано подключение питания и двух линий данных от считывателя пропусков. Колодка используется для более удобного подключения.
Arduino получает номер пропуска либо от считывателя, либо от Raspberry Pi по USB, и отдаёт его в СКУД. СКУД даже не знает, откуда получен номер пропуска.
Это стандартный протокол для СКУД, он поддерживается большинством считывателей. Протокол очень простой: две линии данных, одна линия нулей и одна линия единиц. Как только вы подключаете к земле нулевую линию, считывающее устройство понимает, что передан ноль, тоже самое с единицами. То есть у протокола нет стандартизированных таймингов, и номер пропуска легко считывать через прерывание на Arduino, легко представлять в виде последовательности данных. А поскольку для записи нужен какой-то тайминг, я ориентировался на эти значения:
Для Arduino уже есть готовая библиотека. Она умеет считывать разные форматы Wiegand, но этим её возможности ограничиваются. А мне нужно было еще передавать. Поэтому я написал свою библиотеку, которая работает только с форматом Wiegand-26. 26 — это количество бит: 3 байта номера пропуска и 2 бита чётности. Причем во всех документациях и статьях написано, что, вероятнее всего, ваш современный контроллер будет игнорировать биты чётности, поэтому я ленюсь и их не считаю, а всегда отправляю ноль. СКУД это нормально воспринимает.
У была такая проблема. Если кто-то сначала показался перед камерой, а затем, не дождавшись срабатывания, приложил пропуск, то возникала ситуация гонки: одновременно приходил номер пропуска от считывателя и от распознавания. СКУД с этим не справлялась и не пускала человека. Поэтому пришлось добавить в библиотеку кольцевой буфер на 4 кода. Откуда бы коды ни пришли, они помещаются в буфер, а затем с таймаутом в 0,5 с передаются в СКУД. С тех пор коллеги перестали жаловаться на то, что их не пускают.
Первый прототип был собран из чего попало. На какой-то нелепой стойке висела Raspberry Pi в коробке, а сверху на двухсторонний скотч приклеена камера. Сбоку на стяжках висит Arduino. В общем, всё, как мы любим, очень DIYненько.
Конечно, в таком виде оставлять было нельзя, нужно было оформить красиво. Мы переговорили с несколькими подрядчиками, они нам пообещали заказать образцы в Китае, но потом все оговоренные сроки прошли, а нам так никто ничего и не предложил.
У кастомными продуктов есть одна проблема — все решения узкоспециализированные, они делались бы специально под нас. Во-первых, мы становимся зависимыми от поставщика. Во-вторых, получается уникальная схемотехника с малым тиражом, а значит, стоимость одной штуки будет высокой. В-третьих, достаточно большой срок изготовления, и если какой-то экземпляр выйдет из строя, мы не сможем быстро купить в магазине замену, придётся ждать изготовления следующего тиража, а если сразу делать с запасом, то оставшиеся экземпляры будут пылиться на складе.
После того, как все потенциальные партнёры нас подвели, я пришёл к коллеге из Vision и говорю: «Володя, давай я тебе на 3D-принтере напечатаю корпус, чтобы это красиво выглядело». Он вздохнул и сказал: «Ну давай. Что делать?»
Я во Fusion нарисовал вот такое чудовище Франкенштейна. В углу должна была размещаться Raspberry Pi со входом под Ethernet-кабель. Сбоку вход под питание. «Вторым этажом» ставилась камера. Получилась крупная конструкция, и я её даже напечатал тонким слоем, чтобы не тратить много пластика. Выглядело ужасно, и вешать это было ещё более стыдно.
К тому же коллега прислал мне вот такой референс, мол, нам бы такое. Я ответил, что не смогу так сделать, но решил спроектировать другой корпус.
Новый корпус был диаметром 11 см, меньше компакт-диска. Размещение начинки тоже двухслойное. Ещё напечатав первую версию, я понял, что нет никакого смысла ставить USB-камеру целиком в родном корпусе. Разобрал её аккуратно, и оказалось, что у нее есть 4 посадочных отверстия на лицевой панели. Эту панель с камерой я объединил в общую сборку с пищалкой и светодиодом.
Сначала мы попробовали сгенерировать писк на Raspberry Pi через gpio. Получилось крайне плохо. Поэтому решили вынести эту функцию отдельно от Raspberry Pi, подключив маленькую ардуино (на самом деле Iskra mini), к которой были припаяны пищалка и светодиод, через TTL прямо к колодке.
Вот так это выглядело в бою:
Мы повесили устройство на этаже. В таком виде оно прожило достаточно долго. Пищало, красиво светилось, открывало дверь, правда, не каждый раз. Коллеги, правда, жаловались, что светодиод слишком яркий. Пришлось его ослабить раза в 4.
Затем сделали такой вариант:
Он был навеян дизайном хаба Xiaomi, со светящимся кольцом по периметру. Очень красиво выглядит. Логотип Vision сделан отдельными деталями, напечатанными пластиками разного цвета. Вот модель:
В этот раз я убрал пищалку на заднюю стенку, вмонтировал светодиод в прозрачное колечко по периметру, напечатанное из прозрачного PLA. Декор почти сразу провалился внутрь, потому что изначально был просто вставлен на трении, и пришлось сажать его на клей.
У нас была мысль растиражировать это решение по всему зданию. Но есть проблема: почти на всех этажах по две двери, и у каждой должно быть две камеры, всего 96 камер только для одной из наших башен, а сейчас идет активное освоение второй. Распечатать столько корпусов можно, но уже кажется сложным. Кроме того, у нас достаточно много компонентов в устройстве, а значит, много точек отказа. Если масштабировать решение на всё здание, мы будем постоянно обслуживать эти камеры. Опять же, сложность быстрой замены, ведь каждая камера — это штучное устройство. И нужно либо распечатать их много, с запасом, либо, если что-то случилось, то сразу бежать, печатать и собирать новую. Мы поняли, что DIY-решения — это классно, но нужно что-то более удобное в тиражировании. И возникла идея перенести всё на iPad.
Айпад
У iPad есть несколько преимуществ. Во-первых, экран. Коллеги жаловались на отсутствие обратной связи, они подходят и не понимают, началось распознавание или нет, ждать им или не ждать.
Во-вторых, в iOS есть встроенная функция распознавания лица. Функцию, которую выполняла OpenCV, мы передали iPad. На экране отображается рамка, и человек должен подойти на такое расстояние, чтобы лицо помещалось в эту рамку. После этого система начинает автоматически его распознавать, ничего нажимать не надо.
В-третьих, iPad — это массовый продукт. Если он вышел из строя, мы ставим другой. Хотя сам планшет стоит около 20 тыс. рублей, то это всё равно дешевле кастомных камер, которые нам предлагали партнеры. К тому же быстрее и надёжнее.
iPad взял на себя большую часть функций. На Raspberry Pi, который стоит в серверной, фактически остается только HTTP-хост, который принимает GET-запрос с ID пропуска. Он тут же проксирует код в Arduino, а та проксирует в СКУД.
В первом варианте Raspberry Pi была очень нагружена, потому что на ней постоянно работал OpenCV. К ней было уже не подключить вторую камеру, не хватило бы вычислительной мощности. Мы уже думали о том, что надо ставить туда честный компьютер, который парсил бы 4 потока от двух дверей. Но до этого не дошло. Сейчас поиск лица на изображении выполняется независимо на каждом айпаде. В кроссовой остаются две Arduino, по одной на каждую дверь. Обе платы работают с пропусками на вход и на выход. Почему важно работать с пропусками на вход и на выход. Во-первых, когда лицо распознано и дверь открывается, на считывателе карт загорается зеленая лампочка, и коллегам понятно, что можно выходить. Во-вторых, СКУД логирует входы и выходы. Эмулируя вход и выход раздельно, мы не ломаем схему работы СКУД.
Естественно, подтянулись дизайнеры, которые нарисовали нам красивый интерфейс. Мы еще не вешали iPad на дверь, пока это пилотный проект, а применяем готовые стойки Vision.
Несмотря на то, что MCS — это бизнес-продукт, его могут использовать и любители. Сервис предлагает каждому 5 тыс. бесплатных транзакций в месяц, то есть 166 в день. Поэтому вы можете применять для своих домашних нужд, если укладываетесь в лимит, конечно же. Как это можно сделать?
python examples/python/smarty.py \
-u
"https://smarty.mail.ru/api/v1/persons/recognize
?oauth_provider=mcs&oauth_token=e50b000614a371ce
99c01a80a4558d8ed93b313737363830" \
-p friends1.jpg \
--meta '{"space":"1", "create_new":true}' \
-v
Возьмём фотографию и отправим в Vision вместе с нашим токеном доступа. Укажем, что работаем с первым спейсом, и зададим create_new
— тогда под каждое незнакомое лицо система будет создавать новый идентификатор. Вот что получаем в ответ:
{ "status":200, "body":{ "objects": [ { "status":0, "name":"file_0", "persons":[
{"tag":"person1","coord":[102,30,184,134],"confidence":0.99999,"awesomeness":0.5025},
{"tag":"person2","coord":[393,74,461,166],"confidence":0.99987,"awesomeness":0.548},
{"tag":"person3","coord":[458,48,535,149],"confidence":0.99976,"awesomeness":0.4766},
{"tag":"person4","coord":[273,45,352,147],"confidence":0.99963,"awesomeness":0.504},
{"tag":"person5","coord":[525,81,600,184],"confidence":0.99954,"awesomeness":0.4849},
{"tag":"person6","coord":[194,76,258,167],"confidence":0.9984,"awesomeness":0.5725}
] } ], "aliases_changed":false }, "htmlencoded":false, "last_modified":0 }
Я немного отформатировал JSON. В ответе содержится идентификатор человека, координаты лица на фотографии и два параметра: насколько хорошо распознано лицо и насколько этот человек соответствует эталону. Можете на своём языке программирования отправить POST-запрос с картиной, получить JSON и распарсить ответ.
Если у вас большая проходимость, а нужно определять всего десяток человек, вы можете задать их вручную. Тогда система будет на знакомых людей выдавать их идентификаторы, а на незнакомых — undefined. Людей можно и выборочно удалять, например, если сотрудник уволился.
В каких проектах вы можете использовать распознавание лиц? Если захотите реализовать пропускную систему, придётся озаботиться антиспуфингом. Например, добавив инфракрасную камеру, чтобы определять, фотография это или живой человек. Или поставив две камеры для определения глубины объекта, это можно сделать с помощью OpenCV.
Можно организовать распознавание людей в подъезде. Если это ваши соседи, то всё в порядке, а если кто-то посторонний, то можно отсылать себе оповещение. У нас в доме есть такая проблема, периодически приходят посторонние и оставляют после себя много мусора на лестничной площадке.
Если вы сделаете «умное зеркало», то можно оснастить его и распознаванием членов семьи, чтобы каждому показывать то, что ему интересно. Скажем, мне зеркало покажет график встреч на сегодня, а с дочерью весело поздоровается и предложит почистить зубы, причём не быстро, как обычно, а две минуты.
Ещё идея — распознавание автомобильного номера автоматическими воротами на даче. Чтобы не выходить или не нажимать брелок, можете поставить камеру, которая снимет ваш номер, и ворота откроются автоматически.