Выясняем, как устроено распознавание лиц на видео и фото, и пробуем самостоятельно создать собственный детектор вместе с программистом Александром Белозеровым.
Где нужно распознавание лиц?
Разработкой ПО для распознавания и улучшением алгоритмов занимаются программисты и дата-сайентисты. Эта технология нужна в разных сферах:
- Государство: видеоаналитика используется службами безопасности стран для пограничного контроля, а в Москве так находили нарушителей карантина. Службы безопасности организаций, имеющих дело с секретностью, также используют алгоритмы идентификации для контроля доступа сотрудников к секретным объектам.
- IT-индустрия: Microsoft, Google, Яндекс, ВКонтакте тоже разрабатывают собственные алгоритмы.
- Медицина: технология помогает выявить болезни и отслеживать прогресс в лечении.
- Банкинг: банки используют идентификацию по лицу, чтобы снять деньги в банкомате или получить кредит.
- Образование: распознавание лица помогает поймать тех, кто списывает, — сервисы подключаются к камере на компьютере студента и отслеживают его поведение и движение глаз.
- Персональные портативные устройства: на смартфонах помимо идентификации пользователя распознавание лица выполняет и развлекательную функцию — у приложений Samsung и Snapchat оно лежит в основе AR-фильтров и масок для лица.
Как работает распознавание лиц: метод Виолы-Джонса
Один из способов распознать образ — найти контур объекта и исследовать его свойства. По этому принципу работает метод Виолы-Джонса с использованием признаков Хаара, который придумал венгерский математик Альфред Хаар.
Признаки — это набор геометрических фигур с черно-белым узором, их еще называют маски. Они помогают найти границы какой-либо формы, например очертания лица, линии бровей, носа или рта.
В алгоритме Виолы-Джонса маски накладываются на разные части кадра, а программа определяет, может ли в них находиться объект. Работает это так:
- Классификатор (алгоритм, который будет искать объект в кадре) обучают на фотографиях лиц и получают пороговое значение — его превышение будет сигнализировать о том, что в кадре есть лицо.
- В классификатор загружают изображение, на котором будут искать лицо.
- Классификатор накладывает на него маски и отдельно складывает яркость пикселей, попавших в белую часть маски, и яркость пикселей, попавших в черную часть маски. Потом из первого значения он вычитает второе.
Результат сравнивается с пороговой величиной.
Если результат меньше пороговой величины, значит, в части кадра нет лица, и алгоритм заканчивает свою работу. А если больше, он переходит к следующей части кадра.
На практике маски находят лицо на фотографии так:
Алгоритмы OpenCV
У изображения лица есть свои характеристики:
- Темные и светлые участки и зоны (темные — глаза, губы; светлые — лоб, щеки, подбородок).
- Лица всех людей устроены по одному принципу (глаза — на одной линии, под глазами — нос, под носом — губы, под губами — подбородок).
Это значит, что можно подобрать такой набор масок и составить такой классификатор, который будет учитывать эти особенности.
Для этого можно использовать OpenCV — библиотеку алгоритмов компьютерного зрения и обработки изображений. Реализована она на C/C++, также разрабатывается для Python, Java, Ruby, Matlab, Lua и других языков.
Инструкция: распознаем лицо на фото
Шаг 1. Скачайте готовый классификатор. Мы будем использовать классификатор OpenCV, обученный находить лица, а также глаза, улыбки и другие черты. Скачать его в виде xml-файлов можно с GitHub.
Шаг 2. Скачайте PyCharm.
Для разработки мы советуем кроссплатформенную среду разработки PyCharm — в ней есть полезные инструменты для управления версиями пакетов, анализа кода и его отладки. Скачать ее можно тут.
Шаг 3. Создайте новый проект на Python, мы назвали его opencv_face_recognition.
Шаг 4. По правому клику на названии проекта в дереве каталогов добавьте новый файл main.py.
Шаг 5. Установите библиотеку. Для этого в настройках (Settings) проекта нужно найти вкладку с управлением конфигурацией интерпретатора, нажать на «+», вбить в поиск последовательно «opencv-python» и «opencv-contrib-python» и установить эти пакеты.
Это облегченная версия, которая использует для расчетов только процессор, но процесс установки все равно может занять до 15 минут.
Шаг 6. Чтобы использовать установленную библиотеку OpenCV, импортируйте модуль cv2:
import cv2
До тех пор пока мы не обратимся к каким-либо именам из него, он будет подсвечиваться серым, как неиспользуемый.
Шаг 7. Поместите ранее скачанный классификатор haarcascade_frontalface_default.xml в папку проекта
и загрузите его следующим образом:
import cv2.cv2 as cv2
face_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)
Обратите внимание, что в PyCharm для его корректной подсветки синтаксиса нам пришлось переписать первую строку с импортом.
Шаг 8. Загрузите изображение, на котором мы будем искать лицо, в режиме оттенков серого — информация о цвете алгоритму не важна, только его интенсивность:
import cv2.cv2 as cv2
face_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)
img = cv2.imread(‘xfiles4.jpg’)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
Мы будем использовать кадр из сериала «Секретные материалы» с Малдером и Скалли; вы можете поместить в папку проекта любое другое фото.
Шаг 9. Напишите код. Для поиска лиц на изображении мы используем метод с сигнатурой (его именем и списком параметров)
cv2.CascadeClassifier.detectMultiScale (image [, scaleFactor [, minNeighbors [, flags [, minSize [, maxSize]]]]]):
import cv2.cv2 as cv2
face_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)
img = cv2.imread(‘xfiles4.jpg’)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
Нам хватит первых трех параметров.
- В image надо будет передать 8-битную матрицу изображения.
- scaleFactor показывает, во сколько раз мы будем уменьшать исходное изображение, пытаясь обнаружить объект: это делается потому, что мы изначально не знаем, какого размера будет лицо. Чем меньше будет этот коэффициент, тем дольше будет работать алгоритм.
- minNeighbors влияет на качество обнаружения: чем больше его значение, тем меньше образов сможет обнаружить алгоритм, но тем точнее будет его работа.
Дефолтные значения для последних двух параметров — 1.1 и 3. Их можно заменить на любые другие и подобрать для конкретного случая, если на дефолтных значениях алгоритм будет работать плохо.
Шаг 10. Если лица будут обнаружены, функция вернет набор объектов типа Rect (x, y, w, h) — прямоугольников, начало которых задано парой координат (x, y), а ширина и высота — как w и h. В цикле for добавим эти прямоугольники в исходное изображение image при помощи cv2.rectangle(image, start_point, end_point, color, thickness) по координатам их противоположных вершин (x, y) и (x+w, y+h):
import cv2.cv2 as cv2
face_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)
img = cv2.imread(‘xfiles4.jpg’)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.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)
Шаг 11. Для отображения результата и закрытия программы по нажатию клавиши добавим еще несколько строк: вывод картинки, ожидание нажатия любой клавиши и последующее закрытие окна. В итоге весь наш проект будет выглядеть так:
import cv2.cv2 as cv2
face_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)
img = cv2.imread(‘xfiles4.jpg’)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.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)
cv2.imshow(‘img’, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Шаг 12. Сочетанием клавиш Ctrl-Shift-F10 (Ctrl-Shift-R на MacOS) запустим скрипт:
Инструкция: распознаем лицо в видеопотоке с веб-камеры
Модернизируем наш код так, чтобы в реальном времени обнаруживать лица в кадре, например, на видео с веб-камеры.
Шаг 1. Создайте объект для захвата видеострима:
import cv2.cv2 as cv2
face_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)
capture_io = cv2.VideoCapture(2)
Число для cv2.VideoCapture() придется поперебирать, индексом нашей внешней веб-камеры оказалась двойка.
Шаг 2. Считывать кадры с видеоустройства будем в вечном цикле: cv2.VideoCapture.read() возвращает булево значение об успешном считывании из потока (оно нам не нужно) в паре с самой картинкой. Преобразуем ее в 8-битную матрицу так же, как и раньше:
import cv2.cv2 as cv2
face_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)
capture_io = cv2.VideoCapture(2)
while True:
_, img = capture_io.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
Шаг 3. Остается переписать только конец цикла — чтобы у него было условие выхода, например, по нажатию на «q» (от quit, «выйти»). cv2.waitKey(time) 10 мс ожидает ввода с клавиатуры юникод-символа, который приведет к закрытию стрима и программы.
import cv2.cv2 as cv2
face_cascade = cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)
capture_io = cv2.VideoCapture(2)
while True:
_, img = capture_io.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.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)
cv2.imshow(‘img’, img)
if cv2.waitKey(10) & 0xFF == ord(«q»):
break
capture_io.release()
cv2.destroyAllWindows()
Шаг 4. Код готов, нажимаем Ctrl-Shift-F10 (Ctrl-Shift-R на MacOS) и наблюдаем результат вживую: