Обложка: Кейс: Хабиб vs МакГрегор или Распознавание лиц на Python

Кейс: Хабиб vs МакГрегор или Распознавание лиц на Python

Рассказывает команда IT Resume

Детекция (т.е. нахождение) и распознавание лиц — очень популярная задача в современном мире: в метро уже давно следят за нашими передвижениями, а в загородных домах все чаще ставят «умные дверные глазки».

Так уж сложилось, что сейчас уже нельзя просто написать программу для распознавания лиц и присвоить себе должность Senior Data Scientist — таких знаний требуют даже от начинающих специалистов.

Если Вы еще не игрались с распознаванием лиц, но хотите развиваться в области нейронных сетей (ну или просто Вам интересна эта область), то эксперты IT Resume подготовили для вас этот гайд — давайте вместе пройдем все шаги:

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

Для работы нам потребуется:

  1. Google Colab — среда для работы с Python в браузере. Они еще доступ к GPU дают (а для нейронных сетей это очень нужно).
  2. И все 🙂

Итак, начнем.

Этап 1. Подключение модулей

Перед тем, как начать работу, давайте сменим среду выполнения на «Ускорение GPU». В будущем нам это понадобится для работы нейронной сети. Для этого в Google Colab нажимаем «Среда выполнения» → «Сменить среду выполнения» → «Аппаратный ускоритель GPU».

Теперь подключим необходимые библиотеки. В Colab большинство библиотек уже установлено, поэтому нам осталось их только импортировать:

  • cv2 — для загрузки и обработки изображений;
  • dlib — для детекции лиц;
  • numpy — для работы с матрицами.

Помимо этого, с помощью команды pip install face_recognition мы устанавливаем библиотеку face_recognition — с ее помощью мы будем обрабатывать лицо нейронной сетью.

Примечание Вообще сделать полную обработку можно всего за несколько строчек кода, потому что в библиотеке face_recognition многие процессы (например, детекция лиц) уже завернуты в функции. Но мы намеренно некоторые вещи будем делать «с нуля», чтобы вы лучше во всем разобрались.

Этап 2. Первичная настройка

Теперь нам нужно произвести небольшую настройку, чтобы потом полноценно использовать все инструменты и кодовую базу.

Начнем с настройки детектора лиц. Сначала скачиваем файл с готовой моделью с помощью команды wget (да, именно этой командой Цукерберг запустил Фэйсбук в фильме Социальная сеть) и распаковываем файл в формат .dat.

wget http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
bunzip2 shape_predictor_68_face_landmarks.dat.bz2

Далее создаем детектор лиц и передаем скачанную модель в shape_predictor, который будет предсказывать ключевые точки человеческого лица — контур головы, глаза, нос и рот.

face_detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')

Отлично, теперь мы готовы переходить к содержательной части — обработке фотографий.

Этап 3. Загрузка и обработка фотографий

Перед тем, как загружать фотографию в переменную Python, ее надо загрузить в файловое хранилище Google Colab. Для этого достаточно нажать на иконку Папки на левом сайдбаре и выбрать Upload.

Мы, например, загрузим фотографию Конора МакГрегора.

Отлично, теперь надо «прочитать» изображение в переменную Python. Это можно сделать несколькими способами, но нам удобнее представить изображение сразу в виде матрицы. Это можно сделать с помощью функции imread из модуля cv2.

Если вы загружаете цветную картинку, то «матрица» будет иметь размерность 3*height*width, где 3 — количество цветовых каналов (RGB), а width и height — размерность картинки в пикселях. Проверить это можно с помощью метода shape. Каждое число в матрице — значение пикселя по конкретному цветовому каналу.

img = cv2.imread('conor.jpg')
img.shape #проверяем размерность матрицы
#(434, 770, 3)

Кстати говоря, если вы хотите посмотреть на загруженную картинку, то вам нужно:

  1. Импортировать команду cv2_imshow: from google.colab.patches import cv2_imshow.
  2. Передать в функцию cv2_imshow нужную картинку: cv2_imshow(img).

В некоторых задачах имеет смысл обрабатывать не цветное изображение, а черно-белое. Например, на детекцию лиц наличие цвета мало влияет — контуры лица и так хорошо видны. А вот для нейронной сети это может быть принципиальный момент — мало ли, люди выглядят одинаково, а цвет кожи разный.

Поэтому давайте переведем нашу цветную картинку в черно-белую:

img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

Теперь переходим к следующему этапу — детекция лица.

Этап 4. Детекция лица

Детектор лиц у нас уже настроен, поэтому можем переходить непосредственно к детекции. Делать это будем в 2 этапа:

  1. Ищем прямоугольники, в которых находятся лица.
  2. По этим прямоугольникам предсказываем контуры и ключевые точки лица.

С помощью detector мы получим координаты нужного прямоугольника. Если лиц несколько, то и наборов точек будет несколько. Чтобы выбрать конкретное лицо, нужно указать индекс (в нашем случае — ноль).

face_rect = detector(img, 1)[0]

Чтобы посмотреть на результат, можно нарисовать рамку вокруг лица с помощью метода rectangle и посмотреть фото с помощью cv2_imshow. Только будьте осторожны — рамка останется на фото навсегда, так что лучше потом загрузить изображение заново.

Теперь по найденным квадратам нужно «предсказать» ключевые точки лица. Для этого используем predictor, а потом извлекаем координаты точек.

points = predictor(img, face_rect)
landmarks = np.array([*map(lambda p: [p.x, p.y], points.parts())])

Здесь, чтобы получить координаты точек, мы использовали сразу несколько полезных операций Python:

  • лямбда-функции;
  • функцию map;
  • распаковку.

Если вы планируете связать свою работу с Python, то обязательно освойте все эти приемы — они сильно упростят вам жизнь.

На выходе у нас получилось 68 точек. Не будем сильно в этом гайде заморачиваться с тем, как нанести это на фото, но получится что-то в таком духе:

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

Этап 5. Обработка нейронной сетью

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

Итак, получить итоговый вектор очень просто — достаточно вызвать функцию face_encodings.

vector = face_recognition.face_encodings(img)[0]

Примечание Обратите внимание, что в качестве аргументов мы передали только изображение, а полученные ранее ключевые точки мы не использовали. Причина очень проста — функция face_encodings делает все те же самые действия, которые мы с вами проделали вручную ранее для понимания процесса «изнутри».

На выходе мы получаем вектор размерности 128, т.е. 128 чисел, которые описывают лицо на фотографии. Что значит каждое из этих чисел — неизвестно: это некоторая абстракция, восстановить и осмыслить которую невозможно — слишком уж много математических преобразований лежит внутри этого процесса.

Однако, от этого вектора нам толку мало — чтобы оценить эффективность «нейросетевых технологий», нужно сравнить два вектора для двух разных фотографий. Давайте немного поэксперементируем — будем подавать разные фото на вход и сравнивать с нашим изначальным фото МакГрегора.

Этап 6. Сравнение векторов

Чтобы сравнивать лица между собой, мы будем действовать следующим образом:

  1. Загружаем новое фото и производим обработку, которую уже разобрали на предыдущих этапах. На выходе получаем вектор.
  2. Сравниваем вектора между собой.
  3. На основании расстояния принимаем решение — один и тот же человек на фото или разные.

Встает вопрос — что значит «сравнить вектора»? Самый простой способ — посчитать расстояние в некоторой метрике. Мы выберем обычную евклидову метрику. Вычислять ее без лишнего кода нам позволит функция pdist из scipy.spatial.distance.

Итак, сначала загрузим еще одну фотографию Конора.

Сохраняем полученный вектор для первой фотографии в vector1, для второй — в vector2 и вычисляем расстояние:

from scipy.spatial.distance import pdist

pdist([vector1, vector2], 'euclidean')

Получаем ответ — 0,48. Это достаточно близкое расстояние, из чего делаем вывод, что это один и тот же человек. Сеть справилась отлично!

Ну хорошо, еще пару экспериментов — давайте возьмем снова Конора, но усложним задачу — пусть он будет в очках.

Результат — 0,56. Снова в яблочко (разработчик библиотеки face_recognition рекомендует придерживаться порога 0,6 — если больше 0,6, то это другой человек).

Ну что ж, а может сеть просто всех определяет как Конора? Давайте подсунем ей другого бойца — Хабиба Нурмагомедова. Что наша сеть на это скажет?

Снова проводим уже известную процедуру и ответ… — 0.72. По утвержденному ранее порогу, делаем вывод: Хабиб — не Конор. Сеть снова нас не подвела, и мы со спокойной душой можем переходить к более сложным проектам.

Эпилог

Мы с вами разобрали основной инструментарий, который вам понадобится для старта в области face recognition (да и в нейронных сетях, в целом). Однако это далеко не предел — мы затронули лишь верхушку айсберга, опустив очень много моментов как программных, так и математических.

Вот несколько вещей, которые мы рекомендуем вам сделать, чтобы прокачаться в области Computer Vision (компьютерное зрение):

  • Научитесь выстраивать процесс распознавания с нуля, без использования оберток (чем является библиотека face_recognition). Начните хотя бы с изучения исходников этой библиотеки на GitHub — там ничего сверхсложного нет.
  • Попробуйте разные нейронные сети. Погуглите state-of-the-art решения и посмотрите — чем будет различаться результат.
  • Изучите структуру нейронных сетей (например, сверточных) с математической точки зрения. Это можно сделать с помощью многочисленных туториалов и официальной документации библиотек (например, PyTorch).

Есть много и других точек роста, но начните с этих — остальные мысли придут в процессе 🙂

Желаем удачи и будем рады помочь в комментариях!

P.S. Наш ноутбук с кодом в Google Colab Вы можете найти здесь.