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

С каждым годом расширяется область применения таких систем. Например, пользователи могут приобрести у Google систему Nest — Nest Cam IQ Indoor, стоимостью 349 долларов с интеграцией в умный дом и возможностью распознавания лиц по подписке (за 10 долларов в месяц). И отечественных аналогов для частного пользования немало. Различные СКУД (системы контроля и управления доступом) от Ростелекома, HikVision, VisionLabs и других фирм. Описание зачастую мутное, опыт работы в реальных условиях можно найти на YouTube по запросу «Умный домофон не пускает мужчину домой».

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

Существует несколько методов реализации системы определения биометрических данных в реальном времени: анализ видеопотока на удаленном сервере, на камере с передачей данных на сервер, на локальном устройстве с подключенной камерой.

Наиболее распространена первая схема реализации. Работает она так: камера передает видеопоток на сервер, там специализированное ПО в реальном времени выполняет анализ видеопотока и сравнивает полученные изображения лиц с базой лиц эталонов. Недостатки такой системы — высокая нагрузка на сеть, ограничение по количеству подключенных камер на один сервер.

При применении 2 технологии, анализ изображения будет производится на самом устройстве — камере, а на сервер будут передаваться обработанные метаданные. Недостаток такой системы — очень высокая стоимость камер, способных обработать изображение. Зато можно подключить практически неограниченное количество устройств к удаленному серверу.

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

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

Вопреки расхожему мнению, алгоритмы распознавания лиц могут работать и на системах с небольшой вычислительной мощностью. Как например одноплатный микрокомпьютер Raspberry PI 4B с производительностью старого андройд смартфона. Именно такой микрокомпьютер с 4гб оперативной памяти и 4-ядерным процессором частотой 1.5 ГГц был использован в данном проекте.

В качестве алгоритма распознавания лиц была использована библиотека face-recognition для python. Эта библиотека работает с моделью распознавания лиц от dlib. Устанавливается достаточно просто (cv2 для отображения картинки с камеры):

pip install face-recognition, opencv-python

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

import face_recognition
import numpy as np
import cv2


# векторные представления лиц, имена, user_id в БД
known_face_encodings, known_face_names, known_face_uids = [], [], []

def run_rec():
    video_capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
    while video_capture.isOpened():
        # чтение кадра с камеры
        ret, frame = video_capture.read()
        # уменьшение разрешения (для быстродействия)
        divideint = 2
        small_frame = cv2.resize(frame, (0, 0), 
   fx=1 / divideint, fy=1 / divideint)
        # уменьшение размерности матрицы изображения, аналог [:, :, ::-1] 
        rgb_small_frame = cv2.cvtColor(small_frame, cv2.COLOR_BGR2RGB)
        # обрабатывается каждый 3й кадр (для быстродействия)
        if process_this_frame % 3 == 0:
            # расположение лиц
            face_locations = face_recognition.face_locations(rgb_small_frame)
            # преобразование лиц в векторы
            face_encodings = face_recognition.face_encodings(rgb_small_frame, 
  face_locations)
            # сравнение обнаруженных лиц с лицами в базе
            for face_encoding in face_encodings:
                name = "Unknown"
                # вычисление векторного расстояния (мера схожести векторов)
                # known_face_encodings - 
                face_distances = face_recognition.face_distance(known_face_encodings, face_encoding)
                # определение индекса максимально похожего лица
                best_match_index = np.argmin(face_distances)
                # проверка на степень похожести 
                # похожи если векторное расстояние расстояние меньше 0.6
                if face_distances[best_match_index] < 0.6:
                    # имя обнаруженного лица для пользователя
                    name = known_face_names[best_match_index]
                    # user_id лица для внутреннего использования
                    uid = known_face_uids[best_match_index]

Тестирование системы производилось на базе данных ORL, содержащей изображения лиц с небольшими изменениями освещения, масштаба, пространственных поворотов, положения и различными эмоциями. База представляет собой 400 фотографий 40 разных людей. Все фото представлены в градации серого.

Обычно эта база используется для обучения алгоритмов распознавания лиц, но я решил проверить качество работы и быстродействие алгоритма на основе face-recognition. В результате, алгоритм, работающий на Raspberry PI 4B смог обнаружить 376 лиц за 7 секунд.

import os
import glob
import face_recognition
import time


start = time.time()
faces_folder_path = './orl_faces'
cnt = 0

for f in glob.glob(os.path.join(faces_folder_path, "*.jpg")):
    print("Processing file: {}".format(f))
    #загрузка фото
    img = face_recognition.load_image_file(f)
    #обнаружение лица на фотро
    face_locations = face_recognition.face_locations(img)
    #подсчет
    # face_locations - список элементов (лиц)
    # в списке столько элементов, сколько лиц на фото
    print("Number of myfaces detected: {}".format(len(face_locations)))
    if len(face_locations) != 0: 
        cnt += 1

print(f'total myfaces detected {cnt}')
print(f'total seconds spent {int(time.time() - start)}')

Так, например, компьютер на процессоре Intel Core I5 смог обнаружить те-же 376 лиц примерно за 2 секунды.

Но показатели этого теста можно рассматривать только в контексте скорости обнаружения лица в кадре. Неотъемлемой частью алгоритма распознавания лиц является сравнение лица в кадре с лицами в базе системы. Для этого необходимо преобразовать картинку в векторное представление и сравнить со всеми лицами в базе. К тому же, необходимо было организовать подключение к базе данных с постоянным обновлением данных в ней. Для управления базой данных была использована СУБД SQLite. Она отличается от других СУБД простотой настройки и удобством использования в малопроизводительных платформах, как Raspberry PI. Через постоянные обращения к базе и определяется принадлежность лица в объективе камеры системы к лицам, добавленным в систему как авторизованные пользователи; осуществляется логирование посещений. Эти части алгоритма (векторное преобразование, обращение к базе, сравнение обнаруженного лица с лицами в базе) и представляют собой самую ресурсоемкую его часть. Обращение к базе:

def get_db():
    conn = sqlite3.connect("face_db.sqlite3")
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM FRS")
    facecount = cursor.fetchall()

    known_face_encodings = []
    known_face_names = []
    known_face_uids = []
    face_in_home = []

    for i in range(len(facecount)):
        a = pickle.loads(facecount[i][5])
        known_face_encodings.append(a)
        known_face_names.append(facecount[i][1])
        known_face_uids.append(facecount[i][0])
        face_in_home.append(facecount[i][10])

    return known_face_encodings, 
known_face_names, 
known_face_uids, 
face_in_home, conn

Кроме обнаружения и сравнения лица с находящимися в базе пользователей, есть еще одна часть работы алгоритма. Для проверки работы системы распознавания лиц необходима графическая интерпретация. То есть, для того чтобы увидеть, правильно ли лицо распознается и обнаруживается, необходимо транслировать на экран устройства потоковое видео и обрисовывать в нем границы объекта, распознанного как лицо.

import numpy as np
import cv2

# запуск камеры
video_capture = cv2.video_capture(0, cx2.CAP_DSHOW)

# изменение размеров и имени окна для показа изображения
video_capture.set(3, 800)
video_capture.set(4, 448)
сv2.namedWindow('Video', cv2.WINDOW_NORMAL)
cv2.resizeWindow('Video', 800, 448)

# расположение краев прямоугольника, обозначающего лицо в кадре; имя
for (top, right, bottom, left), name in zip(face_locations, face_names):

    # рисуем прямоугольник вокруг лица
    cv2.rectangle(frame, (left, top), (right, bottom), (107, 168, 0), 2)

    # рисует плашку под текст с именем пользователя
    cv2.rectangle(frame, (left, bottom - 23), (right, bottom), (107, 168, 0), cv2.FILLED)
    cv2.putText(frame, name, (left + 6, bottom - 6), cv2.FONT_ITALIC, 0.5, (0, 0, 0), 1)
    
    # отображение состояния системы
    cv2.rectangle(frame, (8, 5), (228, 64), (255, 255, 255), cv2.FILLED)
    cv2.putText(frame, 'RECOGNITION IN PROGRESS', (10, 20), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 0), 2)
    cv2.putText(frame, 'Model: face-recognition', (10, 40), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 0), 2)

В реальных условиях, при работе с потоковым видео, при наличии лица в кадре, данный алгоритм показывал скорость в 1-2 обработанных кадра в секунду (обнаружение лица, сравнение с лицами – эталонами):

Без показа видео количество обработанных кадров поднялось до около-стабильных 2 FPS. Небольшое изменение, но очень важное в такой системе, реализуемой на одноплатном микрокомпьютере.

Поскольку проект позиционировался как домашняя система распознавания лиц, необходимо было реализовать удобный интерфейс управления и добавить некоторый функционал. Разработка любого приложения довольно ресурсоемкое занятие, требующее обширных знаний. Поэтому было принято решение вместо полноценного приложения создать чат-бота в мессенджере Телеграм с использованием библиотеки AioGram.

Бот находится на стадии MVP, но уже имеет достаточно разных функций для обеспечения автономной и относительно стабильной работы системы. В числе функций:

— включение/выключение функции распознавания лиц (для снижения нагрузки);

— создание и занесение в базу лиц через отправку фотографий чат-бота;

— проверка журнала посещения (только для пользователей, вручную добавленных в базу);

— получение фотографии с камеры системы распознавания в любой момент;

— ограничение доступа к функциям чат-бота неавторизованным пользователям.

Работа функций в чат-боте:

Включение, проверка состояния

Добавление лиц в базу

Проверка логов посещения

Получение фото с камеры

В заключении хочется сказать, что функционал системы по большому счету ограничен только воображением. И конечно же, навыками программирования. Несмотря на то, что мощность Raspberry ограничена, у неё очень много возможностей, вплоть до управления системой умного дома. Да, проект на данный момент далек от завершающей стадии, но уже можно с уверенностью сказать – домашняя система распознавания лиц возможна и на одноплатном микрокомпьютере.

Комментарии (4)


  1. ZlodeiBaal
    25.02.2022 18:57
    +2

    Как-то это слабовато даже для студенческого проекта.
    1) Вы используете Dlib распознавание лиц. Но сейчас 2022 год уже. Не надо так делать. Вот тут я чуть подробнее рассказываю почему так не надо — www.youtube.com/watch?v=2fnNhYCpToE и какие есть альтернативы (как детектор лиц на питоне я может быть даже MediaPipe посоветовал бы сейчас)
    2) Для тестирования вы используете… «ORL» — это база для тестирования лиц собранная с 1992 до 1994 года. Тогда не то что нейронных сетей не было, тогда ещё и Haar, HOG и половины алгоритмов классического CV не было. Тогда решались другие цели и задачи.
    (чб картинки полного размера которые смотрят в камеру — это не совсем того что вы хотите от датасета)
    3) Вы что-то говорите про скорость выполнения. Но не сравниваете с сотнями других современных подходов, которые умеют оптимизироваться под железо. И под RPi и под другие куда более дешевые железки. И вообще сейчас RPi странное решение для FaceRecognition. Например приведу пример Maixduino который с камерой выходит дешевле, а по производительности дешевле
    image
    А ещё есть ESP32 который формально тоже может распознавать. Там есть полный аналог чего вы сделали из коробки. Примерно за 5 баксов с камерой, примерно 5fps.
    Выбор RPi у вас абсолютно нелогичен:)
    4) Вы начинаете рассказывать про ошибки других систем, но не показываете проблемы/ошибки вашей системы/вашего подхода (dlib вы не сможете переобучить, занесение в базу будет иметь кучу ошибок, и.т.д.).


    1. gev
      26.02.2022 21:36

      Выбираю сейчас платформу для себя. Maixduino или ESP32 реально там использовать экран и передачу видео/аудио через WebRTC Full HD, Спасибо?


      1. ZlodeiBaal
        26.02.2022 21:51

        У ESP32 есть стриминг, но не WebRTC. Там что-то типа websocket — randomnerdtutorials.com/esp32-cam-video-streaming-web-server-camera-home-assistant Я слабо разбираюсь именно в реализациях стриминга, но мне кажется это не очень просто запихнуть.
        Экран там воткнуть некуда. Платы с микрофоном вроде есть.

        У Maixduino на k210 со стримингом, как мне кажется, такая же ситуация. Но зато есть куда экранчик воткнуть.

        Но есть второй MAIX — www.seeedstudio.com/Sipeed-MAIX-Dock-p-4815.html
        Сам его не тестил, но по докам там какой-то нормальный линукс, так что все должно быть проще.

        Но на мой взгляд надо все же отталкиваться от задачи. Если ML не нужен, или он нужен минимально, есть куча других устройств которые дают более гибкую настройку всего.
        Опять же, даже RPi в каких-то условиях вполне приятная платформа, я не раз его использовал.

        Про


        1. gev
          27.02.2022 10:06

          Вызваная панель домофона. Пока остановились на rpi