Интерес к системам распознавания лиц настолько велик, что принимает масштабы эпидемии планетарного масштаба. Алгоритмы распознавания уже используются не только спецслужбами, но и многими компаниями, которые давно внедрили данную технологию в нашу с вами повседневную жизнь. Сейчас её можно встретить практически везде: в аэропортах и на вокзалах, в банках и торговых центрах, в больницах и школах и даже просто на улицах больших городов.
Китай - мировой лидер по технологиям наблюдения за своими гражданами. К 2020 году там планируется установить 600 миллионов видеокамер. У полицейских есть специальные очки-дисплеи, которые могут выдать информацию о прохожем - достаточно просто на него посмотреть. В апреле 2017 года на востоке Китая задержали находящегося в розыске мужчину. Полиция с помощью видеонаблюдения нашла его на стадионе во время концерта, где было 70 тысяч человек.
Что уж говорить о виртуальном мире социальных сетей, где люди автоматически отмечаются на загруженных фотографиях и мобильных операционных системах, где смартфон узнаёт своего владельца через объектив фронтальной камеры.
В России успешно применяется технология распознавания на базе нейросети, которая позволяет узнать человека по фотографии и идентифицировать его, сравнив изображение с его фотографиями в социальных сетях. В первую очередь, во "ВКонтакте".
Тема эта настолько обширна, что раскрыть её в одной статье при всем желании никак не получится, да и цель у нас другая - так что остановимся на этом и перейдем к практике.
Шаг за шагом вы узнаете, как буквально в домашних условиях собрать простую и недорогую систему распознавания лиц в режиме реального времени. Способ предложил программист из Чили Марсело Ровай.
Для этого нам понадобится следующее оборудование:
- Raspberry Pi 3 Модель B
- Raspberry Pi Модуль камеры
-
Ссылка скрыта от гостей
- Python 3
Для распознавания лиц мы будем использовать камеру PiCam и библиотеки Open Source Computer Vision (OpenCV) на Raspberry Pi (Raspbian как ОС) и Python.
OpenCV был разработан для вычислительной эффективности с сильным акцентом на приложениях реального времени. Таким образом, он идеально подходит для распознавания лиц в режиме реального времени с помощью камеры.
Работу разделим на три этапа:
- Обнаружение лица и сбор данных
- Обучение Распознавателя
- Распознавание лица
Приведенная ниже схема иллюстрирует эти этапы:
Установка пакета OpenCV 3
Мы будем использовать Raspberry Pi V3, обновленную до последней версии Raspbian (Stretch).
Пошаговую инструкцию установки OpenCV я подробно описал в предыдущей статье: Установка OpenCV 3 + Python на Raspberry Pi ,
После установки, у вас должна быть готовая виртуальная среда OpenCV.
Давайте перейдем в нашу виртуальную среду и проверим, что OpenCV 3 установлен правильно.
Рекомендуется запускать команду «source» каждый раз, когда вы открываете новый терминал, чтобы убедиться, что системные переменные установлены правильно.
source ~/.profile
Далее давайте войдем в нашу виртуальную среду:
workon cv
Если вы видите текст (cv), предшествующий вашему приглашению, то вы находитесь в виртуальной среде cv :
(cv) pi@raspberry:~$
Обращаю Ваше внимание, что виртуальная среда cv Python полностью независима и отделена от версии Python по умолчанию, включенной в загрузку Raspbian Stretch. Таким образом, любые пакеты Python в глобальном каталоге site-packages не будут доступны для виртуальной среды cv. Аналогично, любые пакеты Python, установленные в пакетах site-cv, не будут доступны для глобальной установки Python.
Теперь введите в ваш интерпретатор Python:
python
и подтвердите, что вы используете версию 3.5 (или выше).
Внутри интерпретатора (появится «>>>») импортируйте библиотеку OpenCV:
import cv2
Если сообщения об ошибках не появляются, OpenCV правильно установлен в вашей виртуальной среде PYTHON.
Вы также можете проверить установленную версию OpenCV:
cv2.__version__
Должна появиться 3.3.0 (или более новая версия).
На скриншоте выше показаны предыдущие шаги.
Тестирование камеры
После того, как мы установили OpenCV в RPi, давайте проверим, правильно ли работает ваша камера.
Я предполагаю, что у вас уже есть установленная PiCam на вашем Raspberry Pi.
Камера должна быть включена, когда вы начинаете установку, иначе драйверы будут установлены неправильно.
Если вы получили ошибку типа: OpenCV Error: Assertion failed, вы можете попытаться решить проблему, используя команду:
sudo modprobe bcm2835-v4l2
После того, как все драйверы установлены правильно, введите приведенный ниже код Python в вашей IDE:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
cap.set(3,640) # set Width
cap.set(4,480) # set Height
while(True):
ret, frame = cap.read()
frame = cv2.flip(frame, -1) # Flip camera vertically
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', frame)
cv2.imshow('gray', gray)
k = cv2.waitKey(30) & 0xff
if k == 27: # press 'ESC' to quit
break
cap.release()
cv2.destroyAllWindows()
Приведенный выше код будет захватывать видеопоток, который будет генерироваться вашей PiCam, отображая как в цветном режиме BGR, так и в сером.
Обратите внимание, что я повернул камеру вертикально, так как она собрана. Если это не ваш случай, прокомментируйте или удалите командную строку «flip».
Вы также можете скачать код с GitHub: simpleCamTest.py
Для выполнения скрипта введите команду:
python simpleCamTest.py
Чтобы завершить программу, вы должны нажать клавишу [ESC] на клавиатуре. Щелкните мышью в окне видео, прежде чем нажимать [ESC].
Некоторые пользователи сталкивались с проблемой при попытке открыть камеру (сообщения об ошибке «Ошибка подтверждения»). Это может произойти, если камера не была включена во время установки OpenCv и, следовательно, драйверы камеры были установлены неправильно. Чтобы исправить ошибку, используйте команду:
sudo modprobe bcm2835-v4l2
Вы также можете добавить bcm2835-v4l2 в последнюю строку файла /etc /modules, чтобы драйвер загружался автоматически при загрузке системы.
Обнаружение лица
Самой основной задачей распознавания лиц, конечно же, является «Обнаружение лица». Прежде всего, вы должны «захватить» лицо (Фаза 1), чтобы распознать его, по сравнению с новым лицом, захваченным в будущем (Фаза 3).
Наиболее распространенный способ обнаружения лица (или любых объектов) - использование «
Ссылка скрыта от гостей
»Обнаружение объектов с использованием каскадных классификаторов на основе признаков Хаара - это эффективный метод обнаружения объектов, предложенный Полом Виолой и Майклом Джонсом в их статье «Быстрое обнаружение объектов с использованием расширенного каскада простых функций». Это подход, основанный на машинном обучении, где Каскадная функция обучается на множестве положительных и отрицательных изображений. Затем он используется для обнаружения объектов на других изображениях.
Здесь мы будем работать с распознаванием лиц. Изначально алгоритму требуется много положительных изображений (изображений лиц) и отрицательных изображений (изображений без лиц) для обучения классификатора. Затем нам нужно извлечь из него особенности. Удобно то, что OpenCV изначально поставляется с инструктором и детектором.
Если вы хотите обучить свой классификатор для любого объекта, такого как автомобиль, собака и т. д., можете использовать OpenCV для его создания. Его полная информация приведена здесь:
Ссылка скрыта от гостей
.Если вы не хотите создавать свой собственный классификатор - OpenCV уже содержит множество предварительно обученных классификаторов для лица, глаз, улыбки и т. д. Эти XML-файлы можно загрузить из каталога haarcascades .
Итак, приступим - давайте создадим детектор лица с OpenCV!
Загрузите файл: faceDetection.py из GitHub.
import numpy as np
import cv2
faceCascade = cv2.CascadeClassifier('Cascades/haarcascade_frontalface_default.xml')
cap = cv2.VideoCapture(0)
cap.set(3,640) # set Width
cap.set(4,480) # set Height
while True:
ret, img = cap.read()
img = cv2.flip(img, -1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(20, 20)
)
for (x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
cv2.imshow('video',img)
k = cv2.waitKey(30) & 0xff
if k == 27: # press 'ESC' to quit
break
cap.release()
cv2.destroyAllWindows()
Приведенный выше код - это все, что вам нужно для обнаружения лица с использованием Python и OpenCV.
Обратите внимание на строку ниже:
faceCascade = cv2.CascadeClassifier('Cascades/haarcascade_frontalface_default.xml')
Это строка, которая загружает классификатор - classifier (который должен находиться в каталоге с именем «Cascades /», в каталоге вашего проекта).
Затем мы установим нашу камеру и внутри цикла загрузим наше входное видео в режиме градаций серого.
Теперь мы должны вызвать нашу функцию классификатора, передав ей некоторые очень важные параметры, такие как масштабный коэффициент, количество соседей и минимальный размер обнаруженного лица.
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(20, 20)
)
Где :
gray - это входное изображение в градациях серого.
scaleFactor - это параметр, определяющий, насколько уменьшается размер при каждом масштабе изображения. Используется для создания масштабной пирамиды.
minNeighbors - это параметр, указывающий, сколько соседей должен иметь каждый прямоугольник-кандидат, чтобы сохранить его. Более высокое число дает меньше ложных срабатываний.
minSize - это минимальный размер прямоугольника, который считается лицом.
Функция обнаружит лица на изображении. Далее мы должны «пометить» грани на изображении, используя, например, синий прямоугольник. Это делается с помощью этой части кода:
for (x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
Если грани найдены, он возвращает позиции обнаруженных граней в виде прямоугольника с левым верхним углом (x, y) и имеет «w» в качестве своей ширины и «h» в качестве высоты = => (x, y, w, h).
Как только мы получим эти местоположения, мы можем создать «ROI» (нарисованный прямоугольник) с гранями и представить результат с помощью функции imshow () .
Запустите приведенный выше скрипт Python в своей среде Python, используя терминал Rpi:
python faceDetection.py
Получаем:
Вы также можете подключить классификаторы для обнаружения глаз или даже обнаружения улыбки. В этих случаях вы будете включать функцию классификатора и рисование прямоугольника внутри цикла лица, потому что нет смысла обнаруживать глаза или улыбку за пределами лица.
Обратите внимание, что на Pi, имеющем несколько классификаторов в одном и том же коде, будет замедляться обработка - этот метод обнаружения (HaarCascades) использует большое количество вычислительной мощности.
На GitHub есть готовые примеры классификаторов:
faceEyeDetection.py
faceSmileDetection.py
faceSmileEyeDetection.py
Результат будет примерно таким :
Сбор данных
Давайте начнем первую фазу нашего проекта. Здесь мы просто создадим набор данных, в котором будем хранить для каждого идентификатора группу фотографий в сером цвете с той частью, которая использовалась для обнаружения лица.
Сначала создайте каталог, в котором вы разрабатываете свой проект, например, FacialRecognitionProject:
mkdir FacialRecognitionProject
В этом каталоге, кроме 3-х сценариев Python, которые мы создадим для нашего проекта, мы должны создать Лицевой классификатор. Вы можете скачать его с GitHub:
haarcascade_frontalface_default.xml
Затем создайте подкаталог, в котором мы будем хранить наши образцы лица . Назовем его dataset (набор данных, база данных):
mkdir dataset
Загрузите код из GitHub: 01_face_dataset.py
import cv2
import os
cam = cv2.VideoCapture(0)
cam.set(3, 640) # set video width
cam.set(4, 480) # set video height
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# For each person, enter one numeric face id
face_id = input('\n enter user id end press <return> ==> ')
print("\n [INFO] Initializing face capture. Look the camera and wait ...")
# Initialize individual sampling face count
count = 0
while(True):
ret, img = cam.read()
img = cv2.flip(img, -1) # flip video image vertically
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_detector.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w,y+h), (255,0,0), 2)
count += 1
# Save the captured image into the datasets folder
cv2.imwrite("dataset/User." + str(face_id) + '.' + str(count) + ".jpg", gray[y:y+h,x:x+w])
cv2.imshow('image', img)
k = cv2.waitKey(100) & 0xff # Press 'ESC' for exiting video
if k == 27:
break
elif count >= 30: # Take 30 face sample and stop video
break
# Do a bit of cleanup
print("\n [INFO] Exiting Program and cleanup stuff")
cam.release()
cv2.destroyAllWindows()
Код очень похож на код, который мы видели для распознавания лиц. Мы добавили «команду ввода» для захвата идентификатора пользователя, который должен быть целым числом (1, 2, 3 и т. д.)
face_id = input('\n enter user id end press ==> ')
И для каждого из захваченных кадров мы должны сохранить его в виде файла в каталоге набора данных dataset :
cv2.imwrite("dataset/User." + str(face_id) + '.' + str(count) + ".jpg", gray[y:y+h,x:x+w])
Обратите внимание, что для сохранения вышеуказанного файла вы должны импортировать библиотеку "os". Имя каждого файла будет соответствовать структуре:
User.face_id.count.jpg
Например, для пользователя с face_id = 1, 4-й пример файла в каталоге dataset / будет выглядеть примерно так:
User.1.4.jpg
Как показано на фото:
В коде собрано 30 образцов с каждого идентификатора. Вы можете изменить его на последнем "elif".
Запустите скрипт Python и запишите несколько идентификаторов. Вы должны запускать скрипт каждый раз, когда хотите присоединить нового пользователя или изменить фотографии.
Обучение
На этом этапе мы должны взять все пользовательские данные из нашего набора данных "trainer" OpenCV Recognizer. Это делается напрямую с помощью определенной функции OpenCV. Результатом будет файл .yml, который будет сохранен в каталоге «trainer /».
Итак, приступим к созданию подкаталога, в котором мы будем хранить данные обучения:
mkdir trainer
Загрузите с GitHub второй скрипт на python: 02_face_training.py
import cv2
import numpy as np
from PIL import Image
import os
# Path for face image database
path = 'dataset'
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml");
# function to get the images and label data
def getImagesAndLabels(path):
imagePaths = [os.path.join(path,f) for f in os.listdir(path)]
faceSamples=[]
ids = []
for imagePath in imagePaths:
PIL_img = Image.open(imagePath).convert('L') # convert it to grayscale
img_numpy = np.array(PIL_img,'uint8')
id = int(os.path.split(imagePath)[-1].split(".")[1])
faces = detector.detectMultiScale(img_numpy)
for (x,y,w,h) in faces:
faceSamples.append(img_numpy[y:y+h,x:x+w])
ids.append(id)
return faceSamples,ids
print ("\n [INFO] Training faces. It will take a few seconds. Wait ...")
faces,ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))
# Save the model into trainer/trainer.yml
recognizer.write('trainer/trainer.yml') # recognizer.save() worked on Mac, but not on Pi
# Print the numer of faces trained and end program
print("\n [INFO] {0} faces trained. Exiting Program".format(len(np.unique(ids))))
Убедитесь, что на вашем Rpi установлена библиотека PIL. Если нет, выполните следующую команду в Терминале:
pip install pillow
В качестве распознавателя мы будем использовать распознаватель лица LBPH (ГИСТОГРАММЫ ЛОКАЛЬНЫХ ДВОЙНЫХ ШАБЛОНОВ), включенный в пакет OpenCV. Мы делаем это в следующей строке:
recognizer = cv2.face.LBPHFaceRecognizer_create()
Функция «getImagesAndLabels (path)» будет принимать все фотографии в каталоге: "dataset/" , возвращая 2 массива: "Ids" и "faces"(идентификаторы и лица). С этими массивами в качестве входных данных мы будем обучать наш распознаватель:
recognizer.train(faces, ids)
В результате файл с именем «trainer.yml» будет сохранен в каталоге «trainer /», который был ранее нами создан.
Распознавание
Теперь мы достигли финальной фазы нашего проекта. Здесь мы запечатлим новое лицо на нашей камере, и если у этого человека было запечатлено и обучено его лицо, наш распознаватель сделает прогноз, возвращающий его идентификатор и индекс, показывающие, насколько оно вероятно верно.
Давайте загрузим скрипт Python 3-й фазы из GitHub: 03_face_recognition.py .
import cv2
import numpy as np
import os
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('trainer/trainer.yml')
cascadePath = "haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(cascadePath);
font = cv2.FONT_HERSHEY_SIMPLEX
#iniciate id counter
id = 0
# names related to ids: example ==> Marcelo: id=1, etc
names = ['None', 'Marcelo', 'Paula', 'Ilza', 'Z', 'W']
# Initialize and start realtime video capture
cam = cv2.VideoCapture(0)
cam.set(3, 640) # set video widht
cam.set(4, 480) # set video height
# Define min window size to be recognized as a face
minW = 0.1*cam.get(3)
minH = 0.1*cam.get(4)
while True:
ret, img =cam.read()
img = cv2.flip(img, -1) # Flip vertically
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor = 1.2,
minNeighbors = 5,
minSize = (int(minW), int(minH)),
)
for(x,y,w,h) in faces:
cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
id, confidence = recognizer.predict(gray[y:y+h,x:x+w])
# Check if confidence is less them 100 ==> "0" is perfect match
if (confidence < 100):
id = names[id]
confidence = " {0}%".format(round(100 - confidence))
else:
id = "unknown"
confidence = " {0}%".format(round(100 - confidence))
cv2.putText(img, str(id), (x+5,y-5), font, 1, (255,255,255), 2)
cv2.putText(img, str(confidence), (x+5,y+h-5), font, 1, (255,255,0), 1)
cv2.imshow('camera',img)
k = cv2.waitKey(10) & 0xff # Press 'ESC' for exiting video
if k == 27:
break
# Do a bit of cleanup
print("\n [INFO] Exiting Program and cleanup stuff")
cam.release()
cv2.destroyAllWindows()
Мы включаем сюда новый массив, поэтому будем отображать «имена» вместо нумерованных идентификаторов:
names = ['None', 'Marcelo', 'Paula', 'Ilza', 'Z', 'W']
Так, например: Irina получит user с id = 1; Paul : id = 2 и т.д.
Далее мы обнаружим лицо, то же самое, что мы делали ранее с классификатором haasCascade. Обнаружив лицо, мы можем вызвать самую важную функцию в приведенном выше коде:
id, confidence = recognizer.predict(gray portion of the face)
recognizer.predict () примет в качестве параметра захваченную часть лица, подлежащего анализу, и вернет его вероятного владельца, указав его идентификатор и степень достоверности.
Обратите внимание, что индекс достоверности вернет "zero", если будет достигнут идеальный результат.
И, наконец, если распознаватель может предсказать лицо, мы помещаем текст поверх изображения с вероятным идентификатором и сколько эта вероятность составляет в процентах, что совпадение является правильным («вероятность» = 100 - индекс достоверности). Если нет, то на лицо наносится надпись НЕИЗВЕСТНО.
Вот и всё – теперь вы можете собрать свою собственную систему распознавания лиц. Она, конечно простенькая, но для дома или небольшого офиса – пойдет. К тому же не требует больших материальных затрат.