Технология распознавания лиц (Face Recognition) с каждым годом становится все более популярной в современном мире. Китай запустил данную технологию в школах для контроля за посещением уроков школьниками и их поведением. Многие аэропорты мира уже используют технологию распознавания лиц для обеспечения безопасности на своей территории. Гипермаркеты применяют данную технологию для классификации своих покупателей и изоляции (задержания) лиц, которые ранее были замечены в попытках обмана магазина. Несомненно, что диапазон применений технологии распознавания лиц в ближайшее время будет только расти.
В данной статье мы рассмотрим создание системы распознавания лиц с помощью платы Raspberry Pi и библиотеки OpenCV. Достоинством развертывания такой системы на основе платы Raspberry Pi является то, что система получается чрезвычайно компактной и ее можно будет установить в любом удобном месте. Как и во всех других системах распознавания лиц, у нас будет две программы (на python), одна из которых будет тренировочной программой (Trainer program) и будет анализировать набор фотографий с определенными людьми, после чего она будет создавать набор данных в формате YML файла. Вторая программа будет непосредственно программой распознавания (Recognizer program), которая будет обнаруживать на изображении лицо человека и затем использовать набор данных YML чтобы распознать его и подписать имя человека на изображении. В нашем проекте обе эти программы написаны для Raspberry Pi (Linux), однако с небольшими изменениями они будут работать и на компьютерах с операционной системой Windows.
Для реализации данного проекта нам понадобится библиотека OpenCV. Как ее установить на плату Raspberry Pi можно прочитать в данной статье.
Как работает распознавание лиц с OpenCV
На этом этапе необходимо отметить, что обнаружение лица (Face Detection) и распознавание лица (Face Recognition) – это две разные задачи. При обнаружении лица обнаруживается только лицо человека и программное обеспечение не имеет узнать человека. А вот в задаче распознавания лица программное обеспечение должно не только обнаружить лицо, но и распознать его. То есть перед распознаванием лица нам необходимо сначала обнаружить лицо. Каким образом библиотека OpenCV производит обнаружение лица или какого-либо другого объекта на изображении, мы в данной статье рассматривать не будем, информации об этом достаточно много в сети интернет.
Видео, получаемое с камеры, есть не что иное как последовательность изображений, следующих одно за другим. А каждое из этих изображений представляет собой просто набор пикселов, размещенных на определенных позициях. Так каким же образом программа среди этих пикселов может обнаруживать лицо и затем распознавать его? Для этого в настоящее время существует уже достаточно много разработанных алгоритмов, но их изучение не является целью данной статьи. И, поскольку мы будем использовать библиотеку OpenCV для решения задачи распознавания лиц, то нам нет необходимости глубоко вникать в эти вопросы, нам просто нужно будет использовать соответствующие функции этой библиотеки.
Обнаружение лиц в OpenCV с использованием каскадов Хаара
Мы сможем распознать лицо только если правильно его обнаружим (выделим из полного изображения). Для обнаружения таких объектов как лицо OpenCV использует классификаторы/каскады (Classifiers). Эти классификаторы предварительно тренируются (обучаются) на наборе данных (XML файл), после чего они могут быть использованы для обнаружения определенных объектов, в нашем случае лиц. Более подробно о классификаторах для обнаружения лиц вы можете прочитать в сети Интернет - в последнее время об этом пишут достаточно много. Кроме обнаружения лиц классификаторы/каскады могут также использоваться для обнаружения других объектов: нос, глаза, улыбка, автомобильные номера и многое другое. Список данных классификаторов можно скачать по следующей ссылке:
Classifiers for Object detection in Python
Также библиотека OpenCV позволяет вам создать свой собственный классификатор/каскад (Classifier), который можно использовать для обнаружения любого объекта на изображении при помощи обучения вашего каскада Хаара. В этой статье мы будем использовать классификатор под названием “haarcascade_frontalface_default.xml”, который способен обнаруживать лицо при виде на него спереди (по фронту). Как его использовать мы рассмотрим далее в статье.
Установка необходимых пакетов
Вначале убедитесь что на вашей плате Raspberry Pi установлен pip, только после этого можно переходить к установке необходимых пакетов.
Установка dlib
Dlib – это инструмент для приложений машинного обучения (Machine Learning) и анализа данных. Для его установки введите следующую команду в терминале:
1 |
Pip install dlib |
При этом процесс установки dlib будет выглядеть примерно следующим образом:
Установка pillow
Инструмент Pillow также известен под названием PIL (Python Imaging Library – библиотека Python для работы с изображениями). Он используется для открытия, изменения и сохранения изображений в различных форматах. Для установки PIL используйте следующую команду:
1 |
Pip install pillow |
При успешной установке PIL вы должны получить следующее сообщение на экране:
Установка face_recognition
Библиотека face_recognition для python является, пожалуй, самой простой в использовании библиотекой для распознавания и обработки лиц. Мы будем использовать эту библиотеку для обучения (тренировки, train) и распознавания лиц. Для установки данной библиотеки используйте следующую команду:
1 |
Pip install face_recognition –no –cache-dir |
После успешной установки библиотеки вы должны увидеть экран, показанный на рисунке ниже. Библиотека достаточно "тяжелая", поэтому те, у кого мало памяти на плате, могут столкнуться с проблемами при ее установке, поэтому для установки библиотеки мы использовали параметры “-no -cache-dir” чтобы установка библиотеки проходила без сохранения файлов кэша.
Каталог для сохранения данных распознавания лиц
Наш проект будет состоять из двух программ на python под названиями Face_Trainner.py и Face_Recog.py. Для хранения данных распознавания лиц мы создадим каталог Face_Images, в котором будут храниться образцы изображений, на которых необходимо будет распознавать лица. Файл классификатора/каскада называется “haarcascade_frontalface_default.xml” – он будет использоваться для обнаружения лиц. Также у нас будет файл с названием “face-trainner.yml”, который будет генерироваться с помощью программы Face_Trainner.py на основе файлов изображений, присутствующих в каталоге Face_Images. Все необходимые файлы и каталог для нашего проекта показаны на следующем рисунке.
Все эти файлы и каталог можно скачать по следующей ссылке.
Заполнение каталога Face_Images образцами лиц
Каталог Face_Images, который мы создали на предыдущем этапе, должен иметь в своем составе подкаталоги с именами людей, лица которых мы будем распознавать, и образцами изображений этих лиц внутри этих подкаталогов. В данном проекте автор статьи использовал двух людей для распознавания: самого себя (его имя Aswinth) и Илона Маска (Elon Musk). Поэтому он создал внутри каталога Face_Images два соответствующих подкаталога.
Вам необходимо переименовать эти каталоги на имена людей, которые вы собираетесь распознавать, и заменить фотографии в этих подкаталогах на фотографии этих лиц. Для хорошей работы программы достаточно по 5 фотографий каждого лица. Но чем больше будет людей, чьи лица мы будем распознавать, тем медленнее будет работать программа.
Программа для обучения распознавания лиц (Face Trainer Program)
Рассмотрим программу нашего проекта под названием Face_Traineer.py. Целью работы данной программы является открытие всех изображений в каталоге Face_Images и поиск на них лиц. Когда лицо будет обнаружено, оно вырезается из изображения, конвертируется в черно-белое изображение с оттенками серого (grayscale) и передается в массив numpy. Затем мы будем использовать библиотеку face_recognition (которую мы установили ранее) для обработки этого изображения (тренировки модели) и сохранять его под именем face-trainner.yml. Данные из этого файла позже могут быть использованы для распознавания лиц. Полный текст программы Face_Traineer.py приведен в конце статьи, здесь же мы кратко рассмотрим ее основные фрагменты.
В программе нам первым делом необходимо подключить (импортировать) используемые библиотеки (модули). Модуль cv2 будет использоваться для обработки изображений, numpy – для преобразования изображений в их математические эквиваленты, os – для переключения между каталогами, а PIL – для работы с изображениями.
1 2 3 4 |
import cv2 #For Image processing import numpy as np #For converting Images to Numerical array import os #To handle directories from PIL import Image #Pillow lib for handling images |
Далее мы будем использовать классификатор/каскад haarcascade_frontalface_default.xml для обнаружения лиц на изображениях. Убедитесь в том, что вы поместили этот xml файл в каталог с вашим проектом, иначе будет выдаваться сообщение об ошибке. Затем мы будем использовать переменную recognizer для создания Local Binary Pattern Histogram (LBPH) Face Recognizer (образца локальной двоичной гистограммы распознавателя лиц).
1 2 |
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') recognizer = cv2.createLBPHFaceRecognizer() |
Далее мы должны попасть внутрь каталога Face_Images чтобы получить доступ к изображениям внутри него. Этот каталог должен быть размещен внутри вашего текущего рабочего каталога (current working directory, CWD). Следующая команда используется для входа в каталог Face_Images, который расположен внутри нашего рабочего каталога (CWD).
1 |
Face_Images = os.path.join(os.getcwd(), "Face_Images") #Tell the program where we have saved the face images |
Далее мы будем использовать циклы для доступа к каждому подкаталогу внутри каталога Face_Images и открывать в этих подкаталогах все файлы с расширениями jpeg, jpg или png. Путь к каждому из этих изображений будет сохраняться в переменной path, а имя каталога (оно совпадает с именем человека) будет сохраняться в переменной person_name.
1 2 3 4 5 6 |
for root, dirs, files in os.walk(Face_Images): #go to the face image directory for file in files: #check every directory in it if file.endswith("jpeg") or file.endswith("jpg") or file.endswith("png"): #for image files ending with jpeg,jpg or png path = os.path.join(root, file) person_name = os.path.basename(root) |
Если имя человека изменилось мы будем инкрементировать значение переменной Face_ID, это в дальнейшем упростит нам навигацию между идентификаторами различных людей.
1 2 3 |
if pev_person_name!=person_name: #Check if the name of person has changed Face_ID=Face_ID+1 #If yes increment the ID count pev_person_name = person_name |
Поскольку нам известно, что в библиотеке OpenCV проще работать с черно-белыми изображениями с оттенками серого (поскольку в этом случае значения BGR можно игнорировать), то мы будем конвертировать наши изображения в черно-белый формат с оттенками серого и уменьшать их размер до 550 пикселей чтобы все наши изображения имели одинаковый формат. Убедитесь в том, что лица на изображениях находятся по центру, иначе лица могут быть неправильно вырезаны из изображения. И, наконец, все эти изображения мы преобразуем в массив numpy чтобы получить математическое значение для каждого изображения. Затем мы будем использовать каскад Хаара (cascade classifier) для обнаружения лиц на изображениях и сохранять результат в переменной faces.
1 2 3 4 |
Gery_Image = Image.open(path).convert("L") # convert the image to greysclae using Pillow Crop_Image = Gery_Image.resize( (550,550) , Image.ANTIALIAS) #Crop the Grey Image to 550*550 (Make sure your face is in the center in all image) Final_Image = np.array(Crop_Image, "uint8") faces = face_cascade.detectMultiScale(Final_Image, scaleFactor=1.5, minNeighbors=5) #Detect The face in all sample image |
После того как лицо будет обнаружено, мы будем вырезать эту область с изображения и считать ее областью наших интересов (Region of Interest, ROI). Эта область будет использоваться для обучения (тренировки) распознавателя лиц. Каждое полученное таким образом ROI лицо будет добавляться (append) внутрь переменной x_train. Далее через эту переменную с ROI значениями мы будем пропускать все изображения с одинаковым Face ID чтобы обеспечить распознаватель лиц тренировочными данными. Полученные таким образом данные мы будем сохранять.
1 2 3 4 5 6 7 |
for (x,y,w,h) in faces: roi = Final_Image[y:y+h, x:x+w] #crop the Region of Interest (ROI) x_train.append(roi) y_ID.append(Face_ID) recognizer.train(x_train, np.array(y_ID)) #Create a Matrix of Training data recognizer.save("face-trainner.yml") #Save the matrix as YML file |
Когда вы будете компилировать эту программу вы обнаружите что файл face-trainner.yml обновляется после каждой компиляции. Поэтому всегда, когда вы внесли какие-либо изменения в изображения в каталоге Face_Images, следует запускать компиляцию программы. Также во время компиляции программы на экран в целях отладки выводятся значения Face ID (идентификатор лица), path name (путь к файлу с изображением), person name (имя человека) и массив numpy.
Программа для распознавания лиц (Face Recognizing Program)
Теперь, когда наши тренировочные данные готовы, мы можем использовать их для распознавания лиц. В нашей программе распознавания лиц (Face Recognizer program) мы будем считывать видео в реальном времени с USB веб-камеры и конвертировать его в изображения. Затем мы будем использовать нашу технологию обнаружения лиц для обнаружения лиц на этих изображениях и затем сравнивать их со всеми имеющимися у нас идентификаторами лиц (Face ID), которые мы создали ранее с помощью программы обнаружения лиц. Если будет фиксироваться совпадение, то мы будем выделять лицо прямоугольником и подписывать сверху над ним имя человека, чье лицо мы распознали. Полный текст данной программы приведен в конце статьи, здесь же мы кратко рассмотрим ее основные фрагменты.
Программа имеет много похожего с рассмотренной ранее программой обнаружения лиц, поэтому в ней мы подключим те же самые модули (библиотеки). Также нам придется использовать классификатор (каскад) Хаара поскольку нам снова придется производить обнаружение лиц.
1 2 3 4 5 6 |
import cv2 #For Image processing import numpy as np #For converting Images to Numerical array import os #To handle directories from PIL import Image #Pillow lib for handling images face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') recognizer = cv2.createLBPHFaceRecognizer() |
В переменной (массиве) labels мы укажем имена людей, каталоги фотографий которых имеются в нашем проекте. В нашем случае это будет имена “Aswinth” и “Elon” – вы должны заменить их на те имена, которые используете вы.
1 |
labels = ["Aswinth", "Elon Musk"] |
Далее мы должны загрузить в нашу программу содержимое файла face-trainner.yml, поскольку данные из этого файла мы будем использовать для распознавания лиц.
1 |
recognizer.load("face-trainner.yml") |
Видео в нашем проекте мы считываем с USB веб-камеры. Если вы в вашем проекте используете более чем одну камеру, замените в представленной ниже команде 0 на 1 чтобы считывать видео со второй камеры.
1 |
cap = cv2.VideoCapture(0) #Get vidoe feed from the Camera |
Затем мы преобразуем видео в последовательность изображений/фреймов (frames) и преобразуем их в черно-белый формат с оттенками серого (grayscale). Затем мы обнаруживаем лицо на изображении. При обнаружении лица мы вырезаем с изображения эту область и сохраняем ее в переменной roi_gray.
1 2 3 4 5 6 7 |
ret, img = cap.read() # Break video into frames gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #convert Video frame to Greyscale faces = face_cascade.detectMultiScale(gray, scaleFactor=1.5, minNeighbors=5) #Recog. faces for (x, y, w, h) in faces: roi_gray = gray[y:y+h, x:x+w] #Convert Face to greyscale id_, conf = recognizer.predict(roi_gray) #recognize the Face |
Переменная conf содержит степень доверия, с которым программное обеспечение смогло распознать лицо. Если уровень (степень) доверия больше 80, мы определяем имя человека исходя из его идентификатора (ID number). Затем мы рисуем прямоугольник вокруг лица и подписываем имя человека сверху этого прямоугольника.
1 2 3 4 5 |
if conf>=80: font = cv2.FONT_HERSHEY_SIMPLEX #Font style for the name name = labels[id_] #Get the name from the List using ID number cv2.putText(img, name, (x,y), font, 1, (0,0,255), 2) cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) |
И, наконец, мы отображаем видео, которое мы только что проанализировали, и ставим видео на паузу (break) если нажата клавиша "q".
1 2 3 |
cv2.imshow('Preview',img) #Display the Video if cv2.waitKey(20) & 0xFF == ord('q'): break |
Перед запуском этой программы на выполнение убедитесь в том, что к вашей плате Raspberry Pi подключен монитор через HDMI кабель. После запуска программы вы увидите всплывающее окно с именем "preview" и в нем будет транслироваться видео, которое мы получаем с камеры. Если лицо удается распознать то вокруг него рисуется прямоугольник зеленого цвета, а сверху над ним подписывается имя человека, чье лицо мы распознали. В этом проекте его автор натренировал программе на распознавание своего собственного лица и лица Илона Маска. Вы можете натренировать программу на распознавание лиц тех людей, которые будут вам необходимы. Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Одной из проблем при реализации данного проекта является очень низкая частота кадров (frame rate). Автор этого проекта получал один кадр каждые 3 секунды. При использовании платы Raspberry Pi 4, скорее всего, частоту кадров можно будет существенно повысить. Потому что автор проекта запускал эту же самую программу на своем ноутбуке и получил очень впечатляющие результаты. Поскольку используемые в этом проекте тренировочные данные достаточно простые, то работу программы нельзя назвать достаточно надежной (устойчивой). Вы можете использовать технологию Deep learning (глубокого обучения) чтобы более качественно натренировать ваш набор данных (модель) – это повысит точность распознавания лиц. Существуют и другие способы увеличения частоты кадров (Frame per second, FPS), но их рассмотрение выходит за рамки настоящей статьи – будем надеяться, что мы их частично рассмотрим в последующих статьях на нашем сайте.
Исходный код программ на Python
Код программы для распознавания лиц
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#Program to Detect the Face and Recognise the Person based on the data from face-trainner.yml import cv2 # библиотека для обработки изображений import numpy as np # библиотека для конвертирования изображений в массив чисел import os # библиотека для навигации между каталогами from PIL import Image # библиотека Pillow для работы с изображениями labels = ["Aswinth", "Elon Musk"] face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') recognizer = cv2.createLBPHFaceRecognizer() recognizer.load("face-trainner.yml") cap = cv2.VideoCapture(0) # получаем видео с камеры while(True): ret, img = cap.read() # преобразуем видео в изображения (кадры) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # преобразуем изображение в черно-белый формат с оттенками серого faces = face_cascade.detectMultiScale(gray, scaleFactor=1.5, minNeighbors=5) # Recog. faces for (x, y, w, h) in faces: roi_gray = gray[y:y+h, x:x+w] #вырезаем лицо с изображения id_, conf = recognizer.predict(roi_gray) #распознаем лицо if conf>=80: font = cv2.FONT_HERSHEY_SIMPLEX #шрифт, которым будем писать имя name = labels[id_] # считываем имя из списка по его идентификатору (ID number) cv2.putText(img, name, (x,y), font, 1, (0,0,255), 2) cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) cv2.imshow('Preview',img) # отображаем видео if cv2.waitKey(20) & 0xFF == ord('q'): break # когда все сделано, освобождаем (release) изображение cap.release() cv2.destroyAllWindows() |
Код тренировочной программы обнаружения лиц
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#Program to train with the faces and create a YAML file (программа для тренировки обнаружения лиц и создания YAML файла) import cv2 # библиотека для обработки изображений import numpy as np # библиотека для конвертирования изображений в массив чисел import os # библиотека для навигации между каталогами from PIL import Image # библиотека Pillow для работы с изображениями face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') recognizer = cv2.createLBPHFaceRecognizer() Face_ID = -1 pev_person_name = "" y_ID = [] x_train = [] Face_Images = os.path.join(os.getcwd(), "Face_Images") # сообщаем программе где у нас хранятся изображения с лицами print (Face_Images) for root, dirs, files in os.walk(Face_Images): # переходим в каталог face image for file in files: #check every directory in it if file.endswith("jpeg") or file.endswith("jpg") or file.endswith("png"): # находим в каталоге файлы с изображенями, заканчивающимися на jpeg, jpg или png path = os.path.join(root, file) person_name = os.path.basename(root) print(path, person_name) if pev_person_name!=person_name: # проверяем изменилось ли имя человека Face_ID=Face_ID+1 # если изменилось, то инкрементируем Face_ID pev_person_name = person_name Gery_Image = Image.open(path).convert("L") # преобразуем изображение из цветного в серое (greyscale) с помощью библиотеки Pillow Crop_Image = Gery_Image.resize( (550,550) , Image.ANTIALIAS) # обрезаем серое изображение до размера 550*550 (убедитесь в том, что лица находятся примерно по центру всех изображений) Final_Image = np.array(Crop_Image, "uint8") #print(Numpy_Image) faces = face_cascade.detectMultiScale(Final_Image, scaleFactor=1.5, minNeighbors=5) #обнаруживаем лицо в образцах изображений print (Face_ID,faces) for (x,y,w,h) in faces: roi = Final_Image[y:y+h, x:x+w] # вырезаем интересующую нас область (Region of Interest, ROI) x_train.append(roi) y_ID.append(Face_ID) recognizer.train(x_train, np.array(y_ID)) # Create a Matrix of Training data (создаем матрицу тренировочных данных) recognizer.save("face-trainner.yml") # Save the matrix as YML file (сохраняем матрицу в виде YML файла) |
Здравствуйте! Спасибо большое за вашу программу. Не могли бы вы, пожалуйста, ответить на вопрос. Работает ли ваша программа с тремя и более людьми? Если работает, то какие данные в коде нужно изменить, потому что у меня отображаются только первые два человека, которые стоят в labels.
Добрый вечер. Она может работать с любым количеством лиц если вы предварительно обучите модель для всех этих лиц
А как? Можете точно рассказать,пожалуйста.
В каталог Face_Images необходимо загрузить столько подкаталогов с образцами лиц, сколько человек вы хотите распознавать. То есть, к примеру, если вы хотите распознавать лица 5 человек, то в каталоге Face_Images у вас должно быть 5 подкаталогов, названия которых соответствуют именам распознаваемых вами людей. Дальше программа должна сделать все остальное автоматически