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

    Привет, хабровчане! В 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
    • Обращайте внимание на то, в каких единицах выставляются отступы/размеры элементов (относительных или абсолютных).
    • Помните, что относительные и абсолютные единицы можно использовать вместе (их значения просто просуммируются).
    • Параметр
      .attributes("-fullscreen", True)
      позволяет сделать однооконное приложение, разворачивающееся на весь экран, чтобы не смущать пользователей элементами интерфейса системы.

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

    image

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


    • Устройство
      На экран выводятся карточки устройств с указанием версии операционной системы, названия и ID устройства, а также пользователя, на котором это устройство сейчас зарегистрировано.
    • Фотофиксирование
      Справа находится блок управления, где выводится изображение с веб-камеры, а также кнопки для регистрации и редактирования персональной информации.

      Изображение выводим, чтобы дать пользователю обратную связь — ты точно попал в экран меткой устройства.
    • Выбор версии ОС
      Мы сделали список с выбором интересующей версии ОС, т.к. часто для тестирования нужен не конкретный девайс, а определенная версия Android или iOS. Фильтр версий сделан горизонтальным, чтобы сэкономить место и чтобы список версий был доступен без прокрутки, на одном экране.

    Оптимизация


    Один проход любого компонента системы не занимает слишком много времени. Однако, если запустить распознавание маркеров и лиц одновременно, то попытка распознать все 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

    • +23
    • 6,6k
    • 2
    True Engineering
    72,00
    Специалисты по цифровой трансформации бизнеса
    Поделиться публикацией

    Комментарии 2

      0
      Galaxy A3 на iOS 6.1 смотрится немного странно. Особенно в этом контексте.
        0
        Как известно — нет ничего более постоянного, чем временное =)
        Видимо, при печати — ошиблись и записали не ту версию ОС, потом зачеркнули временно, с намерением потом перепечатать… да так и прижилось…

        Слава богу, теперь такой проблемы не возникает и изменения вносятся сильно проще.

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

      Самое читаемое