Определение возраста, пола и эмоций
В этом туториале Вы узнаете, как определить возраст, пол и эмоции лица с использованием Face SDK. Результат будет отображаться рядом с задетектированным лицом. Предполагается, что у вас есть готовый проект с детекцией лиц на видеопотоке или на изображении. Пример детекции и получения информации о лице на видеопотоке см. в туториале Детекция и трекинг лиц на видеопотоке. В данном туториале мы рассматриваем определение возраста, пола и эмоций лица на изображении.
Готовый демо-проект вы можете найти в дистрибутиве Face SDK: examples/tutorials/age_gender_and_emotions
Определяем пол и возраст
- Укажем путь до изображения в поле
QImage image
. Зададим параметры надписей с информацией о поле, возрасте и эмоциях (размер 15, полужирный шрифт “Arial”).
main.cpp
QImage image(image_path);
QPainter painter(&image);
QPen pen;
pen.setWidth(2);
painter.setPen(pen);
painter.setFont(QFont("Arial", 15, QFont::DemiBold));
- Зададим отступ
margin_from_rect
между ограничивающим прямоугольником лица и текстом с информацией о лице. Также зададим расстояниеtext_element_position
между элементами “возрастная группа”, “возраст”, “пол”, “эмоция”. Указанные элементы отображаются справа от лица друг под другом.
main.cpp
const int margin_from_rect = 32; // отступ от ограничивающего прямоугольника до текста с информацией
const int text_element_position = 32;
- Используя метод
pbio::FacerecService::createAgeGenderEstimator
создаем объектAgeGenderEstimator
для определения пола и возраста. При вызове этого метода необходимо указать конфигурационный файлage_gender_estimator.xml
.
main.cpp
// создаем age-gender estimator
pbio::AgeGenderEstimator::Ptr age_gender_estimator = service->createAgeGenderEstimator("age_gender_estimator.xml");
- Определяем начальную точку
base_point
для отображения информации о поле, возрасте и эмоции. Для этого получаем ограничивающий прямоугольникrectangle
из объектаRawSample
, который хранит данные о лице, и рассчитываем точку, учитывая отступmargin_from_rect
.
main.cpp
// вычисляем начальную точку для отображения информации о поле, возрасте и эмоциях
const pbio::RawSample::Rectangle rectangle = sample->getRectangle();
const QPoint base_point = QPoint(rectangle.x + rectangle.width + margin_from_rect, rectangle.y);
- Определяем пол и возраст лица (
*sample
), используя методpbio::AgeGenderEstimator
. Отображаем возрастную группу лица, исходя из его возраста. На данный момент в Face SDK доступны четыре возрастные группы:
- Kid (до 18 лет),
- Young (18-37 лет),
- Adult (37-55 лет),
- Senior (55 лет и более).
Возрастная группа берется из перечисления pbio::AgeGenderEstimator::Age
, результат записывается в переменную age_group_text
. Используя метод painter.drawText
, выводим надпись с возрастной группой. Надпись будет располагаться на первой строчке справа от начальной точки base_point
.
main.cpp
// определяем и отображаем возраст и пол
{
const pbio::AgeGenderEstimator::AgeGender age_gender = age_gender_estimator->estimateAgeGender(*sample);
painter.save();
// отображаем возрастную группу
const QMap<pbio::AgeGenderEstimator::Age, QString> age_map =
{
{pbio::AgeGenderEstimator::AGE_KID, "Kid"},
{pbio::AgeGenderEstimator::AGE_YOUNG, "Young"},
{pbio::AgeGenderEstimator::AGE_ADULT, "Adult"},
{pbio::AgeGenderEstimator::AGE_SENIOR, "Senior"}
};
QString age_group_text = QString("Age Group: %1").arg(age_map[age_gender.age]);
painter.drawText(base_point + QPoint(0, text_element_position * 0), age_group_text);
}
- Отображаем возраст в годах на второй строчке (ниже возрастной группы).
main.cpp
// определяем и отображаем возраст и пол
{
...
// отображаем возраст в годах
QString age_in_years_text = QString("Age: %1").arg((int)age_gender.age_years);
painter.drawText(base_point + QPoint(0, text_element_position * 1), age_in_years_text);
}
- Отображаем пол на третьей строчке (ниже возраста).
main.cpp
// определяем и отображаем возраст и пол
{
...
// отображаем пол
QString gender = age_gender.gender == pbio::AgeGenderEstimator::GENDER_MALE ? "Male" : "Female";
QString gender_text = QString("Gender: %1").arg(gender);
painter.drawText(base_point + QPoint(0, text_element_position * 2), gender_text);
painter.restore();
}
- Запускаем проект. На данном этапе справа от найденного лица будет отображаться информация о возрастной группе, возрасте и поле.
Определяем эмоции
- Используя метод
pbio::FacerecService::createEmotionsEstimator
, создаем объектEmotionsEstimator
для определения эмоций. При вызове этого метода необходимо указать конфигурационный файлemotions_estimator.xml
.
main.cpp
// создаем emotions estimator
pbio::EmotionsEstimator::Ptr emotions_estimator = service->createEmotionsEstimator("emotions_estimator.xml");
- При помощи метода
pbio::EmotionsEstimator::estimateEmotions
определяем эмоцию найденного лица (*sample
) и соответствующий коэффициент уверенности (от 0 до 1). В перечисленииpbio::EmotionsEstimator::Emotion
указаны все доступные эмоции. На данный момент Face SDK определяет четыре эмоции:
- Neutral (нейтральный),
- Happy (счастливый),
- Angry (злой),
- Surprise (удивленный).
Каждой эмоции присваивается индекс от 0 до 3. Отобразим эмоции в виде четырех столбиков разного цвета (синий, зеленый, красный, желтый) с соответствующими надписями (Neutral, Happy, Angry, Surprise). Чем больше коэффициент уверенности для эмоции, тем длиннее будет столбик в сравнении с тремя другими, что наглядно покажет, какая эмоция преобладает. Все параметры эмоций сохраняем в словарь emotions_params
.
main.cpp
// определяем и отображаем эмоции
{
// определяем эмоции лица
const std::vector<pbio::EmotionsEstimator::EmotionConfidence> emotions = emotions_estimator->estimateEmotions(*sample);
// параметры эмоции для отрисовки: номер строки, цвет столбика, название эмоции
struct EmotionParams
{
int row;
QColor color;
QString label;
};
const QMap<pbio::EmotionsEstimator::Emotion, EmotionParams> emotions_params =
{
{pbio::EmotionsEstimator::EMOTION_NEUTRAL, {0, Qt::blue, "Neutral"}},
{pbio::EmotionsEstimator::EMOTION_HAPPY, {1, Qt::green, "Happy"}},
{pbio::EmotionsEstimator::EMOTION_ANGRY, {2, Qt::red, "Angry"}},
{pbio::EmotionsEstimator::EMOTION_SURPRISE, {3, Qt::yellow, "Surprise"}}
};
}
- Зададим начальную точку
emotions_base_point
, от которой будут рисоваться столбики с эмоциями (справа от ограничивающего прямоугольника лица под надписями с полом, возрастом и возрастной группой). Также укажем размер столбиков с эмоциямиbar_base_size
и отступbar_offset
от названий эмоций.
main.cpp
// определяем и отображаем эмоции
{
...
const QPoint emotions_base_point(base_point + QPoint(0, text_element_position * 3)); // начальная точка для отрисовки первой эмоции
const QSizeF bar_base_size(100, 15); // базовый размер столбика
const QPoint bar_offset(100, 0); // отступ от названия эмоции
}
- Отображаем надписи и столбики с эмоциями. В цикле рассчитываем начальную точку
emotion_row_base_point
для отображения информации для каждой эмоции и начальную точку названия эмоцииtext_base_point
. Затем получаем название эмоции из словаря и отображаем надписьemotion_label
. Отображаем столбик для каждой эмоции: определяем начальную точку для отрисовки столбикаbar_base_point
и рассчитываем длину столбикаbar_size
, умножая значениеbar_base_size.width
на коэффициент уверенности. Окрашиваем столбики в соответствии с цветом каждой эмоции из словаря.
main.cpp
// определяем и отображаем эмоции
{
...
// обрабатываем эмоции в цикле
for (const auto &emotion_confidence: emotions)
{
const auto &emotion_params = emotions_params[emotion_confidence.emotion];
const int &emotion_row = emotion_params.row;
const QPoint emotion_row_base_point = emotions_base_point + QPoint(0, text_element_position * emotion_row);
const QPoint text_base_point = emotion_row_base_point + QPoint(0, bar_base_size.height());
painter.save();
// отображаем название эмоции
const QString &emotion_label = emotion_params.label;
painter.drawText(text_base_point, emotion_label);
// отображаем столбик
const QPoint bar_base_point = emotion_row_base_point + bar_offset;
QSizeF bar_size(bar_base_size.width() * emotion_confidence.confidence, bar_base_size.height());
const QColor &emotion_color = emotion_params.color;
pen.setColor(emotion_color);
pen.setWidth(1);
painter.setPen(pen);
painter.setBrush(QBrush(emotion_color));
painter.drawRect(QRectF(bar_base_point, bar_size));
painter.restore();
}
}
- Запускаем проект. Справа от ограничивающего прямоугольника лица будет отображаться информация об эмоциях (длины столбиков визуализируют вероятностное распределение в пространстве описанных эмоций).