Время прочтения: 5 мин.

Получение информации о возрасте и гендерной принадлежности   человека происходит исключительно по фотографии его лица. Исходя из этого можно разделить нашу задачу на два основных этапа:

  1. обнаружение лиц на входном изображении.
  2. извлечение интересующей области лица (ROI — Region of Interest) и применение алгоритма детектора возраста и пола человека.

Для этапа №1 можно существует множество готовых решений, например : каскады Хаара, HOG ((Histogram of Oriented Gradients), модели глубокого обучения и т. д. Рассмотрим основные отличительные особенности каждого из них :

  • Каскады Haar будут очень быстры и способны работать в режиме реального времени на встроенных устройствах-проблема в том, что они менее точны и очень подвержены ложноположительным обнаружениям
  • Модели HOG более точны, чем каскады Haar, но медленнее. Они также не так терпимы к окклюзии (то есть когда скрыта часть лица)
  • Детекторы лица на основе глубокого обучения являются наиболее надежными и дадут вам наилучшую точность, но требуют еще больше вычислительных ресурсов, чем каскады Haar и HOG

Для выбора метода, подходящего для нашей задачи был произведен сравнительный анализ двух алгоритмов: каскады Хаара  и сверточную нейронную сеть MTCNN (Multi-Task Cascaded Convolutional Neural Network). В первом случае библиотека OpenCV уже содержит множество предварительно подготовленных классификаторов для лица, глаз, улыбки и т. д. (XML-файлы хранятся в папке opencv/data/haarcascades/) , во втором же случае необходимо поставить библиотеку, воспользовавшись командой pip install mtcnn .

Импортируем необходимые библиотеки

import cv2
from mtcnn import MTCNN
import matplotlib.pyplot as plt
image = cv2.cvtColor(cv2.imread('f.jpg'), cv2.COLOR_BGR2RGB) # исходник 

Ниже представлен код для проверки работы алгоритмов

MTCNN:

detector = MTCNN() # создание детектора
result = detector.detect_faces(image)  # обнаружение лиц на изображении
for i in range(len(result)): 
bounding_box = result[i]['box']  #  ограничивающие рамки
cv2.rectangle(image, (bounding_box[0], bounding_box[1]),
(bounding_box[0]+bounding_box[2], bounding_box[1] + bounding_box[3]),
           (0,155,255), 2) #  ограничение области на изображении
plt.imshow(image) # показать полученное изображение

haar cascade:

face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml') # загрузка необходимого XML-классификатора
faces = face_cascade.detectMultiScale(image, 1.3, 5)  # обнаружение лиц на изображении
for (x,y,w,h) in faces: # цикл по всем обнаруженным граням 
    cv2.rectangle(image,(x,y),(x+w,y+h),(255,0,0),2) # отрисовка  области на изображении
plt.imshow(image) # показать полученное изображение

Проведем серию экспериментов для проверки качество работы алгоритмов

 — одиночная фотография человека

— Несколько людей на фотографии

— Несколько людей на фотографии, в случае когда взгляд устремлен не в кадр

— Несколько людей на фотографии, когда часть их лица скрыта, например, масками

Можно сделать вывод, что в идеальных условиях(высокая четкость фотографии, лицо направлено строго в кадр) оба алгоритма работают без нареканий, но при малейшем отклонении от этих условий , каскады Хаара начинают сбоить. Поэтому выбор остановился на использовании модели MTCNN.

Теперь, когда разобрались с выбором метода обнаружения лиц на фотографии перейдем непосредственно к самой задаче. Для определения возраста и пола использовались две разные модели, обученные на огромном количестве данных. Обе модели были обучены Леви и Хасснером, первая их работа вышла в 2015 году под названием  “Age and Gender Classification Using Convolutional Neural Networks”. В своей работе они продемонстрировали , что при обучении с использованием глубоких сверточных нейронных сетей (CNN) можно добиться значительного повышения производительности при выполнении задач предсказывания возраста и пола.

Модель, обученную на  Adience dataset , для предсказывания возраста  можно скачать по ссылке1 (*.caffemodel) и ссылке2 (*.prototxt).Данная модель решает задачу классификации,  а не регрессии. Возрастной диапазон поделён на определенные промежутки [«(0-2)», «(4-6)», «(8-12)», «(15-20)», «(25-32)»,»(38-43)», «(48-53)», «(60-100)»], каждый из которых является отдельным классом, который модель может предсказать.

Для определения гендерной принадлежности была  взята модель с репозитория , посвященному статье “Understanding and Comparing Deep Neural Networks for Age and Gender Classification” .Скачать модели можно по ссылке1 (*.caffemodel) и по ссылке 2 (*.prototxt). Модель использует архитектуру сети GoogleNet и была предобучена на  ImageNet dataset.

Как можно было заметить, каждая модель представлена двумя файлами, это значит что она была обучена с помощью Caffe  (фреймворк глубокого машинного обучения нацеленный на простое использование, высокую скорость и модульность).Файл с расширением prototxt отвечает за архитектуру сети , а  файл с расширением caffemodel за веса модели.

Ниже кратко представлен основной код, в качестве аргумента в модель передаем определённое выше лицо.

AGE_BUCKETS = ["(0-2)", "(4-6)", "(8-12)", "(15-20)", "(25-32)","(38-43)", "(48-53)", "(60-100)"]
gender_list=['Male','Female']
faceBlob = cv2.dnn.blobFromImage(face, 1.0, (227, 227), (78.4, 87.7, 114.8), swapRB=False)
  ageNet.setInput(faceBlob)
  age_preds = ageNet.forward()
  age_i = age_preds[0].argmax()
  age = AGE_BUCKETS[age_i]
  ageConfidence = age_preds[0][age_i]
             age_text = "{}: {:.2f}%".format(age, ageConfidence * 100) # Отобразить предсказание возраста
  genderNet.setInput(faceBlob)
  gender_preds = genderNet.forward()
  gender_i = gender_preds[0].argmax()
  gender=gender_list[gender_i]
  genderConfidence = gender_preds[0][gender_i]
  gender_text = "{}: {:.2f}%".format(gender, genderConfidence * 100) # Отобразить предсказание пола
   y = y1 - 10 if y1 - 10 > 10 else y1 + 10
   cv2.rectangle(image, (x1, y1), (x1+width, y1 + height), (0,155,255),2) 
   сv2.putText(image, display_text, (x1, y),
   cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 0, 255), 2)

Результаты полученные в ходе отработки алгоритма

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