Создаём свою модель распознавания лиц на Python
easy

Создаём свою модель распознавания лиц на Python

Быстро собираем датасет и сразу используем его для обучения

У нас уже есть большой цикл про компьютерное зрение и распознавание лиц. В этом цикле мы научились видеть лицо человека, определять примерный возраст и пол, работать с веб-камерой и с файлами. Если не читали, можно начать сейчас:

Пока что наш алгоритм не умеет различать разных людей в кадре. Максимум — сказать, что это «мужчина, столько-то лет», а кто конкретно — нет.

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

  • Для распознавания лица компьютер должен получить изображение — через камеру или готовый файл.
  • Компьютер использует особый алгоритм, который разбивает изображение на прямоугольники.
  • С помощью этих прямоугольников алгоритм пытается найти на картинке знакомые переходы между светлыми и тёмными областями.
  • Если в одном месте программа находит много таких совпадений, то, скорее всего, это лицо человека.
  • Чтобы программистам каждый раз не писать свой код распознавания с нуля, сделали библиотеку компьютерного зрения — cv2. Если в неё загрузить заранее подготовленные параметры лиц, она сможет распознавать их намного точнее.
  • С помощью этой библиотеки можно находить на картинке не только лица, но и другие предметы — для этого нужно использовать дополнительные библиотеки либо обучать систему самому.
  • Чтобы нейросеть могла понять, кто именно перед ней, её тоже нужно этому обучить отдельно.

Что нужно для обучения нейросети

Чтобы научить нейросеть узнавать конкретных людей в кадре, нужно:

  1. Собрать датасет.
  2. Обучить нейросеть на этом датасете и выгрузить результат обучения в отдельный файл.

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

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

Для проекта нам понадобится Python: как установить Python на компьютер и начать на нём писать.

Подготовка

В папке, где будет лежать скрипт, нужно создать две папки:

  • dataSet,
  • trainer.

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

Ещё нужно скачать файл haarcascade_frontalface_default.xml и положить его туда же, где и скрипт. Это модель распознавания лиц по примитивам Хаара. 

Собираем датасет

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

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

Сначала подключим все нужные библиотеки:

# подключаем библиотеку машинного зрения
import cv2
# библиотека для вызова системных функций
import os

Сразу подключим модель с примитивами Хаара к нейросети — это тот самый файл, который скачивали отдельно. 

Чтобы нейросеть в процессе обучения знала, кому принадлежат эти фотографии, добавим параметр id. Это будет внутренний номер пользователя, который мы потом превратим в настоящее имя:

# получаем путь к этому скрипту
path = os.path.dirname(os.path.abspath(__file__))
# указываем, что мы будем искать лица по примитивам Хаара
detector = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
# счётчик изображений
i=0
# расстояния от распознанного лица до рамки
offset=50
# запрашиваем номер пользователя
name=input('Введите номер пользователя: ')
# получаем доступ к камере
video=cv2.VideoCapture(0)

Последнее, что осталось, — сделать цикл, который соберёт как минимум 30 фотографий, найдёт на них лица и запишет их файл с нужными именами. Так как примитивы Хаара — это чёрно-белые прямоугольники, для простоты и ускорения работы мы тоже будем переводить кадры в ч/б. Чтобы потом в процессе тренировки нейросети было проще, мы будем сохранять не кадр с камеры целиком, а только лицо:

# запускаем цикл
while True:
    # берём видеопоток
    ret, im =video.read()
    # переводим всё в ч/б для простоты
    gray=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
    # настраиваем параметры распознавания и получаем лицо с камеры
    faces=detector.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=5, minSize=(100, 100))
    # обрабатываем лица
    for(x,y,w,h) in faces:
        # увеличиваем счётчик кадров
        i=i+1
        # записываем файл на диск
        cv2.imwrite("dataSet/face-"+name +'.'+ str(i) + ".jpg", gray[y-offset:y+h+offset,x-offset:x+w+offset])
        # формируем размеры окна для вывода лица
        cv2.rectangle(im,(x-50,y-50),(x+w+50,y+h+50),(225,0,0),2)
        # показываем очередной кадр, который мы запомнили
        cv2.imshow('im',im[y-offset:y+h+offset,x-offset:x+w+offset])
        # делаем паузу
        cv2.waitKey(100)
    # если у нас хватает кадров
    if i>30:
        # освобождаем камеру
        video.release()
        # удалаяем все созданные окна
        cv2.destroyAllWindows()
        # останавливаем цикл
        break

Сохраняем скрипт как face_gen.py — потому что для тренировки нам понадобится отдельный код. После запуска в терминале нужно будет ввести номер пользователя — им может быть любое число. Во время работы скрипт покажет нам 30 кадров, которые он сделал, а в папке dataSet появятся новые файлы — это значит, что мы всё сделали правильно:

Создаём свою модель распознавания лиц на Python

Обучаем нейросеть

Создаём новый файл face_train.py — он будет отвечать за обучение на собранном датасете. Так как мы сами придумывали формат имени файла, то это сильно упростит нам задачу: цифра, которая стоит после дефиса и до первой точки, и будет id пользователя:

face-1.29.jpg ← здесь после дефиса и до первой точки стоит число 1, значит эта фотография относится к пользователю с id = 1.

Начало скрипта будет похоже на предыдущее, добавятся только две библиотеки — для обучения нейросети и для работы с изображениями:

# подключаем библиотеку компьютерного зрения
import cv2
# библиотека для вызова системных функций
import os
# для обучения нейросетей
import numpy as np
# встроенная библиотека для работы с изображениями
from PIL import Image 
# получаем путь к этому скрипту
path = os.path.dirname(os.path.abspath(__file__))
# создаём новый распознаватель лиц
recognizer = cv2.face.LBPHFaceRecognizer_create()
# указываем, что мы будем искать лица по примитивам Хаара
faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
# путь к датасету с фотографиями пользователей
dataPath = path+r'/dataSet'

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

Логика будет такая:

  1. Открываем папку с картинками.
  2. По очереди читаем каждую картинку и переводим её в специальный формат, с которым умеет работать библиотека numpy.
  3. Получаем id пользователя из имени файла — просто убираем всё до дефиса и после первой точки.
  4. Определяем лицо на картинке — это будет просто, потому что на картинках и так будут только лица.
  5. Добавляем лица в список лиц.
  6. Добавляем id пользователя в список пользователей
  7. Чтобы было видно, что скрипт работает, на долю секунды будем выводить на экран текущую картинку.
  8. На выходе получим список с лицами и идентификаторами пользователей, к которым они относятся.

Запишем это в виде кода на Python:

# получаем картинки и подписи из датасета
def get_images_and_labels(datapath):
     # получаем путь к картинкам
     image_paths = [os.path.join(datapath, f) for f in os.listdir(datapath)]
     # списки картинок и подписей на старте пустые
     images = []
     labels = []
     # перебираем все картинки в датасете 
     for image_path in image_paths:
         # читаем картинку и сразу переводим в ч/б
         image_pil = Image.open(image_path).convert('L')
         # переводим картинку в numpy-массив
         image = np.array(image_pil, 'uint8')
         # получаем id пользователя из имени файла
         nbr = int(os.path.split(image_path)[1].split(".")[0].replace("face-", ""))
         # определяем лицо на картинке
         faces = faceCascade.detectMultiScale(image)
         # если лицо найдено
         for (x, y, w, h) in faces:
             # добавляем его к списку картинок 
             images.append(image[y: y + h, x: x + w])
             # добавляем id пользователя в список подписей
             labels.append(nbr)
             # выводим текущую картинку на экран
             cv2.imshow("Adding faces to traning set...", image[y: y + h, x: x + w])
             # делаем паузу
             cv2.waitKey(100)
     # возвращаем список картинок и подписей
     return images, labels

Наконец, обучаем и сохраняем модель, чтобы её можно было использовать в других проектах. При этом нейросети неважно, сколько пользователей и фотографий будет в датасете — один или тысяча. Она запомнит их все, сопоставит одно с другим и запомнит, как выглядит пользователь под каждым номером. Результат такой обработки сохраним в yml-файле — это один из стандартных форматов для таких моделей:

# получаем список картинок и подписей
images, labels = get_images_and_labels(dataPath)
# обучаем модель распознавания на наших картинках и учим сопоставлять её лица и подписи к ним
recognizer.train(images, np.array(labels))
# сохраняем модель
recognizer.save(path+r'/trainer/trainer.yml')
# удаляем из памяти все созданные окнаы
cv2.destroyAllWindows()

Если после запуска скрипта в папке trainer появился файл trainer.yml — поздравляем, вы только что обучили нейросеть распознавать лицо человека!

# подключаем библиотеку машинного зрения
import cv2
# библиотека для вызова системных функций
import os

# получаем путь к этому скрипту
path = os.path.dirname(os.path.abspath(__file__))
# указываем, что мы будем искать лица по примитивам Хаара
detector = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
# счётчик изображений
i=0
# расстояния от распознанного лица до рамки
offset=50
# запрашиваем номер пользователя
name=input('Введите номер пользователя: ')
# получаем доступ к камере
video=cv2.VideoCapture(0)

# запускаем цикл
while True:
    # берём видеопоток
    ret, im =video.read()
    # переводим всё в ч/б для простоты
    gray=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
    # настраиваем параметры распознавания и получаем лицо с камеры
    faces=detector.detectMultiScale(gray, scaleFactor=1.2, minNeighbors=5, minSize=(100, 100))
    # обрабатываем лица
    for(x,y,w,h) in faces:
        # увеличиваем счётчик кадров
        i=i+1
        # записываем файл на диск
        cv2.imwrite("dataSet/face-"+name +'.'+ str(i) + ".jpg", gray[y-offset:y+h+offset,x-offset:x+w+offset])
        # формируем размеры окна для вывода лица
        cv2.rectangle(im,(x-50,y-50),(x+w+50,y+h+50),(225,0,0),2)
        # показываем очередной кадр, который мы запомнили
        cv2.imshow('im',im[y-offset:y+h+offset,x-offset:x+w+offset])
        # делаем паузу
        cv2.waitKey(100)
    # если у нас хватает кадров
    if i>30:
        # освобождаем камеру
        video.release()
        # удаляем все созданные окна
        cv2.destroyAllWindows()
        # останавливаем цикл
        break

# подключаем библиотеку компьютерного зрения
import cv2
# библиотека для вызова системных функций
import os
# для обучения нейросетей
import numpy as np
# встроенная библиотека для работы с изображениями
from PIL import Image 
# получаем путь к этому скрипту
path = os.path.dirname(os.path.abspath(__file__))
# создаём новый распознаватель лиц
recognizer = cv2.face.LBPHFaceRecognizer_create()
# указываем, что мы будем искать лица по примитивам Хаара
faceCascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
# путь к датасету с фотографиями пользователей
dataPath = path+r'/dataSet'

# получаем картинки и подписи из датасета
def get_images_and_labels(datapath):
     # получаем путь к картинкам
     image_paths = [os.path.join(datapath, f) for f in os.listdir(datapath)]
     # списки картинок и подписей на старте пустые
     images = []
     labels = []
     # перебираем все картинки в датасете 
     for image_path in image_paths:
         # читаем картинку и сразу переводим в ч/б
         image_pil = Image.open(image_path).convert('L')
         # переводим картинку в numpy-массив
         image = np.array(image_pil, 'uint8')
         # получаем id пользователя из имени файла
         nbr = int(os.path.split(image_path)[1].split(".")[0].replace("face-", ""))
         # определяем лицо на картинке
         faces = faceCascade.detectMultiScale(image)
         # если лицо найдено
         for (x, y, w, h) in faces:
             # добавляем его к списку картинок 
             images.append(image[y: y + h, x: x + w])
             # добавляем id пользователя в список подписей
             labels.append(nbr)
             # выводим текущую картинку на экран
             cv2.imshow("Adding faces to traning set...", image[y: y + h, x: x + w])
             # делаем паузу
             cv2.waitKey(100)
     # возвращаем список картинок и подписей
     return images, labels

# получаем список картинок и подписей
images, labels = get_images_and_labels(dataPath)
# обучаем модель распознавания на наших картинках и учим сопоставлять её лица и подписи к ним
recognizer.train(images, np.array(labels))
# сохраняем модель
recognizer.save(path+r'/trainer/trainer.yml')
# удаляем из памяти все созданные окнаы
cv2.destroyAllWindows()

Что дальше

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

Любите данные? Посмотрите вот это
Возможно, у вас получится построить карьеру в мире дата-сайенса. Это новое направление, в котором очень нужны люди. Изучите эту сферу и начните карьеру в ИТ: старт — бесплатно, а после обучения — помощь с трудоустройством.
Начать бесплатно
Любите данные? Посмотрите вот это Любите данные? Посмотрите вот это Любите данные? Посмотрите вот это Любите данные? Посмотрите вот это
Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Начать карьеру в ИТ
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Еще по теме
easy