Получение информации о возрасте и гендерной принадлежности человека происходит исключительно по фотографии его лица. Исходя из этого можно разделить нашу задачу на два основных этапа:
- Обнаружение лиц на входном изображении.
- Извлечение интересующей области лица (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)
Результаты полученные в ходе отработки алгоритма
Как можно заметить, модель не всегда корректно показывает результат, иногда присваивает мужской пол фотографиям где изображены женщины. Возможно это связано с несбалансированным дата сетом, на котором обучалась модель. При условии наличия необходимых вычислительных ресурсов, можно попробовать самостоятельно обучить модель, это займет некоторое количество времени, но при сбалансированным набором данных и правильно подобранной архитектурой сети и параметров обучения, точность возможно улучшится.