Хабрахабр

Как распознавание лиц помогает находить тестовые телефоны

Привет, хабровчане! В EastBanc Technologies ведётся большое количество проектов, связанных с мобильной разработкой. В связи с чем необходим целый зоопарк устройств для тестирования на всех этапах. И, что характерно, каждый отдельный девайс постоянно оказывается нужен самым разным людям, а найти его даже в одном отделе мобильной разработки из нескольких десятков человек — это целая история. Не говоря уже о том, что есть тестировщики, дизайнеры, PM’ы, в конце концов!

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

image

Исторический контекст

У нас была доска с «карточками» устройств с основной информацией и местом под магнитик, обозначающим сотрудника. Каждый отмечался о взятии устройства.

image

Эта система имеет свои недостатки — не критичные, но в целом неудобные:

  • Магнитики не так легко переместить с одного места на другое.
  • Чтобы посмотреть на такую доску, обязательно придётся идти в другой кабинет.
  • А ещё кому-то может понадобиться сразу много устройств… А значит, нужно несколько магнитиков на одного сотрудника.
  • Ах да, ещё сотрудники иногда увольняются и приходят новые, на которых тоже нужно сделать магнитики.

Мобильное приложение

В компании, которая занимается автоматизацией бизнес-процессов, использовать описанное выше «аналоговое» решение — не очень здорово. Естественно, мы решили автоматизировать задачу поиска нужного устройства. Первым шагом стало написание мобильного приложения, которое умеет определять и сообщать о своем местоположении в комнатах по Wi-Fi точкам доступа. Попутно для удобства наделили девайсы умением сообщать на сервер о версии ОС, а также показывать такую важную характеристику, как заряд батареи.

Смотришь на список в базе данных, где последний раз устройство видело Wi-Fi, идёшь туда и… Казалось бы, задача решена.

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

Спасибо, капитан! Устройства разряжаются, просто выключаются, точки доступа Wi-Fi переставляются из одного места в другое, а геолокация сама по себе говорит только о том, что устройство находится в офисе.

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

Как мы хотели, чтобы это было

Мы придумали концепт системы, которая бы распознавала сотрудников по лицам, тестовые устройства — по специальным меткам, запрашивала бы подтверждение смены статуса устройства, а потом вносила изменения в онлайн-базу, которую любой сотрудник может посмотреть, не вставая с кресла.

Распознавание лиц

Распознавание лиц в целом решенная задача в 2018 году. Поэтому мы не стали изобретать велосипед и пытаться обучать собственные модели, а воспользовались готовым решением. Самым удобным вариантом показался модуль FaceRecognition, т.к. он не требует дообучения и работает весьма быстро даже без ускорения на GPU.

С помощью функции face_locations на фотографиях сотрудников обнаруживались лица, а с помощью face_encodings из них извлекались признаки лица конкретного сотрудника.

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

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

Код распознавания лиц

face_locations = face_recognition.face_locations(rgb_small_frame)
face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations) face_names = []
for face_encoding in face_encodings: matches = face_recognition.face_distance( known_face_encodings, face_encoding) name = "Unknown" if np.min(matches) <= 0.45: best_match_index = np.argmin(matches) name = known_face_info[str(best_match_index)]['name'] else: best_match_index = None

Распознавание устройств

Изначально возникла мысль использовать для распознавания устройств QR-коды, в которые вносить заодно и информацию об устройстве. Однако для устойчивого распознавания QR-кода его приходилось подносить очень близко к камере, что неудобно.

Они несут меньше информации, зато гораздо более устойчиво распознаются. В результате возникла мысль об использовании маркеров дополненной реальности. В ходе экспериментов маркер размером в 30 миллиметров распознавался камерой при небольших отклонениях от вертикали (3-5 градусов) на расстоянии до двух с половиной метров.

Из всего множества маркеров дополненной реальности были выбраны ARuco, т.к. Такой вариант выглядел уже куда лучше. все необходимые инструменты для работы с ними присутствуют в поставке opencv-contrib-python.

Код распознавания маркеров ARuco

self.video_capture = cv2.VideoCapture(0)
ret, frame = self.video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
markers = cv2.aruco.detectMarkers(gray, self.dictionary)

В итоге, каждому устройству был присвоен числовой индекс, с которым сопоставлялся и маркер с этим индексом.

Дело в шляпе?

Казалось бы, мы научились распознавать устройства и лица, работа сделана. Фанфары, овации! Что ещё может быть нужно?

Теперь все компоненты системы нужно заставить стабильно и быстро работать «на бою». На самом деле, работа только начинается.

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

Интерфейс

Едва ли не самым важным пунктом в разработке подобных систем является интерфейс. Кто-то возможно будет спорить, но пользователь — центральный элемент в такой ситуации.

Максимально быстро можно реализовать фронтенд-часть с помощью Tkinter.

Несколько замечаний о Tkinter

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

image

Вот ключевые компоненты интерфейса:

Оптимизация

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

При этом понятно, что 99 % времени система будет производить эту работу вхолостую.

Чтобы этого избежать, были приняты следующие оптимизационные решения:

  1. В обработку подаётся лишь каждый восьмой кадр.

    Код

    if self.lastseen + self.rec_threshold > time.time() or self.frame_number != 8: ret, frame = self.video_capture.read() self.frame_number += 1 if self.frame_number > 8: self.frame_number = 8 return frame, None, None, None

    Задержка реакции системы повышается примерно до 8/30 секунды, при этом время реакции человека — примерно одна секунда. Соответственно, такая задержка всё ещё не будет заметной для пользователя. А мы уже в восемь раз снизили нагрузку на систему.

  2. Сначала в кадре ищется маркер устройства, и лишь при его обнаружении запускается распознавание лиц. Так как поиск маркеров в кадре примерно в 300 раз менее затратен, чем поиск лиц, мы решили, что в режиме ожидания будем проверять только наличие маркера.
  3. Чтобы уменьшить «тормоза» при поиске лиц, когда лиц на изображении нет, в функции face_locations был отключен параметр number_of_time_to_upsample.

    face_locations = face_recognition.face_locations(rgb_small_frame, number_of_times_to_upsample=0)

    Благодаря этому время обработки кадра, на котором нет лиц, сравнялось со временем обработки кадра, где лица легко обнаруживаются.

Что в итоге?

На текущий момент, система успешно развернута на подвернувшемся под руку MacMini Late 2009, на двух ядрах Core 2 Duo. В рамках тестирования, она вполне успешно работала даже на одном виртуальном ядре с 1024 мегабайтами оперативной и 4 гигабайтами постоянной памяти в контейнере Docker. К MacMini подключили сенсорный дисплей, чтобы внешний вид стал минималистичным.

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

Что дальше?

В текущей системе, несомненно, ещё много моментов, которые можно и хочется улучшить:

  • Сделать так, чтобы элементы управления ОС не проявлялись при появлении диалоговых окон (сейчас это messagebox из пакета Tkinter).
  • Разнести вычисления и запросы к серверу в разные потоки с обработкой интерфейса (сейчас они выполняются в основном потоке, mainloop Tkinter’а, что замораживает интерфейс в момент отправки запросов в онлайн-базу).
  • Привести интерфейс к одному дизайну с другими корпоративными ресурсами.
  • Сделать полноценный веб-интерфейс для удаленного просмотра данных.
  • Использовать распознавание голоса для подтверждения/отмены действий и заполнения текстовых полей.
  • Реализовать регистрацию нескольких устройств одновременно.

P.S. А вот так это работает
Видео записано на бета-версии GUI

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть