Распознавание лиц на RASPBERRY PI
- суббота, 26 февраля 2022 г. в 00:36:15
Биометрия везде. Современные мегаполисы в России и мире окутаны сетями камер, подключенными к различным системам распознавания лиц. Насколько это правильно с точки зрения этики — каждый решает сам, но факт в том, что такие методы не только помогают раскрывать преступления, но и предотвращать их совершение.
С каждым годом расширяется область применения таких систем. Например, пользователи могут приобрести у 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 ограничена, у неё очень много возможностей, вплоть до управления системой умного дома. Да, проект на данный момент далек от завершающей стадии, но уже можно с уверенностью сказать – домашняя система распознавания лиц возможна и на одноплатном микрокомпьютере.