Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Воган Ли - Python для хакеров (Библиотека программиста) - 2023.pdf
Скачиваний:
6
Добавлен:
07.04.2024
Размер:
14.76 Mб
Скачать

302      Глава 10. Ограничение доступа по принципу распознавания лиц

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

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

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

На данном этапе в каталоге trainer должно находиться 30 изображений лица пользователя. В следующем разделе, используя эти изображения или изображения из каталога demming_trainer, мы с помощью OpenCV займемся обучением алгоритма распознавания лиц.

Код для обучения алгоритма распознавания лиц

Используем OpenCV для создания алгоритма распознавания лиц на основе LBPH, его обучения на подготовленных изображениях и сохранения результатов в файле. При использовании вашего лица укажите каталог trainer. В ином случае будет использован каталог demming_trainer, который вместе с содержащим код файлом 2_train.py находится в доступной для скачивания директории Chapter_10.

Код листинга 10.3 настраивает пути к каскадам Хаара, используемым для обнаружения лиц, и к обучающим изображениям, захваченным предыдущей программой. OpenCV отслеживает лица с помощью целочисленных меток, а не строк имен. Код также инициализирует списки для хранения этих меток и связанных с ними изображений. Затем выполняются перебор обучающих изображений, их загрузка, извлечение ID пользователя из имени файла и обнаружение лиц. В завершение происходит обучение алгоритма распознавания и сохранение результата в файл.

Листинг 10.3. Обучение и сохранение алгоритма распознавания лиц LBPH

2_train.py

import os

import numpy as np import cv2 as cv

cascade_path = "C:/Python372/Lib/site-packages/cv2/data/"

Проект #14. Ограничение доступа к инопланетному артефакту      303

face_detector = cv.CascadeClassifier(cascade_path + 'haarcascade_frontalface_default.xml')

train_path = './demming_trainer' # Используйте для лица Демминга

#train_path = './trainer' # Раскомментируйте для использования своего лица image_paths = [os.path.join(train_path, f) for f in os.listdir(train_path)] images, labels = [], []

for image in image_paths:

train_image = cv.imread(image, cv.IMREAD_GRAYSCALE)

label = int(os.path.split(image)[-1].split('.')[1]) name = os.path.split(image)[-1].split('.')[0] frame_num = os.path.split(image)[-1].split('.')[2]

faces = face_detector.detectMultiScale(train_image) for (x, y, w, h) in faces: images.append(train_image[y:y + h, x:x + w]) labels.append(label)

print(f"Preparing training images for {name}.{label}.{frame_num}") cv.imshow("Training Image", train_image[y:y + h, x:x + w]) cv.waitKey(50)

cv.destroyAllWindows()

recognizer = cv.face.LBPHFaceRecognizer_create() recognizer.train(images, np.array(labels)) recognizer.write('lbph_trainer.yml') print("Training complete. Exiting...")

Код, выполняющий импорт и распознавание лиц, вы уже видели. В программе 1_capture.py мы вырезали из обучающих изображений рамки с лицами, но нелишне повторить эту процедуру. Поскольку 2_train.py является автономной программой, лучше ничего не принимать без подтверждения.

Далее необходимо выбрать набор обучающих изображений: либо свои из каталога trainer, либо заранее подготовленные из каталога demming_trainer . Закомментируйте или удалите строку для тех, которые не используете. Напомню, так как мы не предоставляем полный путь к каталогу, то нужно запускать программу из папки, где она хранится. Она должна располагаться на один уровень выше каталогов trainer и demming_trainer.

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

Начинаем перебирать пути к изображениям циклом for. Считываем изображение в оттенках серого, после чего извлекаем из его имени файла числовую метку и преобразуем ее в целое число . Напомню, что метка соответствует ID пользователя, введенному через программу 1_capture.py перед захватом видеокадров.

304      Глава 10. Ограничение доступа по принципу распознавания лиц

Давайте подробнее остановимся на процессе извлечения и конвертации. Метод os.path.split() получает путь к каталогу и возвращает кортеж из этого пути

иимени файла, как показано в следующем фрагменте:

>>>import os

>>>path = 'C:\demming_trainer\demming.1.5.jpg'

>>>os.path.split(path)

('C:\\demming_trainer', 'demming.1.5.jpg')

Затем, используя индекс -1, мы выбираем последний элемент кортежа и разделяем его по точкам. В итоге получается список из четырех элементов (имя пользователя, его ID, номер кадра и расширение файла).

>>> os.path.split(path)[-1].split('.') ['demming', '1', '5', 'jpg']

Чтобы извлечь значение метки, мы выбираем в этом списке второй элемент

спомощью индекса 1.

>>>os.path.split(path)[-1].split('.')[1]

'1'

Повторяем этот процесс для извлечения name и frame_num для каждого изображения. В данный момент все они представлены строками, поэтому ID пользователя нужно преобразовать в целое число, чтобы можно было использовать его в качестве метки.

Теперь вызываем детектор лиц для каждого обучающего изображения . В ответ мы получим numpy.ndarray, который назовем faces. Начинаем перебор этого массива, содержащего координаты обнаруженных рамок с лицами. Добавляем изображение в рамке в созданный ранее список images, а также ID пользователя с этого изображения в список labels.

Сообщаем пользователю о происходящем, выводя сообщение в оболочку. Затем в качестве проверки показываем каждое обучающее изображение в течение 50 мс. Если вы смотрели популярный клип Питера Гэбриэла «Sledgehammer» 1986 года, то должны оценить подобный видеоряд.

Теперь пора обучать алгоритм распознавания лиц. Как и в случае с детектором лиц OpenCV, сначала мы инстанцируем объект распознавателя . Далее вызываем метод train(), которому передаются списки images и labels, преобразуемые в массив NumPy.

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

Проект #14. Ограничение доступа к инопланетному артефакту      305

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

Время переходить к распознаванию лиц. Этот процесс называется прогнозированием ввиду того, что в нем все сводится к вероятности. Программа 3_predict.py сначала вычисляет конкатенированную гистограмму для каждого лица, после чего находит расстояние между этой гистограммой и всеми гистограммами в обу­ чающем наборе. Затем она присваивает новому лицу метку и имя контрольного лица с наибольшим соответствием, но только если расстояние между ними впишется в заданный пороговый диапазон.

Импорт модулей и подготовка алгоритма распознавания лиц

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

Листинг 10.4. Импорт модулей и подготовка к обнаружению и распознаванию лиц

3_predict.py, часть 1

import os

from datetime import datetime import cv2 as cv

names = {1: "Demming"}

cascade_path = "C:/Python372/Lib/site-packages/cv2/data/" face_detector = cv.CascadeClassifier(cascade_path +

'haarcascade_frontalface_default.xml')

recognizer = cv.face.LBPHFaceRecognizer_create() recognizer.read('lbph_trainer.yml')

#test_path = './tester'

test_path = './demming_tester'

image_paths = [os.path.join(test_path, f) for f in os.listdir(test_path)]

После нескольких уже знакомых нам операций импорта мы создаем словарь для связывания ID пользователей с их именами. Несмотря на то что сейчас в нем будет всего одна запись, этот словарь name в дальнейшем позволит без проблем добавить и другие. Если вы используете собственное лицо, то фамилию можете тоже поменять, но в качестве ID необходимо оставить 1.

Далее повторяем код, настраивающий объект face_detector. При этом введите собственный cascade_path (см. листинг 10.1 на с. 298).

306      Глава 10. Ограничение доступа по принципу распознавания лиц

Теперь создаем объект распознавателя, как делали это в коде 2_train.py . Затем с помощью метода read() загружаем файл .yml, содержащий информацию для обучения.

Алгоритм распознавания нужно протестировать при помощи изображений лиц из отдельного каталога. Если вы используете заранее подготовленные снимки лица капитана Демминга, то укажите путь к каталогу demming_tester . В ином случае укажите путь к созданному ранее каталогу tester, куда можете добавить собственные изображения. Если вы выбрали свой снимок, то не нужно повторно использовать здесь обучающие изображения, хотя одно можно взять в качестве проверочного. Используйте программу 1_capture.py для создания новых изображений. Если вы носите очки, включите ряд фото в очках и без них. При этом также следует добавить сюда несколько снимков из каталога demming_tester.

Распознавание лиц и обновление журнала доступа

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

Листинг 10.5. Выполнение распознавания лиц и обновление журнала доступа

3_predict.py, часть 2

for image in image_paths:

predict_image = cv.imread(image, cv.IMREAD_GRAYSCALE) faces = face_detector.detectMultiScale(predict_image,

scaleFactor=1.05,

minNeighbors=5)

for (x, y, w, h) in faces:

print(f"\nAccess requested at {datetime.now()}.")

face = cv.resize(predict_image[y:y + h, x:x + w], (100, 100)) predicted_id, dist = recognizer.predict(face)

if predicted_id == 1 and dist <= 95: name = names[predicted_id]

print("{} identified as {} with distance={}"

.format(image, name, round(dist, 1)))

print(f"Access granted to {name} at {datetime.now()}.", file=open('lab_access_log.txt', 'a'))

else:

name = 'unknown' print(f"{image} is {name}.")

cv.rectangle(predict_image, (x, y), (x + w, y + h), 255, 2) cv.putText(predict_image, name, (x + 1, y + h - 5),

Проект #14. Ограничение доступа к инопланетному артефакту      307

cv.FONT_HERSHEY_SIMPLEX, 0.5, 255, 1) cv.imshow('ID', predict_image)

cv.waitKey(2000)

cv.destroyAllWindows()

Начинаем с перебора изображений в тестовом каталоге — в demming_tester либо в tester. Считываем каждое изображение в оттенках серого и присваиваем получающийся массив переменной predict_image, после чего выполняем для него обнаружение лиц.

Теперь перебираем рамки лиц, как делали это ранее. Выводим сообщение о запросе доступа, а затем с помощью OpenCV изменяем размер подмассива face до 100 × 100 пикселей . Это значение близко к размеру обучающих изображений из каталога demming_trainer. Синхронизировать размер изображений не обязательно, но это улучшит результаты. Если вы используете собственные изображения в качестве изображений капитана Демминга, то следует убедиться, что размеры обучающего и тестового изображений близки.

Теперь пора прогнозировать личность того, чье лицо идентифицируется. Для этого потребуется всего одна строка. В ней мы просто вызываем для объекта recognizer метод predict(), передавая ему подмассив face. Этот метод вернет ID и значение расстояния.

Чем меньше значение расстояния, тем выше вероятность того, что лицо спро­ гнозировано верно. Это значение можно использовать в качестве порога: все изображения, спрогнозированные как капитан Демминг и имеющие показатель, равный или ниже порога, будут определены как капитан Демминг. Все остальные получат обозначение 'unknown'.

Порог задаем с помощью инструкции if . Если вы используете собственные обучающие и тестовые изображения, то при первом запуске программы установите значение расстояния как 1000. Просмотрите эти значения для всех изображений в тестовом каталоге, включая известные и 'unknown'. Найдите пороговое значение, ниже которого все лица верно распознаются как принадлежащие капитану Деммингу. В дальнейшем это будет ваш дискриминатор. Для изображений в каталогах demming_trainer и demming_tester пороговое расстояние должно равняться 95.

Далее получаем имя для изображения, используя в качестве ключа в словаре names значение predicted_id. Выводим в оболочке сообщение о распознавании изображения, включая имя соответствующего файла, имя из словаря и значение расстояния.

Для журнала выводим сообщение о том, что name (в данном случае капитан Демминг) получил доступ в лабораторию, и с помощью модуля datetime указываем время доступа .